<commit_before>//! Rust code which is called from lua in the init file
#![deny(dead_code)]

use rustc_serialize::json::ToJson;
use uuid::Uuid;
use super::{send, LuaQuery, running};
use rlua;
use rlua::prelude::LuaResult;
use ::convert::json::json_to_lua;
use ::awesome;

use registry::{self};
use commands;
use keys::{self, KeyPress, KeyEvent};

use super::thread::{update_registry_value};

/// We've `include!`d the code which initializes from the Lua side.

/// Register all the Rust functions for the lua libraries
pub fn register_libraries(lua: &rlua::Lua) -> LuaResult<()> {
    trace!("Registering Rust libraries...");
    {
        let rust_table = lua.create_table();
        rust_table.set("init_workspaces",
                       lua.create_function(init_workspaces))?;
        rust_table.set("register_lua_key",
                       lua.create_function(register_lua_key))?;
        rust_table.set("unregister_lua_key",
                       lua.create_function(unregister_lua_key))?;
        rust_table.set("register_command_key",
                       lua.create_function(register_command_key))?;
        rust_table.set("register_mouse_modifier",
                       lua.create_function(register_mouse_modifier))?;
        rust_table.set("keypress_index",
                       lua.create_function(keypress_index))?;
        rust_table.set("ipc_run",
                       lua.create_function(ipc_run))?;
        rust_table.set("ipc_get",
                       lua.create_function(ipc_get))?;
        rust_table.set("ipc_set",
                       lua.create_function(ipc_set))?;
        let globals = lua.globals();
        globals.set("__rust", rust_table)?;
    }
    trace!("Executing Lua init...");
    let init_code = include_str!("../../lib/lua/lua_init.lua");
    let awesome_init_code = include_str!("../../lib/lua/awesome_init.lua");
    let util_code = include_str!("../../lib/lua/utils.lua");
    lua.exec::<()>(util_code, Some("utils.lua"))?;
    lua.exec::<()>(awesome_init_code, Some("awesome_init.lua"))?;
    awesome::init(&lua)
        .expect("Could not initialize awesome compatibilty modules");
    lua.exec::<()>(init_code, Some("lua_init.lua"))?;
    trace!("Lua register_libraries complete");
    Ok(())
}

/// Run a command
fn ipc_run(_lua: &rlua::Lua, command: String) -> Result<(), rlua::Error> {
    use rlua::Error;
    commands::get(&command).map(|com| com())
        .ok_or(Error::RuntimeError("Command does not exist".into()))
}

/// IPC 'get' handler
fn ipc_get<'lua>(lua: &'lua rlua::Lua, (category, key): (String, String))
                 -> Result<rlua::Value<'lua>, rlua::Error> {
    use rlua::Error;
    let lock = registry::clients_read();
    let client = lock.client(Uuid::nil()).unwrap();
    let handle = registry::ReadHandle::new(&client);
    handle.read(category)
        .map_err(|_|
                 Error::RuntimeError("Could not locate that category".into()))
        .and_then(|category| category.get(&key)
                  .ok_or(Error::RuntimeError(
                      "Could not locate that key in the category".into()))
                  .and_then(|value| json_to_lua(lua, value.to_json())))
}

/// ipc 'set' handler
fn ipc_set(_lua: &rlua::Lua, category: String) -> Result<(), rlua::Error> {
    update_registry_value(category);
    if running() {
        send(LuaQuery::UpdateRegistryFromCache)
            .expect("Could not send message to Lua thread to update registry");
    }
    Ok(())
}

fn init_workspaces(_: &rlua::Lua, _: rlua::Value) -> Result<(), rlua::Error> {
    warn!("Attempting to call `init_workspaces`, this is not implemented");
    Ok(())
}

/// Registers a modifier to be used in conjunction with mouse commands
fn register_mouse_modifier(_lua: &rlua::Lua, modifier: String)
                           -> Result<(), rlua::Error> {
    use rlua::Error;
    let modifier = keys::keymod_from_names(&[modifier.as_str()])
        .map_err(|txt| Error::RuntimeError(txt))?;
    keys::register_mouse_modifier(modifier);
    Ok(())
}

/// Registers a command keybinding.
fn register_command_key(_lua: &rlua::Lua,
                        (mods, command, _repeat, passthrough):
                        (String, String, bool, bool))
                        -> Result<(), rlua::Error> {
    use rlua::Error;
    if let Ok(press) = keypress_from_string(&mods) {
        commands::get(&command)
            .ok_or(Error::RuntimeError(
                format!("Command {} for keybinding {} not found", command, press)))
            .map(|command|
                keys::register(press, KeyEvent::Command(command), passthrough))?;
        Ok(())
    }
    else {
        Err(Error::RuntimeError(format!("Invalid keypress {}, {}", mods, command)))
    }
}

/// Rust half of registering a Lua key: store the KeyPress in the keys table
/// and send Lua back the index for __key_map.
fn register_lua_key(_lua: &rlua::Lua, (mods, _repeat, passthrough):
                          (String, bool, bool))
                          -> Result<String, rlua::Error> {
    use rlua::Error;
    keypress_from_string(&mods)
        .map(|press| {
            keys::register(press.clone(), KeyEvent::Lua, passthrough);
            press.get_lua_index_string()
        }).map_err(|_| Error::RuntimeError(format!("Invalid keys '{}'", mods)))
}

/// Rust half of unregistering a Lua key. This pops it from the key table, if
/// it exists.
///
/// If a key wasn't registered, a proper error string is raised.
fn unregister_lua_key(_lua: &rlua::Lua, mods: String)
                            -> Result<String, rlua::Error> {
    use rlua::Error;
    keypress_from_string(&mods).and_then(|press| {
        if let Some(action) = keys::unregister(&press) {
            trace!("Removed keybinding \"{}\" for {:?}", press, action);
            Ok(press.get_lua_index_string())
        } else {
            let error_str = format!("Could not remove keybinding \"{}\": \
                                     Not registered!",
                                    press);
            warn!("Could not remove keybinding \"{}\": Not registered!",
                  press);
            Err(error_str)
        }
    }).map_err(|err|
               Error::RuntimeError(format!("Invalid keys '{}': {:#?}", mods, err)))
}

/// Parses a keypress from a string
fn keypress_from_string(mods: &str) -> Result<KeyPress, String> {
    let parts: Vec<&str> = mods.split(',').collect();
    if let Some((ref key, mods)) = parts.split_last() {
        KeyPress::from_key_names(mods, &key)
    }
    else {
        Err(format!("Invalid key '{}'", mods))
    }
}

fn keypress_index(_lua: &rlua::Lua, press: String) -> Result<String, rlua::Error> {
    use rlua::Error;
    keypress_from_string(&press)
        .map(|key| key.get_lua_index_string())
        .map_err(|err_msg| Error::RuntimeError(err_msg))
}
<commit_msg>Override Lua's type() function<commit_after>//! Rust code which is called from lua in the init file
#![deny(dead_code)]

use rustc_serialize::json::ToJson;
use uuid::Uuid;
use super::{send, LuaQuery, running};
use rlua;
use rlua::prelude::LuaResult;
use ::convert::json::json_to_lua;
use ::awesome;

use registry::{self};
use commands;
use keys::{self, KeyPress, KeyEvent};

use super::thread::{update_registry_value};

/// We've `include!`d the code which initializes from the Lua side.

/// Register all the Rust functions for the lua libraries
pub fn register_libraries(lua: &rlua::Lua) -> LuaResult<()> {
    trace!("Registering Rust libraries...");
    {
        let rust_table = lua.create_table();
        rust_table.set("init_workspaces",
                       lua.create_function(init_workspaces))?;
        rust_table.set("register_lua_key",
                       lua.create_function(register_lua_key))?;
        rust_table.set("unregister_lua_key",
                       lua.create_function(unregister_lua_key))?;
        rust_table.set("register_command_key",
                       lua.create_function(register_command_key))?;
        rust_table.set("register_mouse_modifier",
                       lua.create_function(register_mouse_modifier))?;
        rust_table.set("keypress_index",
                       lua.create_function(keypress_index))?;
        rust_table.set("ipc_run",
                       lua.create_function(ipc_run))?;
        rust_table.set("ipc_get",
                       lua.create_function(ipc_get))?;
        rust_table.set("ipc_set",
                       lua.create_function(ipc_set))?;
        let globals = lua.globals();
        globals.set("__rust", rust_table)?;
        globals.set("type", lua.create_function(type_override))?;
    }
    trace!("Executing Lua init...");
    let init_code = include_str!("../../lib/lua/lua_init.lua");
    let awesome_init_code = include_str!("../../lib/lua/awesome_init.lua");
    let util_code = include_str!("../../lib/lua/utils.lua");
    lua.exec::<()>(util_code, Some("utils.lua"))?;
    lua.exec::<()>(awesome_init_code, Some("awesome_init.lua"))?;
    awesome::init(&lua)
        .expect("Could not initialize awesome compatibilty modules");
    lua.exec::<()>(init_code, Some("lua_init.lua"))?;
    trace!("Lua register_libraries complete");
    Ok(())
}

/// This function behaves just like Lua's built-in type() function, but also recognises classes and
/// returns special names for them.
#[allow(unused)]
fn type_override(_lua: &rlua::Lua, arg: rlua::Value) -> Result<String, rlua::Error> {
    use rlua::Value;

    // Lua's type() returns the result of lua_typename(), but rlua does not make that available to
    // us, so write our own.
    match arg {
        Value::Nil => Ok("nil".to_owned()),
        Value::Boolean(_) => Ok("boolean".to_owned()),
        Value::LightUserData(_) => Ok("userdata".to_owned()),
        Value::UserData(_) => Ok("userdata".to_owned()),
        Value::Integer(_) => Ok("number".to_owned()),
        Value::Number(_) => Ok("number".to_owned()),
        Value::String(_) => Ok("string".to_owned()),
        Value::Function(_) => Ok("function".to_owned()),
        Value::Thread(_) => Ok("thread".to_owned()),
        Value::Error(e) => Err(e),
        Value::Table(t) => {
            // Handle our own objects specially: Return the metatable's .__class.name if it exists,
            // else return "table".
            match t.get_metatable() {
                None => Ok("table".to_owned()),
                Some(t) => t.raw_get("__class")
                    .and_then(|t: rlua::Table| t.raw_get("name"))
                    .or(Ok("table".to_owned()))
            }
        }
    }
}

/// Run a command
fn ipc_run(_lua: &rlua::Lua, command: String) -> Result<(), rlua::Error> {
    use rlua::Error;
    commands::get(&command).map(|com| com())
        .ok_or(Error::RuntimeError("Command does not exist".into()))
}

/// IPC 'get' handler
fn ipc_get<'lua>(lua: &'lua rlua::Lua, (category, key): (String, String))
                 -> Result<rlua::Value<'lua>, rlua::Error> {
    use rlua::Error;
    let lock = registry::clients_read();
    let client = lock.client(Uuid::nil()).unwrap();
    let handle = registry::ReadHandle::new(&client);
    handle.read(category)
        .map_err(|_|
                 Error::RuntimeError("Could not locate that category".into()))
        .and_then(|category| category.get(&key)
                  .ok_or(Error::RuntimeError(
                      "Could not locate that key in the category".into()))
                  .and_then(|value| json_to_lua(lua, value.to_json())))
}

/// ipc 'set' handler
fn ipc_set(_lua: &rlua::Lua, category: String) -> Result<(), rlua::Error> {
    update_registry_value(category);
    if running() {
        send(LuaQuery::UpdateRegistryFromCache)
            .expect("Could not send message to Lua thread to update registry");
    }
    Ok(())
}

fn init_workspaces(_: &rlua::Lua, _: rlua::Value) -> Result<(), rlua::Error> {
    warn!("Attempting to call `init_workspaces`, this is not implemented");
    Ok(())
}

/// Registers a modifier to be used in conjunction with mouse commands
fn register_mouse_modifier(_lua: &rlua::Lua, modifier: String)
                           -> Result<(), rlua::Error> {
    use rlua::Error;
    let modifier = keys::keymod_from_names(&[modifier.as_str()])
        .map_err(|txt| Error::RuntimeError(txt))?;
    keys::register_mouse_modifier(modifier);
    Ok(())
}

/// Registers a command keybinding.
fn register_command_key(_lua: &rlua::Lua,
                        (mods, command, _repeat, passthrough):
                        (String, String, bool, bool))
                        -> Result<(), rlua::Error> {
    use rlua::Error;
    if let Ok(press) = keypress_from_string(&mods) {
        commands::get(&command)
            .ok_or(Error::RuntimeError(
                format!("Command {} for keybinding {} not found", command, press)))
            .map(|command|
                keys::register(press, KeyEvent::Command(command), passthrough))?;
        Ok(())
    }
    else {
        Err(Error::RuntimeError(format!("Invalid keypress {}, {}", mods, command)))
    }
}

/// Rust half of registering a Lua key: store the KeyPress in the keys table
/// and send Lua back the index for __key_map.
fn register_lua_key(_lua: &rlua::Lua, (mods, _repeat, passthrough):
                          (String, bool, bool))
                          -> Result<String, rlua::Error> {
    use rlua::Error;
    keypress_from_string(&mods)
        .map(|press| {
            keys::register(press.clone(), KeyEvent::Lua, passthrough);
            press.get_lua_index_string()
        }).map_err(|_| Error::RuntimeError(format!("Invalid keys '{}'", mods)))
}

/// Rust half of unregistering a Lua key. This pops it from the key table, if
/// it exists.
///
/// If a key wasn't registered, a proper error string is raised.
fn unregister_lua_key(_lua: &rlua::Lua, mods: String)
                            -> Result<String, rlua::Error> {
    use rlua::Error;
    keypress_from_string(&mods).and_then(|press| {
        if let Some(action) = keys::unregister(&press) {
            trace!("Removed keybinding \"{}\" for {:?}", press, action);
            Ok(press.get_lua_index_string())
        } else {
            let error_str = format!("Could not remove keybinding \"{}\": \
                                     Not registered!",
                                    press);
            warn!("Could not remove keybinding \"{}\": Not registered!",
                  press);
            Err(error_str)
        }
    }).map_err(|err|
               Error::RuntimeError(format!("Invalid keys '{}': {:#?}", mods, err)))
}

/// Parses a keypress from a string
fn keypress_from_string(mods: &str) -> Result<KeyPress, String> {
    let parts: Vec<&str> = mods.split(',').collect();
    if let Some((ref key, mods)) = parts.split_last() {
        KeyPress::from_key_names(mods, &key)
    }
    else {
        Err(format!("Invalid key '{}'", mods))
    }
}

fn keypress_index(_lua: &rlua::Lua, press: String) -> Result<String, rlua::Error> {
    use rlua::Error;
    keypress_from_string(&press)
        .map(|key| key.get_lua_index_string())
        .map_err(|err_msg| Error::RuntimeError(err_msg))
}
<|endoftext|>


<commit_before>extern crate git2;
extern crate regex;

#[cfg(not(test))] use std::env;

use git2::{Repository, Commit};
use regex::Regex;

macro_rules! filter_option {
    ($e:expr) => (match $e { Ok(t) => t, Err(e) => return Some(Err(e)) })
}

macro_rules! option_match {
    ($e:expr) => (match $e { Ok(t) => t, Err(e) => panic!("err! - {}", e) })
}

fn main() {
    let repo = option_match!(Repository::open("./"));
    let mut revwalk = option_match!(repo.revwalk());

    option_match!(revwalk.push_range(&commit_range()[..]));

    let revwalk = revwalk.filter_map(|id| {
        let id = option_match!(id);
        let commit = filter_option!(repo.find_commit(id));
        Some(Ok(commit))
    });

    for commit in revwalk {
        let commit = option_match!(commit);
        print_to_stdout(&commit);
    }
}

fn print_to_stdout(commit: &Commit) {
    for line in String::from_utf8_lossy(commit.message_bytes()).lines() {
        let re = Regex::new(r"^#changelog.*$").unwrap();

        if re.is_match(line) {
            println!("{} by {}", line, commit.author());
        }
    };
}

fn commit_range() -> String {
    let args: Vec<_> = env::args().collect();
    let commit_from: &str = &args[1][..];
    let commit_to: &str = &args[2][..];
    let mut commit_range = String::from("");

    commit_range.push_str(commit_from);
    commit_range.push_str("..");
    commit_range.push_str(commit_to);

    commit_range
}

#[cfg(test)] mod env {
    use std::vec;
    pub fn args() -> vec::IntoIter<&'static str> { vec!["changelg", "377d686351969f27f288dec2fb09d0d5431fcde1", "3763e0e3ff218cbdfbf99c68109a04d666e81abeto"].into_iter() }
}

#[test]
#[should_panic]
fn it_should_panic_on_error_in_option_match() {
    fn something_bad_happens<T>() -> Result<T, &'static str> {
        Err("Fail")
    };

    option_match!(something_bad_happens());
}

#[test]
fn it_should_return_result_on_ok_in_option_match() {
    fn something_good_happens() -> Result<&'static str, &'static str> {
        Ok("Good")
    };

    let result = option_match!(something_good_happens());
    assert_eq!(result, "Good");
}

#[test]
fn it_should_return_expected_commit_range_string(){
    assert_eq!(commit_range(), "377d686351969f27f288dec2fb09d0d5431fcde1..3763e0e3ff218cbdfbf99c68109a04d666e81abeto");
}<commit_msg>Refactoring code structure<commit_after>extern crate git2;
extern crate regex;

use std::env;

use git2::{Repository, Commit};
use regex::Regex;

macro_rules! filter_option {
    ($e:expr) => (match $e { Ok(t) => t, Err(e) => return Some(Err(e)) })
}

macro_rules! option_match {
    ($e:expr) => (match $e { Ok(t) => t, Err(e) => panic!("err! - {}", e) })
}

fn main() {
    changelg(env::args().collect());
}

fn changelg(args: Vec<String>) {
    let repo = option_match!(Repository::open("./"));
    let mut revwalk = option_match!(repo.revwalk());

    option_match!(
        revwalk.push_range(
            &commit_range(&args[1][..], &args[2][..])[..]
        )
    );

    let revwalk = revwalk.filter_map(|id| {
        let id = option_match!(id);
        let commit = filter_option!(repo.find_commit(id));
        Some(Ok(commit))
    });

    for commit in revwalk {
        let commit = option_match!(commit);
        print_to_stdout(&commit);
    }
}

fn commit_range(commit_from: &str, commit_to: &str) -> String {
    let mut commit_range = String::from("");

    commit_range.push_str(commit_from);
    commit_range.push_str("..");
    commit_range.push_str(commit_to);

    commit_range
}

fn print_to_stdout(commit: &Commit) {
    for line in String::from_utf8_lossy(commit.message_bytes()).lines() {
        if match_changelog_identifier(line) {
            println!("{} by {}", line, commit.author());
        };
    };
}

fn match_changelog_identifier(line: &str) -> bool {
    let re = Regex::new(r"^#changelog.*$").unwrap();
    re.is_match(line)
}

#[test]
#[should_panic]
fn it_should_panic_on_error_in_option_match() {
    fn something_bad_happens<T>() -> Result<T, &'static str> {
        Err("Fail")
    };

    option_match!(something_bad_happens());
}

#[test]
fn it_should_return_result_on_ok_in_option_match() {
    fn something_good_happens() -> Result<&'static str, &'static str> {
        Ok("Good")
    };

    let result = option_match!(something_good_happens());
    assert_eq!(result, "Good");
}

#[test]
fn it_should_return_expected_commit_range_string(){
    let commit_range = commit_range("377d686351969f27f288dec2fb09d0d5431fcde1", "3763e0e3ff218cbdfbf99c68109a04d666e81abeto");
    assert_eq!(commit_range, "377d686351969f27f288dec2fb09d0d5431fcde1..3763e0e3ff218cbdfbf99c68109a04d666e81abeto");
}

#[test]
fn it_should_return_true_when_a_string_is_tagged_changelog_(){
    let result = match_changelog_identifier("#changelog Hello World");
    assert_eq!(result, true);
}

#[test]
fn it_should_return_false_when_a_string_is_tagged_changelog_(){
    let result = match_changelog_identifier("Hello World");
    assert_eq!(result, false);
}<|endoftext|>


<commit_before>extern crate mmap;
extern crate time;
extern crate timely;
extern crate getopts;

use timely::progress::timestamp::RootTimestamp;
use timely::progress::nested::Summary::Local;
use timely::dataflow::*;
use timely::dataflow::operators::*;
// use timely::communication::*;
use timely::dataflow::channels::pact::Exchange;
use timely::drain::DrainExt;

mod typedrw;
mod graphmap;
mod sorting;
use graphmap::GraphMMap;
use sorting::{SegmentList, radix_sort_32};

fn main () {

    let filename = std::env::args().skip(1).next().unwrap();
    let strategy = std::env::args().skip(2).next().unwrap() == "process";

    // currently need timely's full option set to parse args
    let mut opts = getopts::Options::new();
    opts.optopt("w", "workers", "", "");
    opts.optopt("p", "process", "", "");
    opts.optopt("n", "processes", "", "");
    opts.optopt("h", "hostfile", "", "");

    if let Ok(matches) = opts.parse(std::env::args().skip(3)) {

        let workers: usize = matches.opt_str("w").map(|x| x.parse().unwrap_or(1)).unwrap_or(1);

        timely::execute_from_args(std::env::args().skip(2), move |root| {

            let index = root.index() as usize;
            let peers = root.peers() as usize;

            let start = time::precise_time_s();

            let nodes = GraphMMap::new(&filename).nodes();

            let mut segments = SegmentList::new(1024); // list of edge segments

            let mut src = vec![];   // holds ranks
            let mut deg = vec![];   // holds source degrees
            let mut rev = vec![];   // holds (dst, deg) pairs
            let mut trn = vec![];   // holds transposed sources

            let mut going = start;

            let mut input = root.scoped(|builder| {

                let (input, edges) = builder.new_input::<(u32, u32)>();
                let (cycle, ranks) = builder.loop_variable::<(u32, f32)>(RootTimestamp::new(20), Local(1));

                let mut ranks = edges.binary_notify(&ranks,
                                    Exchange::new(|x: &(u32,u32)| x.0 as u64),
                                    Exchange::new(|x: &(u32,f32)| x.0 as u64),
                                    "pagerank",
                                    vec![RootTimestamp::new(0)],
                                    move |input1, input2, output, notificator| {

                    // receive incoming edges (should only be iter 0)
                    while let Some((_index, data)) = input1.next() {
                        segments.push(data.drain_temp());
                    }

                    // all inputs received for iter, commence multiplication
                    while let Some((iter, _)) = notificator.next() {

                        let now = time::now();

                        if index == 0 { println!("{}:{}:{}.{} starting iteration {}", now.tm_hour, now.tm_min, now.tm_sec, now.tm_nsec, iter.inner); }

                        // if the very first iteration, prepare some stuff.
                        // specifically, transpose edges and sort by destination.
                        if iter.inner == 0 {
                            let (a, b, c) = transpose(segments.finalize(), peers, nodes);
                            deg = a; rev = b; trn = c;
                            src = vec![0.0f32; deg.len()];
                        }

                        // record some timings in order to estimate per-iteration times
                        if iter.inner == 0  && index == 0 { println!("src: {}, dst: {}, edges: {}", src.len(), rev.len(), trn.len()); }
                        if iter.inner == 10 && index == 0 { going = time::precise_time_s(); }
                        if iter.inner == 20 && index == 0 { println!("average: {}", (time::precise_time_s() - going) / 10.0 ); }

                        // prepare src for transmitting to destinations
                        for s in 0..src.len() { src[s] = 0.15 + 0.85 * src[s] / deg[s] as f32; }

                        // wander through destinations
                        let mut trn_slice = &trn[..];
                        let mut session = output.session(&iter);
                        for &(dst, deg) in &rev {
                            let mut accum = 0.0;
                            for &s in &trn_slice[..deg as usize] {
                                accum += src[s as usize];
                            }
                            trn_slice = &trn_slice[deg as usize..];
                            session.give((dst, accum));
                        }

                        for s in &mut src { *s = 0.0; }
                    }

                    // receive data from workers, accumulate in src
                    while let Some((iter, data)) = input2.next() {
                        notificator.notify_at(&iter);
                        for &(node, rank) in data.iter() {
                            src[node as usize / peers] += rank;
                        }
                    }
                });

                // optionally, do process-local accumulation
                if strategy {
                    let local_base = workers * (index / workers);
                    let local_index = index % workers;
                    let mut acc = vec![0.0; (nodes / workers) + 1];   // holds ranks
                    ranks = ranks.unary_notify(
                        Exchange::new(move |x: &(u32,f32)| (local_base as u64 + (x.0 as u64 % workers as u64))),
                        "aggregation",
                        vec![],
                        move |input, output, iterator| {
                            while let Some((iter, data)) = input.next() {
                                iterator.notify_at(&iter);
                                for &(node, rank) in data.iter() {
                                    acc[node as usize / workers] += rank;
                                }
                            }

                            while let Some((item, _)) = iterator.next() {
                                output.session(&item)
                                      .give_iterator(acc.drain_temp()
                                                        .enumerate()
                                                        .filter(|x| x.1 != 0.0)
                                                        .map(|(u,f)| ((u * workers + local_index) as u32, f)));

                                for _ in 0..(1 + (nodes/workers)) { acc.push(0.0); }
                            }
                        }
                    );
                }

                ranks.connect_loop(cycle);

                input
            });

            // introduce edges into the computation;
            // allow mmaped file to drop
            {
                let graph = GraphMMap::new(&filename);
                for node in 0..graph.nodes() {
                    if node % peers == index {
                        for dst in graph.edges(node) {
                            input.send((node as u32, *dst as u32));
                        }
                    }
                }
            }
            input.close();
            while root.step() { }

            if index == 0 { println!("elapsed: {}", time::precise_time_s() - start); }
        });
    }
    else {
        println!("error parsing arguments");
        println!("usage:\tpagerank <source> (worker|process) [timely options]");
    }
}

// returns [src/peers] degrees, (dst, deg) pairs, and a list of [src/peers] endpoints
fn transpose(mut edges: Vec<Vec<(u32, u32)>>, peers: usize, nodes: usize) -> (Vec<u32>, Vec<(u32, u32)>, Vec<u32>)  {

    let mut deg = vec![0; (nodes as usize / peers) + 1];
    for list in &edges {
        for &(s, _) in list {
            deg[s as usize / peers] += 1;
        }
    }

    radix_sort_32(&mut edges, &mut Vec::new(), &|&(_,d)| d);

    let mut rev = Vec::<(u32,u32)>::with_capacity(deg.len());
    let mut trn = Vec::with_capacity(edges.len() * 1024);
    for list in edges {
        for (s,d) in list {
            let len = rev.len();
            if (len == 0) || (rev[len-1].0 < d) {
                rev.push((d, 0u32));
            }

            let len = rev.len();
            rev[len-1].1 += 1;
            trn.push(s / peers as u32);
        }
    }

    return (deg, rev, trn);
}
<commit_msg>version drift in timely<commit_after>extern crate mmap;
extern crate time;
extern crate timely;
extern crate getopts;

use timely::progress::timestamp::RootTimestamp;
// use timely::progress::nested::Summary::Local;
use timely::dataflow::*;
use timely::dataflow::operators::*;
// use timely::communication::*;
use timely::dataflow::channels::pact::Exchange;
use timely::drain::DrainExt;

mod typedrw;
mod graphmap;
mod sorting;
use graphmap::GraphMMap;
use sorting::{SegmentList, radix_sort_32};

fn main () {

    let filename = std::env::args().skip(1).next().unwrap();
    let strategy = std::env::args().skip(2).next().unwrap() == "process";

    // currently need timely's full option set to parse args
    let mut opts = getopts::Options::new();
    opts.optopt("w", "workers", "", "");
    opts.optopt("p", "process", "", "");
    opts.optopt("n", "processes", "", "");
    opts.optopt("h", "hostfile", "", "");

    if let Ok(matches) = opts.parse(std::env::args().skip(3)) {

        let workers: usize = matches.opt_str("w").map(|x| x.parse().unwrap_or(1)).unwrap_or(1);

        timely::execute_from_args(std::env::args().skip(2), move |root| {

            let index = root.index() as usize;
            let peers = root.peers() as usize;

            let start = time::precise_time_s();

            let nodes = GraphMMap::new(&filename).nodes();

            let mut segments = SegmentList::new(1024); // list of edge segments

            let mut src = vec![];   // holds ranks
            let mut deg = vec![];   // holds source degrees
            let mut rev = vec![];   // holds (dst, deg) pairs
            let mut trn = vec![];   // holds transposed sources

            let mut going = start;

            let mut input = root.scoped(|builder| {

                let (input, edges) = builder.new_input::<(u32, u32)>();
                let (cycle, ranks) = builder.loop_variable::<(u32, f32)>(20, 1);

                let mut ranks = edges.binary_notify(&ranks,
                                    Exchange::new(|x: &(u32,u32)| x.0 as u64),
                                    Exchange::new(|x: &(u32,f32)| x.0 as u64),
                                    "pagerank",
                                    vec![RootTimestamp::new(0)],
                                    move |input1, input2, output, notificator| {

                    // receive incoming edges (should only be iter 0)
                    while let Some((_index, data)) = input1.next() {
                        segments.push(data.drain_temp());
                    }

                    // all inputs received for iter, commence multiplication
                    while let Some((iter, _)) = notificator.next() {

                        let now = time::now();

                        if index == 0 { println!("{}:{}:{}.{} starting iteration {}", now.tm_hour, now.tm_min, now.tm_sec, now.tm_nsec, iter.inner); }

                        // if the very first iteration, prepare some stuff.
                        // specifically, transpose edges and sort by destination.
                        if iter.inner == 0 {
                            let (a, b, c) = transpose(segments.finalize(), peers, nodes);
                            deg = a; rev = b; trn = c;
                            src = vec![0.0f32; deg.len()];
                        }

                        // record some timings in order to estimate per-iteration times
                        if iter.inner == 0  && index == 0 { println!("src: {}, dst: {}, edges: {}", src.len(), rev.len(), trn.len()); }
                        if iter.inner == 10 && index == 0 { going = time::precise_time_s(); }
                        if iter.inner == 20 && index == 0 { println!("average: {}", (time::precise_time_s() - going) / 10.0 ); }

                        // prepare src for transmitting to destinations
                        for s in 0..src.len() { src[s] = 0.15 + 0.85 * src[s] / deg[s] as f32; }

                        // wander through destinations
                        let mut trn_slice = &trn[..];
                        let mut session = output.session(&iter);
                        for &(dst, deg) in &rev {
                            let mut accum = 0.0;
                            for &s in &trn_slice[..deg as usize] {
                                accum += src[s as usize];
                            }
                            trn_slice = &trn_slice[deg as usize..];
                            session.give((dst, accum));
                        }

                        for s in &mut src { *s = 0.0; }
                    }

                    // receive data from workers, accumulate in src
                    while let Some((iter, data)) = input2.next() {
                        notificator.notify_at(&iter);
                        for &(node, rank) in data.iter() {
                            src[node as usize / peers] += rank;
                        }
                    }
                });

                // optionally, do process-local accumulation
                if strategy {
                    let local_base = workers * (index / workers);
                    let local_index = index % workers;
                    let mut acc = vec![0.0; (nodes / workers) + 1];   // holds ranks
                    ranks = ranks.unary_notify(
                        Exchange::new(move |x: &(u32,f32)| (local_base as u64 + (x.0 as u64 % workers as u64))),
                        "aggregation",
                        vec![],
                        move |input, output, iterator| {
                            while let Some((iter, data)) = input.next() {
                                iterator.notify_at(&iter);
                                for &(node, rank) in data.iter() {
                                    acc[node as usize / workers] += rank;
                                }
                            }

                            while let Some((item, _)) = iterator.next() {
                                output.session(&item)
                                      .give_iterator(acc.drain_temp()
                                                        .enumerate()
                                                        .filter(|x| x.1 != 0.0)
                                                        .map(|(u,f)| ((u * workers + local_index) as u32, f)));

                                for _ in 0..(1 + (nodes/workers)) { acc.push(0.0); }
                            }
                        }
                    );
                }

                ranks.connect_loop(cycle);

                input
            });

            // introduce edges into the computation;
            // allow mmaped file to drop
            {
                let graph = GraphMMap::new(&filename);
                for node in 0..graph.nodes() {
                    if node % peers == index {
                        for dst in graph.edges(node) {
                            input.send((node as u32, *dst as u32));
                        }
                    }
                }
            }
            input.close();
            while root.step() { }

            if index == 0 { println!("elapsed: {}", time::precise_time_s() - start); }
        });
    }
    else {
        println!("error parsing arguments");
        println!("usage:\tpagerank <source> (worker|process) [timely options]");
    }
}

// returns [src/peers] degrees, (dst, deg) pairs, and a list of [src/peers] endpoints
fn transpose(mut edges: Vec<Vec<(u32, u32)>>, peers: usize, nodes: usize) -> (Vec<u32>, Vec<(u32, u32)>, Vec<u32>)  {

    let mut deg = vec![0; (nodes as usize / peers) + 1];
    for list in &edges {
        for &(s, _) in list {
            deg[s as usize / peers] += 1;
        }
    }

    radix_sort_32(&mut edges, &mut Vec::new(), &|&(_,d)| d);

    let mut rev = Vec::<(u32,u32)>::with_capacity(deg.len());
    let mut trn = Vec::with_capacity(edges.len() * 1024);
    for list in edges {
        for (s,d) in list {
            let len = rev.len();
            if (len == 0) || (rev[len-1].0 < d) {
                rev.push((d, 0u32));
            }

            let len = rev.len();
            rev[len-1].1 += 1;
            trn.push(s / peers as u32);
        }
    }

    return (deg, rev, trn);
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate goblin;
extern crate rustc_demangle;
extern crate toml;
extern crate capstone;
#[macro_use] extern crate quick_error;

pub mod symbol;

use clap::{Arg, App, SubCommand, AppSettings};
use symbol::Symbol;

use std::fs::File;
use std::io::{self, Cursor, Read, Seek, ErrorKind};
use std::io::SeekFrom;
use std::path::{Path, PathBuf};
use std::result;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Io(err: std::io::Error) { from () }
        CapstoneError(err: capstone::error::Error) { from ()}
        UnsupportedBinary { from() }
        SectionlessBinary { description("Cannot analyze and disassemble a sectionless (section stripped) binary") from() }
        StrippedBinary { description("Cannot analyze and disassemble a stripped binary") from() }
    }
}

type Result<T> = result::Result<T, Error>;

/// The command line state we're interested in
pub struct Config {
    pub exports: bool,
    pub demangle: bool,
    pub crate_name: String,
    pub disassemble: bool,
}

/// A symbol object.
/// - It knows how to return `Symbol`s _and_ disassemble itself, as well as other useful information about itself.
/// When a new binary backend becomes available, `impl` a new `SymObject`!
pub trait SymObject {
    fn get_arch(&self) -> Option<capstone::Arch>;
    fn is_64(&self) -> bool;
    fn symbols(&self, config: &Config) -> Vec<Symbol>;
    fn disassemble(&self, bytes: &mut Cursor<&Vec<u8>>, config: &Config) -> Result<()>;
    #[inline]
    fn print_instructions(&self, bytes: &[u8], config: &Config, capstone: &capstone::Capstone, symbol: Symbol) -> Result<()> {
        let offset = symbol.offset as usize;
        let bytes = &bytes[offset .. offset + symbol.size];
        let instructions = capstone.disassemble(bytes, symbol.vaddr)?;
        if !instructions.is_empty() {
            println!("{}:\n{}", symbol.format(config.demangle, self.is_64()), instructions);
        }
        Ok(())
    }
    fn print_symbols(&self, config: &Config) {
        for symbol in self.symbols(config) {
            println!("{}", symbol.format(config.demangle, self.is_64()))
        }
    }
    fn analyze (&self, bytes: &mut Cursor<&Vec<u8>>, config: &Config) -> Result<()> {
        if config.disassemble {
            self.disassemble(bytes, config)?;
        } else {
            self.print_symbols(config);
        }
        Ok(())
    }
}

fn bias(sym: &goblin::elf::Sym, section: &goblin::elf::SectionHeader) -> u64 {
    (sym.st_value() - section.sh_addr()) + section.sh_offset()
}

fn valid_disassembly_target(name: &str) -> bool {
    match name {
        ".init" | ".plt" | ".got" | ".plt.got" | ".text" | ".fini" => true,
        _ => false,
    }
}

// this is all terribly inefficient right now, primarily due to goblin parsing and reading everything
// on earth. that should be fixed soon with some special magiks
impl SymObject for goblin::elf::Elf {
    fn is_64(&self) -> bool {
        self.is_64
    }
    fn symbols(&self, config: &Config) -> Vec<Symbol> {
        let mut syms = Vec::new();
        let (iter, strtab) = if config.exports {
            (&self.dynsyms, &self.dynstrtab)
        } else {
            (&self.syms, &self.strtab)
        };
        for sym in iter {
            let name = &strtab[sym.st_name() as usize];
            // we skip boring empty symbol names and imports
            if !name.is_empty() && (!config.exports || !sym.is_import()) {
                syms.push(Symbol::new(name, sym.st_value(), sym.st_value(), sym.st_size() as usize));
            }
        }
        syms.sort_by(|s1, s2| s1.offset.cmp(&s2.offset));
        syms
    }

    fn get_arch(&self) -> Option<capstone::Arch> {
        use goblin::elf::header::*;
        use capstone::Arch::*;
        match self.header.e_machine() {
            EM_AARCH64 => Some(ARM64),
            EM_ARM => Some(ARM),
            EM_X86_64 => Some(X86),
            EM_386 => Some(X86),
            _ => None
        }
    }

    fn disassemble (&self, bytes: &mut Cursor<&Vec<u8>>, config: &Config) -> Result<()> {
        let arch = self.get_arch().ok_or(Error::UnsupportedBinary)?;
        let mut capstone = capstone::Capstone::new(arch)?;
        capstone.att();
        let mode = if self.little_endian { capstone::Mode::LittleEndian } else { capstone::Mode::BigEndian };
        capstone.mode(&[mode])?;
        let strtab = &self.strtab;
        let shdr_strtab = &self.shdr_strtab;
        let bytes = bytes.get_ref();
        let section_headers = &self.section_headers;

//        let bias = |sym, section| {
//            let sym: &goblin::elf::Sym = sym;
//            let section: &goblin::elf::SectionHeader = section;
//            (sym.st_value() - section.sh_addr()) + section.sh_offset()
//        };

        if section_headers.len() == 0 { return Err(Error::SectionlessBinary)}
        let sections: Vec<(_, &str)> = section_headers.into_iter().map (| section | {
            let section_name = &shdr_strtab[section.sh_name()];
            (section, section_name)
        }).collect();
        let syms = &self.syms;
        if syms.len() == 0 { return Err(Error::StrippedBinary)}
        // filter the symbols to remove imports and empty symbol names
        let mut elf_syms = syms.into_iter().filter(|sym| !sym.is_import() && !&strtab[sym.st_name()].is_empty()).collect::<Vec<_>>();
        elf_syms.sort_by(|s1, s2| {
            use std::cmp::Ordering::*;
            match s1.st_shndx().cmp(&s2.st_shndx()) {
                Equal => {
                    s1.st_value().cmp(&s2.st_value())
                },
                order => order
            }
        });
        let mut current_section = 0;
        let nsyms = elf_syms.len();
        let mut i = 0;
        for sym in &elf_syms {
            //println!("name: {} st_shndx: {}", &strtab[sym.st_name()],  sym.st_shndx());
            //println!("{} {:?}", &strtab[sym.st_name()], sym);
            let is_last = i >= nsyms - 1;
            let section_index = sym.st_shndx();
            if section_index >= sections.len() { continue }
            let (ref section, ref section_name) = sections[sym.st_shndx() as usize];
            if section.sh_type() != goblin::elf::section_header::SHT_PROGBITS || !valid_disassembly_target(section_name) { continue }
            //if name.is_empty() { name = format!("{}@{}", &dynstrtab[sym.st_name()], section_name)}
            if current_section != section_index {
                current_section = section_index;
                println!("Disassembly of section {}\n", section_name);
                match section_name {
                    // TODO: this is now a _broken_ hack for printing PLT entries (it doesn't print them,
                    // because there are no longer any symbols with the plt section to set off this logic)
                    &".plt" | &".plt.got" => {
                        let start = section.sh_offset();
                        let vaddr = section.sh_addr();
                        let ssize = section.sh_entsize() as usize;
                        let size = section.sh_entsize();
                        let strtab = &self.dynstrtab;
                        let symbol = Symbol::new(&"PLT", start, vaddr, ssize);
                        self.print_instructions(&bytes, config, &capstone, symbol)?;
                        let mut offset = size;
                        for rela in &self.pltrela {
                            let start = start + offset;
                            let vaddr = vaddr + offset;
                            let symindex = rela.r_sym();
                            let sym = self.dynsyms.get(symindex);
                            let name = &strtab[sym.st_name()];
                            //println!("name: {} offset {:x} size: {} shname: {} shoffset: {:x} shaddr: {:x}", name, rela.r_offset(), size, section_name, section.sh_offset(), section.sh_addr());
                            let symbol = Symbol::new(&name, start, vaddr, ssize);
                            self.print_instructions(&bytes, config, &capstone, symbol)?;
                            offset += size;
                        }
                    },
                    _ => ()
                }
            }
            // we're not doing plt stuff, so regular disassembly
            let name = &strtab[sym.st_name()];
            if name.is_empty() { continue }
            let mut size = sym.st_size() as usize;
            let offset = bias(&sym, &section);
            // we compute the size of unsized symbols on the fly. it sucks. because elf sucks.
            if size == 0 && !is_last {
                let next_sym = &elf_syms[i + 1];
                //println!("i: {} current {}, name{} next: {:?}", i, current_section, name, next_sym);
                if current_section == next_sym.st_shndx() {
                    let next_offset = bias(&next_sym, &section);
                    size = (next_offset - offset) as usize;
                } else {
                    size = section.sh_size() as usize;
                }
            }
            //println!("offset {:x} size: {} section: {}, sh_type: {}", offset, size, section_name, section_header::sht_to_str(section.sh_type()));
            let symbol = Symbol::new(name, offset, sym.st_value(), size);
            self.print_instructions(&bytes, config, &capstone, symbol)?;
            i += 1;
        }
        Ok(())
    }
}

fn get_crate_name() -> String {
    let mut toml_fd = File::open("Cargo.toml")
                          .expect("No Cargo.toml file found in root directory...");
    let mut toml = String::new();
    let _ = toml_fd.read_to_string(&mut toml);
    let value: toml::Value = toml.parse().expect("Malformed Cargo.toml file");
    let package_name = value.lookup("package.name")
                            .expect("No package.name in Cargo.toml")
                            .as_str()
                            .unwrap()
                            .to_owned()
        // we only replace this if it's a library..., so this breaks on ourself :/
                            .replace("-", "_");
    package_name
}

fn get_target(crate_name: &str) -> Option<PathBuf> {
    let targets = [Path::new("target").join("debug").join(&crate_name),
                   Path::new("target").join("debug").join(&format!("lib{}.so", &crate_name)),
                   Path::new("target").join("debug").join(&format!("lib{}.rlib", &crate_name)),
                   Path::new("target").join("debug").join(&format!("lib{}.a", &crate_name))];
    for target in &targets {
        match File::open(&target) {
            Ok(_) => return Some(target.clone()),
            _ => (),
        }
    }
    None
}

fn run(fd: &mut File, config: &Config) -> Result<()> {
    // todo write a generic peek function in goblin you jerk
    let mut magic = [0u8; 16];
    let err = ErrorKind::InvalidInput;
    let metadata = fd.metadata()?;
    let mut buffer = Vec::new();
    fd.read_to_end(&mut buffer)?;
    let mut bytes = &mut Cursor::new(&buffer);
    bytes.read(&mut magic)?;
    bytes.seek(SeekFrom::Start(0))?;
    if &magic[0..goblin::archive::SIZEOF_MAGIC] == goblin::archive::MAGIC {
        let archive = goblin::archive::Archive::parse(bytes, metadata.len() as usize)?;
        let bytes = archive.extract(&format!("{}.0.o", &config.crate_name), bytes)?;
        let mut bytes = Cursor::new(&bytes);
        // ideally would pattern match (or just recurse) on the identifier here but we're only supporting elf
        let elf = goblin::elf::Elf::parse(&mut bytes)?;
        elf.analyze(&mut bytes, config)
    } else if &magic[0..4] == goblin::elf::header::ELFMAG {
        let elf = goblin::elf::Elf::parse(bytes)?;
        elf.analyze(bytes, config)
    } else {
        Err(Error::from(io::Error::new(err,
                           format!("No binary backend available for target: {:?}", &fd))))
    }
}

fn main() {

    let matches = App::new("cargo-sym")
                      .version("0.0.3")
                      .bin_name("cargo")
                      .settings(&[AppSettings::GlobalVersion, AppSettings::SubcommandRequired])
                      .subcommand(SubCommand::with_name("sym")
                                      .author("m4b <m4b.github.io@gmail.com>")
                                      .about("Prints the debugging symbols in your binary; more \
                                              fancy stuff to come later")
                                      .args(&[Arg::with_name("binary")
                                                  .help("The binary file to read ")
                                                  .required(false)
                                                  .index(1),
                                          Arg::with_name("disassemble")
                                              .short("-d")
                                              .long("disassemble")
                                              .value_name("DISASSEMBLE")
                                              .takes_value(false)
                                              .help("Whether to disassaemble or not "),
                                          Arg::with_name("demangle")
                                                  .short("-C")
                                                  .long("demangle")
                                                  .value_name("DEMANGLE")
                                                  .takes_value(false)
                                                  .help("Whether to demangle or not "),
                                              Arg::with_name("exports")
                                                  .short("-e")
                                                  .long("exports")
                                                  .value_name("EXPORTS")
                                                  .takes_value(false)
                                                  .help("Print the exported symbols that are \
                                                         importable by other binaries")]))
                      .get_matches();

    let crate_name = get_crate_name();
    let matches = matches.subcommand_matches("sym").unwrap();
    let demangle = matches.is_present("demangle");
    let exports = matches.is_present("exports");
    let disassemble = matches.is_present("disassemble");
    let config = Config {
        demangle: demangle,
        exports: exports,
        crate_name: crate_name.to_string(),
        disassemble: disassemble,
    };
    let mut fd = match matches.value_of("binary") {
                     Some(binary) => File::open(Path::new(binary)),
                     _ => File::open(get_target(&crate_name).expect("No valid binary found")),
                 }
                 .expect("Cannot open file");

    run(&mut fd, &config)
        .expect(&format!("Cannot read symbols from: {:?}", &fd));
}
<commit_msg>reformat with newer rustfmt and add --dump flag to print debug contents of binary<commit_after>extern crate clap;
extern crate goblin;
extern crate rustc_demangle;
extern crate toml;
extern crate capstone;
#[macro_use]
extern crate quick_error;

pub mod symbol;

use clap::{Arg, App, SubCommand, AppSettings};
use symbol::Symbol;

use std::fs::File;
use std::io::{self, Cursor, Read, Seek, ErrorKind};
use std::io::SeekFrom;
use std::path::{Path, PathBuf};
use std::result;
use std::fmt;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Io(err: std::io::Error) { from () }
        CapstoneError(err: capstone::error::Error) { from ()}
        UnsupportedBinary { from() }
        SectionlessBinary { description("Cannot analyze and disassemble a sectionless (section stripped) binary") from() }
        StrippedBinary { description("Cannot analyze and disassemble a stripped binary") from() }
    }
}

type Result<T> = result::Result<T, Error>;

/// The command line state we're interested in
pub struct Config {
    pub exports: bool,
    pub demangle: bool,
    pub crate_name: String,
    pub disassemble: bool,
    pub dump: bool,
}

/// A symbol object.
/// - It knows how to return `Symbol`s _and_ disassemble itself, as well as other useful information about itself.
/// When a new binary backend becomes available, `impl` a new `SymObject`!
pub trait SymObject: fmt::Debug {
    fn get_arch(&self) -> Option<capstone::Arch>;
    fn is_64(&self) -> bool;
    fn symbols(&self, config: &Config) -> Vec<Symbol>;
    fn disassemble(&self, bytes: &mut Cursor<&Vec<u8>>, config: &Config) -> Result<()>;
    #[inline]
    fn print_instructions(&self,
                          bytes: &[u8],
                          config: &Config,
                          capstone: &capstone::Capstone,
                          symbol: Symbol)
                          -> Result<()> {
        let offset = symbol.offset as usize;
        let bytes = &bytes[offset..offset + symbol.size];
        let instructions = capstone.disassemble(bytes, symbol.vaddr)?;
        if !instructions.is_empty() {
            println!("{}:\n{}",
                     symbol.format(config.demangle, self.is_64()),
                     instructions);
        }
        Ok(())
    }
    fn print_symbols(&self, config: &Config) {
        for symbol in self.symbols(config) {
            println!("{}", symbol.format(config.demangle, self.is_64()))
        }
    }
    fn analyze(&self, bytes: &mut Cursor<&Vec<u8>>, config: &Config) -> Result<()> {
        if config.disassemble {
            self.disassemble(bytes, config)?;
        }
        if config.dump {
            println!("{:#?}", self);
        } else {
            self.print_symbols(config);
        }
        Ok(())
    }
}

fn bias(sym: &goblin::elf::Sym, section: &goblin::elf::SectionHeader) -> u64 {
    (sym.st_value() - section.sh_addr()) + section.sh_offset()
}

fn valid_disassembly_target(name: &str) -> bool {
    match name {
        ".init" | ".plt" | ".got" | ".plt.got" | ".text" | ".fini" => true,
        _ => false,
    }
}

// this is all terribly inefficient right now, primarily due to goblin parsing and reading everything
// on earth. that should be fixed soon with some special magiks
impl SymObject for goblin::elf::Elf {
    fn is_64(&self) -> bool {
        self.is_64
    }
    fn symbols(&self, config: &Config) -> Vec<Symbol> {
        let mut syms = Vec::new();
        let (iter, strtab) = if config.exports {
            (&self.dynsyms, &self.dynstrtab)
        } else {
            (&self.syms, &self.strtab)
        };
        for sym in iter {
            let name = &strtab[sym.st_name() as usize];
            // we skip boring empty symbol names and imports
            if !name.is_empty() && (!config.exports || !sym.is_import()) {
                syms.push(Symbol::new(name,
                                      sym.st_value(),
                                      sym.st_value(),
                                      sym.st_size() as usize));
            }
        }
        syms.sort_by(|s1, s2| s1.offset.cmp(&s2.offset));
        syms
    }

    fn get_arch(&self) -> Option<capstone::Arch> {
        use goblin::elf::header::*;
        use capstone::Arch::*;
        match self.header.e_machine() {
            EM_AARCH64 => Some(ARM64),
            EM_ARM => Some(ARM),
            EM_X86_64 => Some(X86),
            EM_386 => Some(X86),
            _ => None,
        }
    }

    fn disassemble(&self, bytes: &mut Cursor<&Vec<u8>>, config: &Config) -> Result<()> {
        let arch = self.get_arch().ok_or(Error::UnsupportedBinary)?;
        let mut capstone = capstone::Capstone::new(arch)?;
        capstone.att();
        let mode = if self.little_endian {
            capstone::Mode::LittleEndian
        } else {
            capstone::Mode::BigEndian
        };
        capstone.mode(&[mode])?;
        let strtab = &self.strtab;
        let shdr_strtab = &self.shdr_strtab;
        let bytes = bytes.get_ref();
        let section_headers = &self.section_headers;

        //        let bias = |sym, section| {
        //            let sym: &goblin::elf::Sym = sym;
        //            let section: &goblin::elf::SectionHeader = section;
        //            (sym.st_value() - section.sh_addr()) + section.sh_offset()
        //        };

        if section_headers.len() == 0 {
            return Err(Error::SectionlessBinary);
        }
        let sections: Vec<(_, &str)> = section_headers.into_iter()
            .map(|section| {
                let section_name = &shdr_strtab[section.sh_name()];
                (section, section_name)
            })
            .collect();
        let syms = &self.syms;
        if syms.len() == 0 {
            return Err(Error::StrippedBinary);
        }
        // filter the symbols to remove imports and empty symbol names
        let mut elf_syms = syms.into_iter()
            .filter(|sym| !sym.is_import() && !&strtab[sym.st_name()].is_empty())
            .collect::<Vec<_>>();
        elf_syms.sort_by(|s1, s2| {
            use std::cmp::Ordering::*;
            match s1.st_shndx().cmp(&s2.st_shndx()) {
                Equal => s1.st_value().cmp(&s2.st_value()),
                order => order,
            }
        });
        let mut current_section = 0;
        let nsyms = elf_syms.len();
        let mut i = 0;
        for sym in &elf_syms {
            // println!("name: {} st_shndx: {}", &strtab[sym.st_name()],  sym.st_shndx());
            // println!("{} {:?}", &strtab[sym.st_name()], sym);
            let is_last = i >= nsyms - 1;
            let section_index = sym.st_shndx();
            if section_index >= sections.len() {
                continue;
            }
            let (ref section, ref section_name) = sections[sym.st_shndx() as usize];
            if section.sh_type() != goblin::elf::section_header::SHT_PROGBITS ||
               !valid_disassembly_target(section_name) {
                continue;
            }
            // if name.is_empty() { name = format!("{}@{}", &dynstrtab[sym.st_name()], section_name)}
            if current_section != section_index {
                current_section = section_index;
                println!("Disassembly of section {}\n", section_name);
                match section_name {
                    // TODO: this is now a _broken_ hack for printing PLT entries (it doesn't print them,
                    // because there are no longer any symbols with the plt section to set off this logic)
                    &".plt" | &".plt.got" => {
                        let start = section.sh_offset();
                        let vaddr = section.sh_addr();
                        let ssize = section.sh_entsize() as usize;
                        let size = section.sh_entsize();
                        let strtab = &self.dynstrtab;
                        let symbol = Symbol::new(&"PLT", start, vaddr, ssize);
                        self.print_instructions(&bytes, config, &capstone, symbol)?;
                        let mut offset = size;
                        for rela in &self.pltrela {
                            let start = start + offset;
                            let vaddr = vaddr + offset;
                            let symindex = rela.r_sym();
                            let sym = self.dynsyms.get(symindex);
                            let name = &strtab[sym.st_name()];
                            // println!("name: {} offset {:x} size: {} shname: {} shoffset: {:x} shaddr: {:x}", name, rela.r_offset(), size, section_name, section.sh_offset(), section.sh_addr());
                            let symbol = Symbol::new(&name, start, vaddr, ssize);
                            self.print_instructions(&bytes, config, &capstone, symbol)?;
                            offset += size;
                        }
                    }
                    _ => (),
                }
            }
            // we're not doing plt stuff, so regular disassembly
            let name = &strtab[sym.st_name()];
            if name.is_empty() {
                continue;
            }
            let mut size = sym.st_size() as usize;
            let offset = bias(&sym, &section);
            // we compute the size of unsized symbols on the fly. it sucks. because elf sucks.
            if size == 0 && !is_last {
                let next_sym = &elf_syms[i + 1];
                // println!("i: {} current {}, name{} next: {:?}", i, current_section, name, next_sym);
                if current_section == next_sym.st_shndx() {
                    let next_offset = bias(&next_sym, &section);
                    size = (next_offset - offset) as usize;
                } else {
                    size = section.sh_size() as usize;
                }
            }
            // println!("offset {:x} size: {} section: {}, sh_type: {}", offset, size, section_name, section_header::sht_to_str(section.sh_type()));
            let symbol = Symbol::new(name, offset, sym.st_value(), size);
            self.print_instructions(&bytes, config, &capstone, symbol)?;
            i += 1;
        }
        Ok(())
    }
}

fn get_crate_name() -> String {
    let mut toml_fd = File::open("Cargo.toml")
        .expect("No Cargo.toml file found in root directory...");
    let mut toml = String::new();
    let _ = toml_fd.read_to_string(&mut toml);
    let value: toml::Value = toml.parse().expect("Malformed Cargo.toml file");
    let package_name = value.lookup("package.name")
                            .expect("No package.name in Cargo.toml")
                            .as_str()
                            .unwrap()
                            .to_owned()
        // we only replace this if it's a library..., so this breaks on ourself :/
                            .replace("-", "_");
    package_name
}

fn get_target(crate_name: &str) -> Option<PathBuf> {
    let targets = [Path::new("target").join("debug").join(&crate_name),
                   Path::new("target").join("debug").join(&format!("lib{}.so", &crate_name)),
                   Path::new("target").join("debug").join(&format!("lib{}.rlib", &crate_name)),
                   Path::new("target").join("debug").join(&format!("lib{}.a", &crate_name))];
    for target in &targets {
        match File::open(&target) {
            Ok(_) => return Some(target.clone()),
            _ => (),
        }
    }
    None
}

fn run(fd: &mut File, config: &Config) -> Result<()> {
    // todo write a generic peek function in goblin you jerk
    let mut magic = [0u8; 16];
    let err = ErrorKind::InvalidInput;
    let metadata = fd.metadata()?;
    let mut buffer = Vec::new();
    fd.read_to_end(&mut buffer)?;
    let mut bytes = &mut Cursor::new(&buffer);
    bytes.read(&mut magic)?;
    bytes.seek(SeekFrom::Start(0))?;
    if &magic[0..goblin::archive::SIZEOF_MAGIC] == goblin::archive::MAGIC {
        let archive = goblin::archive::Archive::parse(bytes, metadata.len() as usize)?;
        let bytes = archive.extract(&format!("{}.0.o", &config.crate_name), bytes)?;
        let mut bytes = Cursor::new(&bytes);
        // ideally would pattern match (or just recurse) on the identifier here but we're only supporting elf
        let elf = goblin::elf::Elf::parse(&mut bytes)?;
        elf.analyze(&mut bytes, config)
    } else if &magic[0..4] == goblin::elf::header::ELFMAG {
        let elf = goblin::elf::Elf::parse(bytes)?;
        elf.analyze(bytes, config)
    } else {
        Err(Error::from(io::Error::new(err,
                                       format!("No binary backend available for target: {:?}",
                                               &fd))))
    }
}

fn main() {

    let matches = App::new("cargo-sym")
        .version("0.0.3")
        .bin_name("cargo")
        .settings(&[AppSettings::GlobalVersion, AppSettings::SubcommandRequired])
        .subcommand(SubCommand::with_name("sym")
            .author("m4b <m4b.github.io@gmail.com>")
            .about("Prints the debugging symbols in your binary; more fancy stuff to come later")
            .args(&[Arg::with_name("binary")
                        .help("The binary file to read ")
                        .required(false)
                        .index(1),
                    Arg::with_name("disassemble")
                        .short("-d")
                        .long("disassemble")
                        .value_name("DISASSEMBLE")
                        .takes_value(false)
                        .help("Whether to disassaemble or not "),
                    Arg::with_name("demangle")
                        .short("-C")
                        .long("demangle")
                        .value_name("DEMANGLE")
                        .takes_value(false)
                        .help("Whether to demangle or not "),
                    Arg::with_name("dump")
                        .long("dump")
                        .value_name("DUMP")
                        .takes_value(false)
                        .help("Dump the debug representation of the binary"),
                    Arg::with_name("exports")
                        .short("-e")
                        .long("exports")
                        .value_name("EXPORTS")
                        .takes_value(false)
                        .help("Print the exported symbols that are importable by other \
                               binaries")]))
        .get_matches();

    let crate_name = get_crate_name();
    let matches = matches.subcommand_matches("sym").unwrap();
    let demangle = matches.is_present("demangle");
    let exports = matches.is_present("exports");
    let disassemble = matches.is_present("disassemble");
    let dump = matches.is_present("dump");
    let config = Config {
        demangle: demangle,
        exports: exports,
        crate_name: crate_name.to_string(),
        disassemble: disassemble,
        dump: dump,
    };
    let mut fd = match matches.value_of("binary") {
            Some(binary) => File::open(Path::new(binary)),
            _ => File::open(get_target(&crate_name).expect("No valid binary found")),
        }
        .expect("Cannot open file");

    run(&mut fd, &config).expect(&format!("Cannot read symbols from: {:?}", &fd));
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

mod wiz;
mod constants;

use clap::{App, Arg};

arg_enum! {
    #[derive(Debug)]
    enum Method {
        Install,
        Remove
    }
}

fn main() {

/*
 * TODO: Eliminate hardcoded strings, instead
 * putting them in constants.rs or other places.
 */

    let arg_matches = App::new(NAME)
        .version(VERSION)

        .arg(Arg::with_name("method")
             .help("Specify what to do with the specified package")
             .index(1)
             .possible_values(&Method::variants())
             .required(true))

        .arg(Arg::with_name("package")
             .help("Specify package")
             .index(2)
             .required(true))

        .get_matches();

    let method = value_t!(arg_matches.value_of("method"), Method).unwrap();
    let package = arg_matches.value_of("package").unwrap_or("invalid");

    match method {
        Method::Install => println!("install: {}", package),
        Method::Remove => println!("remove: {}", package)
    }
}
<commit_msg>Fixing typos<commit_after>#[macro_use]
extern crate clap;

mod wiz;
mod constants;

use clap::{App, Arg};

arg_enum! {
    #[derive(Debug)]
    enum Method {
        Install,
        Remove
    }
}

fn main() {

/*
 * TODO: Eliminate hardcoded strings, instead
 * putting them in constants.rs or other places.
 */

    let arg_matches = App::new(constants::NAME)
        .version(constants::VERSION)

        .arg(Arg::with_name("method")
             .help("Specify what to do with the specified package")
             .index(1)
             .possible_values(&Method::variants())
             .required(true))

        .arg(Arg::with_name("package")
             .help("Specify package")
             .index(2)
             .required(true))

        .get_matches();

    let method = value_t!(arg_matches.value_of("method"), Method).unwrap();
    let package = arg_matches.value_of("package").unwrap_or("invalid");

    match method {
        Method::Install => println!("install: {}", package),
        Method::Remove => println!("remove: {}", package)
    }
}
<|endoftext|>


<commit_before>#![allow(unused_parens)]
extern crate mpv ;
extern crate sdl2;
extern crate sdl2_ttf;
extern crate sdl2_image;
extern crate sdl2_sys;
#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate clap;
use clap::{Arg, App};

mod utils;
mod display;
mod init;
mod subtitles;
mod toyunda_player;

use toyunda_player::ToyundaPlayer;
use std::os::raw::c_void;

fn main() {
    // init the logger
    env_logger::init().unwrap();

    let matches = App::new("Toyunda Player RS")
                          .version(crate_version!())
                          .author("Cobrand")
                          .about("Flexible karaoke player")
                          .arg(Arg::with_name("mode")
                            .value_name("MODE")
                            .long("mode")
                            .help("Default is 'normal', can be 'karaoke','edit or 'normal'"))
                          .arg(Arg::with_name("fullscreen")
                            .short("f")
                            .long("fullscreen")
                            .help("Enables fullscreen"))
                          .arg(Arg::with_name("volume")
                            .short("v")
                            .long("volume")
                            .takes_value(true)
                            .help("Initial volume of the player; Default is 100"))
                          .arg(Arg::with_name("quit")
                            .short("q")
                            .long("quit")
                            .help("Forces quiting the player once the waiting queue is finished"))
                          .arg(Arg::with_name("no-quit")
                            .long("no-quit")
                            .conflicts_with("quit")
                            .help("Forces keeping alive the player once the waiting queue is finished"))
                          .arg(Arg::with_name("VIDEO_FILE")
                            .help("Sets the video file(s) to play")
                            .multiple(true)
                            .required(true))
                          .get_matches();

    // INIT SDL
    let sdl_context = sdl2::init().unwrap();
    let mut video_subsystem = sdl_context.video().unwrap();
    let renderer = init::init_sdl(&mut video_subsystem,&matches);
    let video_subsystem_ptr = &mut video_subsystem as *mut _ as *mut c_void;
    // INIT MPV
    let mut mpv_builder = mpv::MpvHandlerBuilder::new().expect("Error while creating MPV builder");
    mpv_builder.set_option("sid", "no").unwrap(); // disables subtitles if any
    mpv_builder.set_option("softvol", "yes").unwrap(); // enables softvol so it can go higher than 100%
    mpv_builder.set_option("softvol-max", 250.0).unwrap(); // makes the max volume at 250%
    mpv_builder.try_hardware_decoding().unwrap(); // try hardware decoding instead of software decoding
    let mpv = mpv_builder.build_with_gl(Some(init::get_proc_address), video_subsystem_ptr)
       .expect("Error while initializing MPV");
    // BIND MPV WITH SDL

    let displayer = display::Displayer::new(renderer)
                        .expect("Failed to init displayer");
    // Create a new displayer for the toyunda_player

    let mut toyunda_player = ToyundaPlayer::new(mpv, displayer);
    match toyunda_player.start(matches) {
        Err(e) => {
            error!("Failed to start player with given arguments, expect default parameters !\n\
                    '{}' ({:?})",e,e);
        }
        Ok(_) => {
            info!("Parsed arguments successfully");
        }
    };
    let res = toyunda_player.main_loop(&sdl_context);
    match res {
        Ok(_) => {
            info!("Toyunda Player finished gracefully");
        },
        Err(e) => {
            error!("An uncoverable error occured : {}",e);
        }
    };
}
<commit_msg>Added some after help about shortcuts<commit_after>#![allow(unused_parens)]
extern crate mpv ;
extern crate sdl2;
extern crate sdl2_ttf;
extern crate sdl2_image;
extern crate sdl2_sys;
#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate clap;
use clap::{Arg, App};

mod utils;
mod display;
mod init;
mod subtitles;
mod toyunda_player;

use toyunda_player::ToyundaPlayer;
use std::os::raw::c_void;

fn main() {
    // init the logger
    env_logger::init().unwrap();

    let matches = App::new("Toyunda Player")
                          .version(crate_version!())
                          .after_help("PLAYER SHORTCUTS :\n    \
                            * V : Hides / Shows subtitles\n    \
                            * F : Toggles fullscreen\n    \
                            * + / - : Raises / Lowers the volume\n    \
                            * Left / Right arrow : Seek backwards / frontwards\n    \
                            ")
                          .author("Cobrand")
                          .about("A flexible karaoke player for the epitanime association")
                          .arg(Arg::with_name("mode")
                            .value_name("MODE")
                            .long("mode")
                            .help("Default is 'normal', can be 'karaoke','edit or 'normal'"))
                          .arg(Arg::with_name("fullscreen")
                            .short("f")
                            .long("fullscreen")
                            .help("Enables fullscreen"))
                          .arg(Arg::with_name("volume")
                            .short("v")
                            .long("volume")
                            .takes_value(true)
                            .help("Initial volume of the player; Default is 100"))
                          .arg(Arg::with_name("quit")
                            .short("q")
                            .long("quit")
                            .help("Forces quiting the player once the waiting queue is finished"))
                          .arg(Arg::with_name("no-quit")
                            .long("no-quit")
                            .conflicts_with("quit")
                            .help("Forces keeping alive the player once the waiting queue is finished"))
                          .arg(Arg::with_name("VIDEO_FILE")
                            .help("Sets the video file(s) to play")
                            .multiple(true)
                            .required(true))
                          .get_matches();

    // INIT SDL
    let sdl_context = sdl2::init().unwrap();
    let mut video_subsystem = sdl_context.video().unwrap();
    let renderer = init::init_sdl(&mut video_subsystem,&matches);
    let video_subsystem_ptr = &mut video_subsystem as *mut _ as *mut c_void;
    // INIT MPV
    let mut mpv_builder = mpv::MpvHandlerBuilder::new().expect("Error while creating MPV builder");
    mpv_builder.set_option("sid", "no").unwrap(); // disables subtitles if any
    mpv_builder.set_option("softvol", "yes").unwrap(); // enables softvol so it can go higher than 100%
    mpv_builder.set_option("softvol-max", 250.0).unwrap(); // makes the max volume at 250%
    mpv_builder.try_hardware_decoding().unwrap(); // try hardware decoding instead of software decoding
    let mpv = mpv_builder.build_with_gl(Some(init::get_proc_address), video_subsystem_ptr)
       .expect("Error while initializing MPV");
    // BIND MPV WITH SDL

    let displayer = display::Displayer::new(renderer)
                        .expect("Failed to init displayer");
    // Create a new displayer for the toyunda_player

    let mut toyunda_player = ToyundaPlayer::new(mpv, displayer);
    match toyunda_player.start(matches) {
        Err(e) => {
            error!("Failed to start player with given arguments, expect default parameters !\n\
                    '{}' ({:?})",e,e);
        }
        Ok(_) => {
            info!("Parsed arguments successfully");
        }
    };
    let res = toyunda_player.main_loop(&sdl_context);
    match res {
        Ok(_) => {
            info!("Toyunda Player finished gracefully");
        },
        Err(e) => {
            error!("An uncoverable error occured : {}",e);
        }
    };
}
<|endoftext|>


<commit_before>use std::char;
use std::collections::BTreeSet;
use std::io;
use std::process;

const NSQRT: usize = 3;
const N: usize = NSQRT * NSQRT;
const NSQ: usize = N*N;

fn error(msg: String) -> ! {
    println!("error: {}", msg);
    process::exit(1);
}

/// Return the 0-based row index of `cell`.
fn row(cell: usize) -> usize {
    cell / N
}

/// Return the 0-based row index of `cell`.
fn col(cell: usize) -> usize {
    cell % N
}

/// Return the 0-based index of the upper-left cell of `cell`'s group.
fn group(cell: usize) -> usize {
    let r = row(cell);
    let c = col(cell);
    (N * (r - r % NSQRT)) + (c - c % NSQRT)
}

/// Return the neighbors of `cell`:
/// - The cells on the same row;
/// - The cells on the same column;
/// - The same in the same group.
/// Note: `cell` is not a neighbor of itself.
fn neighbors(cell: usize) -> BTreeSet<usize> {
    let mut all_neighbors: BTreeSet<usize> = BTreeSet::new();

    // Neighbors on row
    for col in 0..N {
        all_neighbors.insert((N * row(cell)) + col);
    }

    // Neighbors on column
    for row in 0..N {
        all_neighbors.insert((N * row) + col(cell));
    }

    // Neighbors in group
    let leader = group(cell);
    for r in row(leader) .. row(leader) + NSQRT {
        for c in col(leader) .. col(leader) + NSQRT {
            all_neighbors.insert(N * r + c);
        }
    }

    all_neighbors.remove(&cell);
    return all_neighbors;
}

/// A sudoku board is represented by a vector of bytes.
#[derive(Debug)]
struct SudokuBoard(Vec<BTreeSet<usize>>);

impl SudokuBoard {
    /// Create a new sudoku board from a string.
    /// A non-zero digit stands for itself,
    /// a dot stands for a blank cell,
    /// anything else is an error.
    fn from_str(digits: &str) -> Self {
        if digits.len() != NSQ {
            error(format!("invalid puzzle length; expected {}, got {}",
                          NSQ, digits.len()));
        }
        let mut v = Vec::with_capacity(NSQ);
        for d in digits.chars() {
            match d {
                '.' => {
                    let candidates: BTreeSet<usize> = (1 .. N+1).collect();
                    v.push(candidates);
                }
                '1' ... '9' => {
                    let mut singleton = BTreeSet::new();
                    singleton.insert(d.to_digit(10).unwrap() as usize);
                    v.push(singleton);
                }
                _ => { error(format!("invalid digit ({:?}) in string", d)); }
            }
        }
        SudokuBoard(v)
    }

    fn cell_solved(&self, cell: usize) -> bool {
        self.0[cell].len() == 1
    }

    fn cell_solvable(&self, cell: usize) -> bool {
        self.0[cell].len() != 0
    }

    fn solved(&self) -> bool {
        (0 .. NSQ).all(|cell| self.cell_solved(cell))
    }

    fn solvable(&self) -> bool {
        (0 .. NSQ).all(|cell| self.cell_solvable(cell))
    }

    fn non_candidates(&self, cell: usize) -> BTreeSet<usize> {
        let mut set: BTreeSet<usize> = BTreeSet::new();
        for n in neighbors(cell) {
            if self.cell_solved(n) {
                for x in self.0[n].iter() {
                    set.insert(*x);
                }
            }
        }
        set
    }

    fn propagate(&self) -> Self {
        let mut output = SudokuBoard(self.0.clone());
        loop {
            let mut candidates_changed = false;
            for i in 0 .. NSQ {
                for nc in output.non_candidates(i) {
                    let q = output.0[i].remove(&nc);
                    candidates_changed = q || candidates_changed;
                }
            }
            if !candidates_changed {
                break;
            }
        }
        return output;
    }

    fn solve(&self, cell: usize) -> Option<Self> {
        if cell >= NSQ {
            return Some(SudokuBoard(self.0.clone()));
        }

        if self.cell_solved(cell) {
            return self.solve(cell + 1);
        }

        let mut newboard = self.propagate();

        if newboard.solved() {
            return Some(newboard);
        }

        if !newboard.solvable() {
            return None;
        }

        let cell_candidates = newboard.0[cell].clone();
        for c in cell_candidates.iter() {
            newboard.0[cell].clear();
            newboard.0[cell].insert(*c);
            match newboard.solve(cell + 1) {
                Some(solved_board) => { return Some(solved_board); }
                None => { }
            }
        }

        return None;
    }

    fn debug(&self) {
        for i in 0 .. NSQ {
            println!("[{:?}]", self.0[i]);
        }
    }
}

fn main() {
    let stdin = io::stdin();
    let mut buf = String::with_capacity(NSQ);

    loop {
        buf.clear();
        match stdin.read_line(&mut buf) {
            Err(e) => { error(format!("I/O error, {:?}", e)); }
            Ok(0) => { return; }
            Ok(_) => { /* pass through */ }
        }
        let sb = SudokuBoard::from_str(&buf.trim());
        match sb.solve(0) {
            Some(_) => { println!("OK"); }
            None => { println!("No solution"); }
        }
    }
}

/*
#[test]
fn test_row_col() {
    assert_eq!(row(11), 1);
    assert_eq!(col(11), 2);
}

#[test]
fn test_group() {
    assert_eq!(group(0), 0);
    assert_eq!(group(1), 0);
    assert_eq!(group(2), 0);
    assert_eq!(group(9), 0);
    assert_eq!(group(10), 0);
    assert_eq!(group(11), 0);
    assert_eq!(group(18), 0);
    assert_eq!(group(19), 0);
    assert_eq!(group(20), 0);
    assert_eq!(group(60), 60);
    assert_eq!(group(61), 60);
    assert_eq!(group(62), 60);
    assert_eq!(group(69), 60);
    assert_eq!(group(70), 60);
    assert_eq!(group(71), 60);
    assert_eq!(group(78), 60);
    assert_eq!(group(79), 60);
    assert_eq!(group(80), 60);
}

#[test]
fn test_is_solved() {
    let sb = SudokuBoard(vec![0, 1]);
    assert!(!sb.is_solved(0));
    assert!(sb.is_solved(1));
}

#[test]
fn test_neighbors() {
    assert!(!neighbors(0).contains(&0));
    // Neighbors of 0 on the same row
    assert!(neighbors(0).contains(&1));
    assert!(neighbors(0).contains(&2));
    assert!(neighbors(0).contains(&3));
    assert!(neighbors(0).contains(&4));
    assert!(neighbors(0).contains(&5));
    assert!(neighbors(0).contains(&6));
    assert!(neighbors(0).contains(&7));
    assert!(neighbors(0).contains(&8));
    // Neighbors of 0 on the same col
    assert!(neighbors(0).contains(&9));
    assert!(neighbors(0).contains(&18));
    assert!(neighbors(0).contains(&27));
    assert!(neighbors(0).contains(&36));
    assert!(neighbors(0).contains(&45));
    assert!(neighbors(0).contains(&54));
    assert!(neighbors(0).contains(&63));
    assert!(neighbors(0).contains(&72));
    // Neighbors of 0 in the same group
    assert!(neighbors(0).contains(&1));
    assert!(neighbors(0).contains(&2));
    assert!(neighbors(0).contains(&9));
    assert!(neighbors(0).contains(&10));
    assert!(neighbors(0).contains(&11));
    assert!(neighbors(0).contains(&18));
    assert!(neighbors(0).contains(&19));
    assert!(neighbors(0).contains(&20));
}

#[test]
fn test_candidates() {
    let sb = SudokuBoard::from_str(".2......34..........6...................................................5........");
    assert!(!sb.candidates(0).contains(&2));
    assert!(!sb.candidates(0).contains(&3));
    assert!(!sb.candidates(0).contains(&4));
    assert!(!sb.candidates(0).contains(&5));
    assert!(!sb.candidates(0).contains(&6));
    assert!(sb.candidates(0).contains(&1));
    assert!(sb.candidates(0).contains(&7));
    assert!(sb.candidates(0).contains(&8));
    assert!(sb.candidates(0).contains(&9));
}
*/
<commit_msg>Print solution to stdout<commit_after>use std::collections::BTreeSet;
use std::io;
use std::process;

const NSQRT: usize = 3;
const N: usize = NSQRT * NSQRT;
const NSQ: usize = N*N;

fn error(msg: String) -> ! {
    println!("error: {}", msg);
    process::exit(1);
}

/// Return the 0-based row index of `cell`.
fn row(cell: usize) -> usize {
    cell / N
}

/// Return the 0-based row index of `cell`.
fn col(cell: usize) -> usize {
    cell % N
}

/// Return the 0-based index of the upper-left cell of `cell`'s group.
fn group(cell: usize) -> usize {
    let r = row(cell);
    let c = col(cell);
    (N * (r - r % NSQRT)) + (c - c % NSQRT)
}

/// Return the neighbors of `cell`:
/// - The cells on the same row;
/// - The cells on the same column;
/// - The same in the same group.
/// Note: `cell` is not a neighbor of itself.
fn neighbors(cell: usize) -> BTreeSet<usize> {
    let mut all_neighbors: BTreeSet<usize> = BTreeSet::new();

    // Neighbors on row
    for col in 0..N {
        all_neighbors.insert((N * row(cell)) + col);
    }

    // Neighbors on column
    for row in 0..N {
        all_neighbors.insert((N * row) + col(cell));
    }

    // Neighbors in group
    let leader = group(cell);
    for r in row(leader) .. row(leader) + NSQRT {
        for c in col(leader) .. col(leader) + NSQRT {
            all_neighbors.insert(N * r + c);
        }
    }

    all_neighbors.remove(&cell);
    return all_neighbors;
}

/// A sudoku board is represented by a vector of bytes.
#[derive(Debug)]
struct SudokuBoard(Vec<BTreeSet<usize>>);

impl SudokuBoard {
    /// Create a new sudoku board from a string.
    /// A non-zero digit stands for itself,
    /// a dot stands for a blank cell,
    /// anything else is an error.
    fn from_str(digits: &str) -> Self {
        if digits.len() != NSQ {
            error(format!("invalid puzzle length; expected {}, got {}",
                          NSQ, digits.len()));
        }
        let mut v = Vec::with_capacity(NSQ);
        for d in digits.chars() {
            match d {
                '.' => {
                    let candidates: BTreeSet<usize> = (1 .. N+1).collect();
                    v.push(candidates);
                }
                '1' ... '9' => {
                    let mut singleton = BTreeSet::new();
                    singleton.insert(d.to_digit(10).unwrap() as usize);
                    v.push(singleton);
                }
                _ => { error(format!("invalid digit ({:?}) in string", d)); }
            }
        }
        SudokuBoard(v)
    }

    fn cell_solved(&self, cell: usize) -> bool {
        self.0[cell].len() == 1
    }

    fn cell_solvable(&self, cell: usize) -> bool {
        self.0[cell].len() != 0
    }

    fn solved(&self) -> bool {
        (0 .. NSQ).all(|cell| self.cell_solved(cell))
    }

    fn solvable(&self) -> bool {
        (0 .. NSQ).all(|cell| self.cell_solvable(cell))
    }

    fn non_candidates(&self, cell: usize) -> BTreeSet<usize> {
        let mut set: BTreeSet<usize> = BTreeSet::new();
        for n in neighbors(cell) {
            if self.cell_solved(n) {
                for x in self.0[n].iter() {
                    set.insert(*x);
                }
            }
        }
        set
    }

    fn propagate(&self) -> Self {
        let mut output = SudokuBoard(self.0.clone());
        loop {
            let mut candidates_changed = false;
            for i in 0 .. NSQ {
                for nc in output.non_candidates(i) {
                    let q = output.0[i].remove(&nc);
                    candidates_changed = q || candidates_changed;
                }
            }
            if !candidates_changed {
                break;
            }
        }
        return output;
    }

    fn solve(&self, cell: usize) -> Option<Self> {
        if cell >= NSQ {
            return Some(SudokuBoard(self.0.clone()));
        }

        if self.cell_solved(cell) {
            return self.solve(cell + 1);
        }

        let mut newboard = self.propagate();

        if newboard.solved() {
            return Some(newboard);
        }

        if !newboard.solvable() {
            return None;
        }

        let cell_candidates = newboard.0[cell].clone();
        for c in cell_candidates.iter() {
            newboard.0[cell].clear();
            newboard.0[cell].insert(*c);
            match newboard.solve(cell + 1) {
                Some(solved_board) => { return Some(solved_board); }
                None => { }
            }
        }

        return None;
    }

    fn to_str(&self) -> String {
        let mut output = String::with_capacity(NSQ);
        for i in 0 .. NSQ {
            if self.cell_solved(i) {
                for c in self.0[i].iter() {
                    output.push_str(&format!("{}", c));
                }
            } else {
                output.push('.');
            }
        }
        output
    }
}

fn main() {
    let stdin = io::stdin();
    let mut buf = String::with_capacity(NSQ);

    loop {
        buf.clear();
        match stdin.read_line(&mut buf) {
            Err(e) => { error(format!("I/O error, {:?}", e)); }
            Ok(0) => { return; }
            Ok(_) => { /* pass through */ }
        }
        let sb = SudokuBoard::from_str(&buf.trim());
        match sb.solve(0) {
            Some(solution) => { println!("{}", solution.to_str()); }
            None => { println!("No solution"); }
        }
    }
}

#[test]
fn test_row_col() {
    assert_eq!(row(11), 1);
    assert_eq!(col(11), 2);
}

#[test]
fn test_group() {
    assert_eq!(group(0), 0);
    assert_eq!(group(1), 0);
    assert_eq!(group(2), 0);
    assert_eq!(group(9), 0);
    assert_eq!(group(10), 0);
    assert_eq!(group(11), 0);
    assert_eq!(group(18), 0);
    assert_eq!(group(19), 0);
    assert_eq!(group(20), 0);
    assert_eq!(group(60), 60);
    assert_eq!(group(61), 60);
    assert_eq!(group(62), 60);
    assert_eq!(group(69), 60);
    assert_eq!(group(70), 60);
    assert_eq!(group(71), 60);
    assert_eq!(group(78), 60);
    assert_eq!(group(79), 60);
    assert_eq!(group(80), 60);
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::fs;
use std::io;
use std::path::Path;

use handlebars::{no_escape, Handlebars};

const SITE_TITLE: &str = "Grauwoelfchen's Workroom";
const DST_DIR: &str = "./dst";

const LINKS: [Link; 4] = [
    Link {
        title: "Home",
        href: "/",
    },
    Link {
        title: "About",
        href: "/about.html",
    },
    Link {
        title: "Software",
        href: "/software.html",
    },
    Link {
        title: "Link",
        href: "/link.html",
    },
];

#[derive(Debug)]
enum Error {
    Io(io::Error),
    Parse(handlebars::TemplateError),
    Render(handlebars::RenderError),
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Self {
        Self::Io(error)
    }
}

impl From<handlebars::TemplateError> for Error {
    fn from(error: handlebars::TemplateError) -> Self {
        Self::Parse(error)
    }
}

impl From<handlebars::RenderError> for Error {
    fn from(error: handlebars::RenderError) -> Self {
        Self::Render(error)
    }
}

struct Link {
    pub title: &'static str,
    pub href: &'static str,
}

fn main() -> Result<(), Error> {
    let mut reg = Handlebars::new();

    let layout = include_str!("./layout.hbs");
    reg.register_template_string("layout", layout)?;
    reg.register_escape_fn(no_escape);

    let dst = Path::new(&DST_DIR);

    // error
    let dat = include_str!("./error.hbs");
    fs::write(dst.join("error.html"), &dat.as_bytes())?;

    // index
    let data = load("Home", include_str!("./index.hbs"));
    let result = reg.render("layout", &data)?;
    fs::write(dst.join("index.html"), result)?;

    // about
    let data = load("About", include_str!("./about.hbs"));
    let result = reg.render("layout", &data).unwrap();
    fs::write(dst.join("about.html"), result)?;

    // software
    let data = load("Software", include_str!("./software.hbs"));
    let result = reg.render("layout", &data).unwrap();
    fs::write(dst.join("software.html"), result)?;

    // link
    let data = load("Link", include_str!("./link.hbs"));
    let result = reg.render("layout", &data).unwrap();
    fs::write(dst.join("link.html"), result)?;

    reg.unregister_escape_fn();

    Ok(())
}

/// Returns built an entry for navigations list.
fn build_nav(heading: &str, link: &Link) -> String {
    let class = if link.title == heading {
        " class=\"active\""
    } else {
        ""
    };
    format!(
        r#"

  {}

"#,
        class, link.href, link.title,
    )
}

fn load(heading: &str, content: &str) -> BTreeMap<String, String> {
    let mut data = BTreeMap::new();

    let mut nav = "".to_string();
    for link in LINKS {
        nav.push_str(&build_nav(heading, &link));
    }
    data.insert("navi".to_string(), nav);
    data.insert("content".to_string(), content.to_string());

    // meta
    if heading != "Home" {
        data.insert("page_title".to_string(), heading.to_string());
    }
    data.insert("site_title".to_string(), SITE_TITLE.to_string());
    data
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_build_nav() {
        let link = Link {
            title: "Foo",
            href: "/foo.html",
        };
        let nav = build_nav("Foo", &link);
        assert_eq!(
            nav,
            r#"

  Foo

"#
        );

        let link = Link {
            title: "Bar",
            href: "/foo.html",
        };
        let nav = build_nav("Bar", &link);
        assert_eq!(
            nav,
            r#"

  Foo

"#
        );
    }
}
<commit_msg>Add a comment for load function<commit_after>use std::collections::BTreeMap;
use std::fs;
use std::io;
use std::path::Path;

use handlebars::{no_escape, Handlebars};

const SITE_TITLE: &str = "Grauwoelfchen's Workroom";
const DST_DIR: &str = "./dst";

const LINKS: [Link; 4] = [
    Link {
        title: "Home",
        href: "/",
    },
    Link {
        title: "About",
        href: "/about.html",
    },
    Link {
        title: "Software",
        href: "/software.html",
    },
    Link {
        title: "Link",
        href: "/link.html",
    },
];

#[derive(Debug)]
enum Error {
    Io(io::Error),
    Parse(handlebars::TemplateError),
    Render(handlebars::RenderError),
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Self {
        Self::Io(error)
    }
}

impl From<handlebars::TemplateError> for Error {
    fn from(error: handlebars::TemplateError) -> Self {
        Self::Parse(error)
    }
}

impl From<handlebars::RenderError> for Error {
    fn from(error: handlebars::RenderError) -> Self {
        Self::Render(error)
    }
}

struct Link {
    pub title: &'static str,
    pub href: &'static str,
}

fn main() -> Result<(), Error> {
    let mut reg = Handlebars::new();

    let layout = include_str!("./layout.hbs");
    reg.register_template_string("layout", layout)?;
    reg.register_escape_fn(no_escape);

    let dst = Path::new(&DST_DIR);

    // error
    let dat = include_str!("./error.hbs");
    fs::write(dst.join("error.html"), &dat.as_bytes())?;

    // index
    let data = load("Home", include_str!("./index.hbs"));
    let result = reg.render("layout", &data)?;
    fs::write(dst.join("index.html"), result)?;

    // about
    let data = load("About", include_str!("./about.hbs"));
    let result = reg.render("layout", &data).unwrap();
    fs::write(dst.join("about.html"), result)?;

    // software
    let data = load("Software", include_str!("./software.hbs"));
    let result = reg.render("layout", &data).unwrap();
    fs::write(dst.join("software.html"), result)?;

    // link
    let data = load("Link", include_str!("./link.hbs"));
    let result = reg.render("layout", &data).unwrap();
    fs::write(dst.join("link.html"), result)?;

    reg.unregister_escape_fn();

    Ok(())
}

/// Returns built an entry for navigations list.
fn build_nav(heading: &str, link: &Link) -> String {
    let class = if link.title == heading {
        " class=\"active\""
    } else {
        ""
    };
    format!(
        r#"

  {}

"#,
        class, link.href, link.title,
    )
}

/// Loads the content as a BTreeMap object that has navi, content
/// {page,site}_title as attributes.
fn load(heading: &str, content: &str) -> BTreeMap<String, String> {
    let mut data = BTreeMap::new();

    let mut nav = "".to_string();
    for link in LINKS {
        nav.push_str(&build_nav(heading, &link));
    }
    data.insert("navi".to_string(), nav);
    data.insert("content".to_string(), content.to_string());

    // meta
    if heading != "Home" {
        data.insert("page_title".to_string(), heading.to_string());
    }
    data.insert("site_title".to_string(), SITE_TITLE.to_string());
    data
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_build_nav() {
        let link = Link {
            title: "Foo",
            href: "/foo.html",
        };
        let nav = build_nav("Foo", &link);
        assert_eq!(
            nav,
            r#"

  Foo

"#
        );

        let link = Link {
            title: "Bar",
            href: "/foo.html",
        };
        let nav = build_nav("Bar", &link);
        assert_eq!(
            nav,
            r#"

  Foo

"#
        );
    }
}
<|endoftext|>