<commit_before>use std::env;
use std::io;
use std::fs::File;
use std::io::prelude::*;

fn main() {
    if let Some(path) = env::args().nth(1) {
        let mut contents = String::new();
        match File::open(path) {
            Ok(mut file) => {
                match file.read_to_string(&mut contents) {
                    Ok(_) => {
                        match brainfuck::read(&contents) {
                            Ok(program) => {
                                let stdio = io::stdin();
                                let input = stdio.lock();
                                let output = io::stdout();
                                brainfuck::eval(program, input, output);
                            }
                            Err(msg) => println!("Read the file, but could not parse it: {}", msg),
                        }
                    }
                    Err(_) => println!("Found the file but failed to read it."),
                }
            }
            Err(_) => println!("Failed to open the file for reading."),
        };
    } else {
        println!("Please provide a path to some brainfuck source as the first argument.")
    }
}

mod brainfuck {
    use std::io::{Read, Write}
;

    #[derive(PartialEq)]
    #[derive(Debug)]
    pub enum Command {
        IncrementPointer,
        DecrementPointer,
        IncrementValue,
        DecrementValue,
        OutputValue,
        InputValue,
        ForwardsTo(usize),
        BackwardsTo(usize),
    }

    pub fn read(source: &str) -> Result<Vec<Command>, &'static str> {
        let mut forward_pointers: Vec<usize> = vec![];
        let mut backward_pointers: Vec<usize> = vec![];
        let mut position: usize = 0;
        let mut program: Vec<Command> = source
            .chars()
            .filter_map(|token| {
                let command = match token {
                    '>' => Some(Command::IncrementPointer),
                    '<' => Some(Command::DecrementPointer),
                    '+' => Some(Command::IncrementValue),
                    '-' => Some(Command::DecrementValue),
                    '.' => Some(Command::OutputValue),
                    ',' => Some(Command::InputValue),
                    '[' => {
                        forward_pointers.push(position);
                        Some(Command::BackwardsTo(position))
                    }
                    ']' => {
                        backward_pointers.push(position);
                        Some(Command::ForwardsTo(position))
                    }
                    _ => None,
                };

                if command.is_some() {
                    position += 1
                }

                command
            })
            .collect();

        if forward_pointers.len() == backward_pointers.len() {
            for (a, b) in forward_pointers.iter().rev().zip(backward_pointers) {
                program.swap(*a, b)
            }

            Ok(program)
        } else {
            Err("Found an unmatched square brace.")
        }
    }

    fn write_byte<W>(mut writer: W, byte: i32)
        where W: Write
    {
        write!(&mut writer, "{}", byte as u8 as char).expect("Unable to write");
    }

    fn read_byte<R>(reader: R) -> i32
        where R: Read
    {
        reader
            .bytes()
            .next()
            .and_then(|result| result.ok())
            .map(|byte| byte as i32)
            .unwrap_or(0)
    }

    pub fn eval<R, W>(program: Vec<Command>, mut reader: R, mut writer: W)
        where R: Read,
              W: Write
    {
        let mut memory: Vec<i32> = vec![0; 30000];
        let mut mem_pointer: usize = 0;
        let mut prog_pointer: usize = 0;
        let prog_len = program.len();

        while prog_pointer < prog_len {
            match program[prog_pointer] {
                Command::IncrementPointer => {
                    mem_pointer += 1;
                }
                Command::DecrementPointer => {
                    mem_pointer -= 1;
                }
                Command::IncrementValue => {
                    memory[mem_pointer] += 1;
                }
                Command::DecrementValue => {
                    memory[mem_pointer] -= 1;
                }
                Command::OutputValue => {
                    write_byte(&mut writer, memory[mem_pointer]);
                }
                Command::InputValue => {
                    memory[mem_pointer] = read_byte(&mut reader);
                }
                Command::ForwardsTo(next) => {
                    if memory[mem_pointer] == 0 {
                        prog_pointer = next;
                    }
                }
                Command::BackwardsTo(next) => {
                    if memory[mem_pointer] != 0 {
                        prog_pointer = next;
                    }
                }
            };

            prog_pointer += 1;
        }
    }
}

#[cfg(test)]
mod tests {
    use brainfuck::*;
    use brainfuck::Command::*;
    use std::io::Cursor;

    #[test]
    fn read_empty() {
        let source = "";
        let expected: Vec<Command> = vec![];

        match read(source) {
            Ok(actual) => assert_eq!(expected, actual),
            Err(_) => assert!(false),
        };
    }

    #[test]
    fn read_simple() {
        let source = "+>-<.,<.-+>,";
        let expected = vec![IncrementValue,
                            IncrementPointer,
                            DecrementValue,
                            DecrementPointer,
                            OutputValue,
                            InputValue,
                            DecrementPointer,
                            OutputValue,
                            DecrementValue,
                            IncrementValue,
                            IncrementPointer,
                            InputValue];

        match read(source) {
            Ok(actual) => assert_eq!(expected, actual),
            Err(_) => assert!(false),
        };
    }

    #[test]
    fn read_garbage() {
        let source = ",.+lol,hey.>there<";
        let expected = vec![InputValue,
                            OutputValue,
                            IncrementValue,
                            InputValue,
                            OutputValue,
                            IncrementPointer,
                            DecrementPointer];

        match read(source) {
            Ok(actual) => assert_eq!(expected, actual),
            Err(_) => assert!(false),
        };
    }

    #[test]
    fn read_loop() {
        let source = "[->+<]";
        let expected = vec![ForwardsTo(5),
                            DecrementValue,
                            IncrementPointer,
                            IncrementValue,
                            DecrementPointer,
                            BackwardsTo(0)];

        match read(source) {
            Ok(actual) => assert_eq!(expected, actual),
            Err(_) => assert!(false),
        };
    }

    #[test]
    fn read_bad_loop() {
        let source = "[,.[,.>+-][./.[]]";
        let expected = "Found an unmatched square brace.";

        match read(source) {
            Ok(_) => assert!(false),
            Err(actual) => assert_eq!(expected, actual),
        };
    }

    #[test]
    fn read_nested_loops() {
        let source = "[[]]";
        let expected = vec![ForwardsTo(3),
                            ForwardsTo(2),
                            BackwardsTo(1),
                            BackwardsTo(0)];

        match read(source) {
            Ok(actual) => assert_eq!(expected, actual),
            Err(_) => assert!(false),
        };
    }

    #[test]
    fn read_more_nested_loops() {
        let source = "[[[][]]]";
        let expected = vec![ForwardsTo(7),
                            ForwardsTo(6),
                            ForwardsTo(3),
                            BackwardsTo(2),
                            ForwardsTo(5),
                            BackwardsTo(4),
                            BackwardsTo(1),
                            BackwardsTo(0)];

        match read(source) {
            Ok(actual) => assert_eq!(expected, actual),
            Err(_) => assert!(false),
        };
    }

    #[test]
    fn eval_empty() {
        let input = Cursor::new(&b""[..]);
        let mut output = Cursor::new(vec![]);

        match read("") {
            Ok(program) => eval(program, input, &mut output),
            Err(_) => assert!(false),
        }

        let expected = "";
        let actual = String::from_utf8(output.into_inner()).expect("Not UTF-8");

        assert_eq!(expected, actual);
    }

    #[test]
    fn eval_new_line() {
        let input = Cursor::new(&b""[..]);
        let mut output = Cursor::new(vec![]);

        match read("++++++++++.") {
            Ok(program) => eval(program, input, &mut output),
            Err(_) => assert!(false),
        }

        let expected = "\n";
        let actual = String::from_utf8(output.into_inner()).expect("Not UTF-8");

        assert_eq!(expected, actual);
    }

    #[test]
    fn eval_cat() {
        let input = Cursor::new(&b"Hello, World!"[..]);
        let mut output = Cursor::new(vec![]);

        match read(",[.,]") {
            Ok(program) => eval(program, input, &mut output),
            Err(_) => assert!(false),
        }

        let expected = "Hello, World!";
        let actual = String::from_utf8(output.into_inner()).expect("Not UTF-8");

        assert_eq!(expected, actual);
    }

    // #[test]
    // fn eval_hello_world() {
    //     let input = Cursor::new(&b""[..]);
    //     let mut output = Cursor::new(vec![]);

    //     match read("--------[>+>+++++>-->-->--->++++>------<<<<<<<-------]>.>---.>----..>-.>++++.>.>+++++++.<<<.+++.<.<-.>>>>+.") {
    //         Ok(program) => eval(program, input, &mut output),
    //         Err(_) => assert!(false),
    //     }

    //     let expected = "Hello, World!";
    //     let actual = String::from_utf8(output.into_inner()).expect("Not UTF-8");

    //     assert_eq!(expected, actual);
    // }
}
<commit_msg>Fixed brace matching stack implementation<commit_after>use std::env;
use std::io;
use std::fs::File;
use std::io::prelude::*;

fn main() {
    if let Some(path) = env::args().nth(1) {
        let mut contents = String::new();
        match File::open(path) {
            Ok(mut file) => {
                match file.read_to_string(&mut contents) {
                    Ok(_) => {
                        match brainfuck::read(&contents) {
                            Ok(program) => {
                                let stdio = io::stdin();
                                let input = stdio.lock();
                                let output = io::stdout();
                                brainfuck::eval(program, input, output);
                            }
                            Err(msg) => println!("Read the file, but could not parse it: {}", msg),
                        }
                    }
                    Err(_) => println!("Found the file but failed to read it."),
                }
            }
            Err(_) => println!("Failed to open the file for reading."),
        };
    } else {
        println!("Please provide a path to some brainfuck source as the first argument.")
    }
}

mod brainfuck {
    use std::io::{Read, Write}
;

    #[derive(PartialEq)]
    #[derive(Debug)]
    pub enum Command {
        IncrementPointer,
        DecrementPointer,
        IncrementValue,
        DecrementValue,
        OutputValue,
        InputValue,
        ForwardsTo(usize),
        BackwardsTo(usize),
    }

    pub fn read(source: &str) -> Result<Vec<Command>, &'static str> {
        let mut jumps: Vec<usize> = vec![];
        let mut swaps: Vec<(usize, usize)> = vec![];
        let mut extra_close = false;
        let mut position: usize = 0;
        let mut program: Vec<Command> = source
            .chars()
            .filter_map(|token| {
                let command = match token {
                    '>' => Some(Command::IncrementPointer),
                    '<' => Some(Command::DecrementPointer),
                    '+' => Some(Command::IncrementValue),
                    '-' => Some(Command::DecrementValue),
                    '.' => Some(Command::OutputValue),
                    ',' => Some(Command::InputValue),
                    '[' => {
                        jumps.push(position);
                        Some(Command::BackwardsTo(position))
                    }
                    ']' => {
                        match jumps.pop() {
                            Some(jump) => {
                                swaps.push((jump, position));
                                Some(Command::ForwardsTo(position))
                            },
                            None => {
                                extra_close = true;
                                None
                            }
                        }
                    }
                    _ => None,
                };

                if command.is_some() {
                    position += 1
                }

                command
            })
            .collect();

        if jumps.len() > 0 {
            Err("Too many open braces")
        } else if extra_close {
            Err("Too many close braces")
        } else {
            for (a, b) in swaps {
                program.swap(a, b)
            }

            Ok(program)
        }
    }

    fn write_byte<W>(mut writer: W, byte: i32)
        where W: Write
    {
        write!(&mut writer, "{}", byte as u8 as char).expect("Unable to write");
    }

    fn read_byte<R>(reader: R) -> i32
        where R: Read
    {
        reader
            .bytes()
            .next()
            .and_then(|result| result.ok())
            .map(|byte| byte as i32)
            .unwrap_or(0)
    }

    pub fn eval<R, W>(program: Vec<Command>, mut reader: R, mut writer: W)
        where R: Read,
              W: Write
    {
        let mut memory: Vec<i32> = vec![0; 30000];
        let mut mem_pointer: usize = 0;
        let mut prog_pointer: usize = 0;
        let prog_len = program.len();

        while prog_pointer < prog_len {
            match program[prog_pointer] {
                Command::IncrementPointer => {
                    mem_pointer += 1;
                }
                Command::DecrementPointer => {
                    mem_pointer -= 1;
                }
                Command::IncrementValue => {
                    memory[mem_pointer] += 1;
                }
                Command::DecrementValue => {
                    memory[mem_pointer] -= 1;
                }
                Command::OutputValue => {
                    write_byte(&mut writer, memory[mem_pointer]);
                }
                Command::InputValue => {
                    memory[mem_pointer] = read_byte(&mut reader);
                }
                Command::ForwardsTo(next) => {
                    if memory[mem_pointer] == 0 {
                        prog_pointer = next;
                    }
                }
                Command::BackwardsTo(next) => {
                    if memory[mem_pointer] != 0 {
                        prog_pointer = next;
                    }
                }
            };

            prog_pointer += 1;
        }
    }
}

#[cfg(test)]
mod tests {
    use brainfuck::*;
    use brainfuck::Command::*;
    use std::io::Cursor;

    #[test]
    fn read_empty() {
        let source = "";
        let expected: Vec<Command> = vec![];

        match read(source) {
            Ok(actual) => assert_eq!(expected, actual),
            Err(_) => assert!(false),
        };
    }

    #[test]
    fn read_simple() {
        let source = "+>-<.,<.-+>,";
        let expected = vec![IncrementValue,
                            IncrementPointer,
                            DecrementValue,
                            DecrementPointer,
                            OutputValue,
                            InputValue,
                            DecrementPointer,
                            OutputValue,
                            DecrementValue,
                            IncrementValue,
                            IncrementPointer,
                            InputValue];

        match read(source) {
            Ok(actual) => assert_eq!(expected, actual),
            Err(_) => assert!(false),
        };
    }

    #[test]
    fn read_garbage() {
        let source = ",.+lol,hey.>there<";
        let expected = vec![InputValue,
                            OutputValue,
                            IncrementValue,
                            InputValue,
                            OutputValue,
                            IncrementPointer,
                            DecrementPointer];

        match read(source) {
            Ok(actual) => assert_eq!(expected, actual),
            Err(_) => assert!(false),
        };
    }

    #[test]
    fn read_loop() {
        let source = "[->+<]";
        let expected = vec![ForwardsTo(5),
                            DecrementValue,
                            IncrementPointer,
                            IncrementValue,
                            DecrementPointer,
                            BackwardsTo(0)];

        match read(source) {
            Ok(actual) => assert_eq!(expected, actual),
            Err(_) => assert!(false),
        };
    }

    #[test]
    fn read_too_many_opens() {
        let source = "[,.[,.>+-][./.[]]";
        let expected = "Too many open braces";

        match read(source) {
            Ok(_) => assert!(false),
            Err(actual) => assert_eq!(expected, actual),
        };
    }

    #[test]
    fn read_too_many_closes() {
        let source = "[,.[,.>+-][./.[]]]]]]";
        let expected = "Too many close braces";

        match read(source) {
            Ok(_) => assert!(false),
            Err(actual) => assert_eq!(expected, actual),
        };
    }

    #[test]
    fn read_nested_loops() {
        let source = "[[]]";
        let expected = vec![ForwardsTo(3),
                            ForwardsTo(2),
                            BackwardsTo(1),
                            BackwardsTo(0)];

        match read(source) {
            Ok(actual) => assert_eq!(expected, actual),
            Err(_) => assert!(false),
        };
    }

    #[test]
    fn read_more_nested_loops() {
        let source = "[[[][]]]";
        let expected = vec![ForwardsTo(7),
                            ForwardsTo(6),
                            ForwardsTo(3),
                            BackwardsTo(2),
                            ForwardsTo(5),
                            BackwardsTo(4),
                            BackwardsTo(1),
                            BackwardsTo(0)];

        match read(source) {
            Ok(actual) => assert_eq!(expected, actual),
            Err(_) => assert!(false),
        };
    }

    #[test]
    fn eval_empty() {
        let input = Cursor::new(&b""[..]);
        let mut output = Cursor::new(vec![]);

        match read("") {
            Ok(program) => eval(program, input, &mut output),
            Err(_) => assert!(false),
        }

        let expected = "";
        let actual = String::from_utf8(output.into_inner()).expect("Not UTF-8");

        assert_eq!(expected, actual);
    }

    #[test]
    fn eval_new_line() {
        let input = Cursor::new(&b""[..]);
        let mut output = Cursor::new(vec![]);

        match read("++++++++++.") {
            Ok(program) => eval(program, input, &mut output),
            Err(_) => assert!(false),
        }

        let expected = "\n";
        let actual = String::from_utf8(output.into_inner()).expect("Not UTF-8");

        assert_eq!(expected, actual);
    }

    #[test]
    fn eval_cat() {
        let input = Cursor::new(&b"Hello, World!"[..]);
        let mut output = Cursor::new(vec![]);

        match read(",[.,]") {
            Ok(program) => eval(program, input, &mut output),
            Err(_) => assert!(false),
        }

        let expected = "Hello, World!";
        let actual = String::from_utf8(output.into_inner()).expect("Not UTF-8");

        assert_eq!(expected, actual);
    }

    // #[test]
    // fn eval_hello_world() {
    //     let input = Cursor::new(&b""[..]);
    //     let mut output = Cursor::new(vec![]);

    //     match read("--------[>+>+++++>-->-->--->++++>------<<<<<<<-------]>.>---.>----..>-.>++++.>.>+++++++.<<<.+++.<.<-.>>>>+.") {
    //         Ok(program) => eval(program, input, &mut output),
    //         Err(_) => assert!(false),
    //     }

    //     let expected = "Hello, World!";
    //     let actual = String::from_utf8(output.into_inner()).expect("Not UTF-8");

    //     assert_eq!(expected, actual);
    // }
}
<|endoftext|>


<commit_before>use std::path::*;
use std::io::{Result, Write};

use env::Env;
use file_saver::*;
use library;
use nameutil::*;
use super::functions;
use super::statics;
use super::super::general;

pub fn generate(env: &Env) {
    println!("generating sys for {}", env.config.library_name);

    let path =  PathBuf::from(&env.config.target_path)
        .join(file_name_sys(&env.config.library_name, "lib"));
    println!("Generating file {:?}", path);

    save_to_file(path, &mut |w| generate_lib(w, env));
}

fn generate_lib<W: Write>(w: &mut W, env: &Env) -> Result<()>{
    try!(general::start_comments(w, &env.config));
    try!(statics::begin(w));

    let ns = env.library.namespace(library::MAIN_NAMESPACE);
    let classes = prepare_classes(ns);

    try!(generate_classes_structs(w, &classes));
    try!(generate_interfaces_structs(w, &prepare_interfaces(ns)));

    try!(statics::before_func(w));

    try!(writeln!(w, ""));
    try!(writeln!(w, "extern \"C\" {{"));
    try!(functions::generate_classes_funcs(w, env, &classes));

    //TODO: other functions
    try!(writeln!(w, "\n}}"));

    Ok(())
}

fn prepare_classes(ns: &library::Namespace) -> Vec<&library::Class> {
    let mut vec: Vec<&library::Class> = Vec::with_capacity(ns.types.len());
    for typ in &ns.types {
        if let &Some(library::Type::Class(ref klass)) = typ {
            vec.push(klass);
        }
    }
    vec.sort();
    vec
}

fn generate_classes_structs<W: Write>(w: &mut W, classes: &Vec<&library::Class>) -> Result<()> {
    try!(writeln!(w, ""));
    for klass in classes {
        try!(writeln!(w, "#[repr(C)]\npub struct {};", klass.glib_type_name));
    }

    Ok(())
}

fn prepare_interfaces(ns: &library::Namespace) -> Vec<&library::Interface> {
    let mut vec: Vec<&library::Interface> = Vec::with_capacity(ns.types.len());
    for typ in &ns.types {
        if let &Some(library::Type::Interface(ref interface)) = typ {
            vec.push(interface);
        }
    }
    vec.sort();
    vec
}

fn generate_interfaces_structs<W: Write>(w: &mut W, interfaces: &Vec<&library::Interface>) -> Result<()> {
    try!(writeln!(w, ""));
    for interface in interfaces {
        try!(writeln!(w, "#[repr(C)]\npub struct {};", interface.glib_type_name));
    }

    Ok(())
}
<commit_msg>codegen::sys::lib: Generalize fn prepare<commit_after>use std::path::*;
use std::io::{Result, Write};

use env::Env;
use file_saver::*;
use library::{self, MaybeRef};
use nameutil::*;
use super::functions;
use super::statics;
use super::super::general;

pub fn generate(env: &Env) {
    println!("generating sys for {}", env.config.library_name);

    let path =  PathBuf::from(&env.config.target_path)
        .join(file_name_sys(&env.config.library_name, "lib"));
    println!("Generating file {:?}", path);

    save_to_file(path, &mut |w| generate_lib(w, env));
}

fn generate_lib<W: Write>(w: &mut W, env: &Env) -> Result<()>{
    try!(general::start_comments(w, &env.config));
    try!(statics::begin(w));

    let ns = env.library.namespace(library::MAIN_NAMESPACE);
    let classes = prepare(ns);

    try!(generate_classes_structs(w, &classes));
    try!(generate_interfaces_structs(w, &prepare(ns)));

    try!(statics::before_func(w));

    try!(writeln!(w, ""));
    try!(writeln!(w, "extern \"C\" {{"));
    try!(functions::generate_classes_funcs(w, env, &classes));

    //TODO: other functions
    try!(writeln!(w, "\n}}"));

    Ok(())
}

fn prepare<T: Ord>(ns: &library::Namespace) -> Vec<&T>
where library::Type: MaybeRef<T> {
    let mut vec: Vec<&T> = Vec::with_capacity(ns.types.len());
    for typ in ns.types.iter().filter_map(|t| t.as_ref()) {
        if let Some(ref x) = typ.maybe_ref() {
            vec.push(x);
        }
    }
    vec.sort();
    vec
}

fn generate_classes_structs<W: Write>(w: &mut W, classes: &Vec<&library::Class>) -> Result<()> {
    try!(writeln!(w, ""));
    for klass in classes {
        try!(writeln!(w, "#[repr(C)]\npub struct {};", klass.glib_type_name));
    }

    Ok(())
}

fn generate_interfaces_structs<W: Write>(w: &mut W, interfaces: &Vec<&library::Interface>) -> Result<()> {
    try!(writeln!(w, ""));
    for interface in interfaces {
        try!(writeln!(w, "#[repr(C)]\npub struct {};", interface.glib_type_name));
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! Commands from the user to manipulate the tree

use super::{try_lock_tree, try_lock_action, lock_action};
use super::{Action, Container, ContainerType, Direction, Handle, Layout, TreeError};
use super::Tree;

use uuid::Uuid;
use rustwlc::{Geometry, Point, ResizeEdge, WlcView, WlcOutput, ViewType};
use rustc_serialize::json::{Json, ToJson};

pub type CommandResult = Result<(), TreeError>;

/* These commands are exported to take nothing and return nothing,
 * since they are the commands actually registered and usable over
 * the IPC/Lua thread.
 */

pub fn remove_active() {
    if let Ok(mut tree) = try_lock_tree() {
        if let Some(container) = tree.0.get_active_container_mut() {
            match *container {
                Container::View { ref handle, .. } => {
                    handle.close();
                    // Thanks borrowck
                    // Views shouldn't be removed from tree, that's handled by
                    // view_destroyed callback
                    return
                },
                _ => {}
            }
        }
        tree.0.remove_active();
    }
}

pub fn toggle_float() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.toggle_float().ok();
    }
}

pub fn toggle_float_focus() {
    if let Ok(mut tree) = try_lock_tree() {
        if let Err(err) = tree.toggle_floating_focus() {
            warn!("Could not float focus: {:#?}", err);
        }
    }
}

pub fn tile_switch() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.0.toggle_cardinal_tiling();
        tree.layout_active_of(ContainerType::Workspace)
            .unwrap_or_else(|_| {
                warn!("Could not tile workspace");
            });
    }
}

pub fn split_vertical() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.0.toggle_active_layout(Layout::Vertical).ok();
    }
}

pub fn split_horizontal() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.0.toggle_active_layout(Layout::Horizontal).ok();
    }
}

pub fn focus_left() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Left)
            .unwrap_or_else(|_| {
                warn!("Could not focus left");
            });
    }
}

pub fn focus_right() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Right)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            });
    }
}

pub fn focus_up() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Up)
            .unwrap_or_else(|_| {
                warn!("Could not focus up");
            });
    }
}

pub fn focus_down() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Down)
            .unwrap_or_else(|_| {
                warn!("Could not focus down");
            });
    }
}

pub fn move_active_left() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Left)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            })
    }
}

pub fn move_active_right() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Right)
            .unwrap_or_else(|_| {
                error!("Could not focus right");
            })
    }
}

pub fn move_active_up() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Up)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            })
    }
}

pub fn move_active_down() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Down)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            })
    }
}

pub fn tree_as_json() -> Json {
    if let Ok(tree) = try_lock_tree() {
        tree.0.to_json()
    } else {
        Json::Null
    }
}

/// Returns a copy of the action behind the lock.
pub fn performing_action() -> Option<Action> {
    if let Ok(action) = try_lock_action() {
        *action
    } else {
        error!("Could not lock action mutex!");
        None
    }
}

/// Sets the value behind the lock to the provided value.
///
/// None means an action is done being performed.
pub fn set_performing_action(val: Option<Action>) -> CommandResult {
    if let Ok(mut action) = lock_action() {
        *action = val;
        Ok(())
    } else {
        error!("Action mutex was poisoned");
        panic!("Action mutex was poisoned");
    }
}

/* These commands are the interface that the rest of Way Cooler has to the
 * tree. Any action done, whether through a callback, or from the IPC/Lua thread
 * it will have to go through one of these methods.
 */

impl Tree {
    /// Gets the uuid of the active container, if there is an active container
    pub fn active_id(&self) -> Option<Uuid> {
        if let Some(active_ix) = self.0.active_container {
            Some(self.0.tree[active_ix].get_id())
        } else {
            None
        }
    }

    pub fn toggle_float(&mut self) -> CommandResult {
        if let Some(uuid) = self.active_id() {
            let is_floating: Result<bool, _> = self.0.lookup(uuid)
                .and_then(|container| Ok(container.floating()));
            try!(match is_floating {
                Ok(true) => self.ground_container(uuid),
                Ok(false) => self.float_container(uuid),
                Err(err) => return Err(err)
            });
        }
        Ok(())
    }

    pub fn toggle_floating_focus(&mut self) -> CommandResult {
        self.0.toggle_floating_focus()
    }

    pub fn move_active(&mut self, maybe_uuid: Option<Uuid>, direction: Direction) -> CommandResult {
        let uuid = try!(maybe_uuid
                        .or_else(|| self.0.get_active_container()
                                 .and_then(|container| Some(container.get_id())))
                        .ok_or(TreeError::NoActiveContainer));
        try!(self.0.move_container(uuid, direction));
        // NOTE Make this not layout the active, but actually the node index's workspace.
        try!(self.layout_active_of(ContainerType::Output));
        Ok(())
    }

    /// Attempts to drag the window around the screen.
    pub fn try_drag_active(&mut self, point: Point) -> CommandResult {
        if let Some(mut action) = performing_action() {
            let old_point = action.grab;
            let active_ix = try!(self.0.active_container
                                .ok_or(TreeError::NoActiveContainer));
            try!(self.0.drag_floating(active_ix, point, old_point));
            action.grab = point;
            set_performing_action(Some(action)).unwrap();
            Ok(())
        } else {
            Err(TreeError::PerformingAction(false))
        }
    }

    /// Adds an Output to the tree. Never fails
    pub fn add_output(&mut self, output: WlcOutput) -> CommandResult {
        self.0.add_output(output);
        Ok(())
    }

    /// Adds a Workspace to the tree. Never fails
    pub fn switch_to_workspace(&mut self, name: &str) -> CommandResult {
        self.0.switch_to_workspace(name);
        Ok(())
    }

    /// Tiles the active container of some container type. Never fails
    pub fn layout_active_of(&mut self, c_type: ContainerType) -> CommandResult {
        self.0.layout_active_of(c_type);
        Ok(())
    }

    /// Attempts to set the node behind the id to be floating
    pub fn float_container(&mut self, id: Uuid) -> CommandResult {
        self.0.float_container(id)
    }

    /// Attempts to set the node behind the id to be not floating
    pub fn ground_container(&mut self, id: Uuid) -> CommandResult {
        self.0.ground_container(id)
    }

    /// Adds a view to the workspace of the active container
    pub fn add_view(&mut self, view: WlcView) -> CommandResult {
        let tree = &mut self.0;
        let output = view.get_output();
        if tree.get_active_container().is_none() {
            return Err(TreeError::NoActiveContainer)
        }
        view.set_mask(output.get_mask());
        let v_type = view.get_type();
        let v_class = view.get_class();
        // If it is empty, don't add to tree
        if v_type != ViewType::empty() {
            // Now focused on something outside the tree,
            // have to unset the active container
            if !tree.active_is_root() {
                tree.unset_active_container();
            }
            return Ok(())
        }
        if v_class.as_str() == "Background" {
            info!("Setting background: {}", view.get_title());
            view.send_to_back();
            let output = view.get_output();
            let resolution = output.get_resolution()
                .expect("Couldn't get output resolution");
            let fullscreen = Geometry {
                origin: Point { x: 0, y: 0 },
                size: resolution
            };
            view.set_geometry(ResizeEdge::empty(), fullscreen);
            return Ok(());
        }
        try!(tree.add_view(view));
        tree.normalize_view(view);
        tree.layout_active_of(ContainerType::Workspace);
        Ok(())
    }

    /// Attempts to remove a view from the tree. If it is not in the tree it fails.
    ///
    /// This will NOT close the handle behind the view, and should only be called
    /// on views that have already been slated for removal from the wlc pool.
    /// Otherwise you leak a `WlcView`
    pub fn remove_view(&mut self, view: WlcView) -> CommandResult {
        let result;
        match self.0.remove_view(&view) {
            Err(err)  => {
                warn!("Remove view error: {:?}\n {:#?}", err, *self.0);
                result = Err(err)
            },
            Ok(Container::View { handle, id, .. }) => {
                trace!("Removed container {:?}", id);
                handle.close();
                trace!("Close wlc view {:?}", handle);
                result = Ok(())
            },
            _ => unreachable!()
        }
        let root_ix = self.0.tree.root_ix();
        self.0.layout(root_ix);
        result
    }

    /// Attempts to remove a container based on UUID. Fails if the container
    /// cannot be removed or if the container does not exist.
    ///
    /// This WILL close the view, and should never be called from the
    /// `view_destroyed` callback, as it's possible the view from that callback is invalid.
    pub fn remove_view_by_id(&mut self, id: Uuid) -> CommandResult {
        match try!(self.0.lookup(id)).get_handle() {
            Some(Handle::View(view)) => return self.remove_view(view),
            Some(Handle::Output(_)) | None => {
                Err(TreeError::UuidNotAssociatedWith(ContainerType::View))
            }
        }
    }

    /// Sets the view to be the new active container. Never fails
    pub fn set_active_view(&mut self, view: WlcView) -> CommandResult {
        try!(self.0.set_active_view(view.clone()));
        view.focus();
        Ok(())
    }

    #[allow(dead_code)]
    /// Sets the active container to be the container at the UUID
    /// Fails if the container is not a container or view, or if the
    /// container does not exist
    pub fn set_active_container_by_id(&mut self, id: Uuid) -> CommandResult {
        if let Some(node_ix) = self.0.tree.lookup_id(id) {
            match self.0.tree[node_ix].get_type() {
                ContainerType::View | ContainerType::Container => {
                    self.0.active_container = Some(node_ix);
                    Ok(())
                },
                _ => {
                    Err(TreeError::UuidWrongType(self.0.tree[node_ix].get_id(),
                                                  vec!(ContainerType::View,
                                                       ContainerType::Container)))
                }

            }
        } else {
            Err(TreeError::NodeNotFound(id))
        }
    }

    /// Destroy the tree
    pub fn destroy_tree(&mut self) -> CommandResult {
        self.0.destroy_tree();
        Ok(())
    }

    pub fn move_focus(&mut self, dir: Direction) -> CommandResult {
        try!(self.0.move_focus(dir));
        Ok(())
    }

    /// Moves the active container to a workspace
    pub fn send_active_to_workspace(&mut self, workspace_name: &str) -> CommandResult {
        self.0.send_active_to_workspace(workspace_name);
        Ok(())
    }
}
<commit_msg>set_active_container_by_id calls its proper method<commit_after>//! Commands from the user to manipulate the tree

use super::{try_lock_tree, try_lock_action, lock_action};
use super::{Action, Container, ContainerType, Direction, Handle, Layout, TreeError};
use super::Tree;

use uuid::Uuid;
use rustwlc::{Geometry, Point, ResizeEdge, WlcView, WlcOutput, ViewType};
use rustc_serialize::json::{Json, ToJson};

pub type CommandResult = Result<(), TreeError>;

/* These commands are exported to take nothing and return nothing,
 * since they are the commands actually registered and usable over
 * the IPC/Lua thread.
 */

pub fn remove_active() {
    if let Ok(mut tree) = try_lock_tree() {
        if let Some(container) = tree.0.get_active_container_mut() {
            match *container {
                Container::View { ref handle, .. } => {
                    handle.close();
                    // Thanks borrowck
                    // Views shouldn't be removed from tree, that's handled by
                    // view_destroyed callback
                    return
                },
                _ => {}
            }
        }
        tree.0.remove_active();
    }
}

pub fn toggle_float() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.toggle_float().ok();
    }
}

pub fn toggle_float_focus() {
    if let Ok(mut tree) = try_lock_tree() {
        if let Err(err) = tree.toggle_floating_focus() {
            warn!("Could not float focus: {:#?}", err);
        }
    }
}

pub fn tile_switch() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.0.toggle_cardinal_tiling();
        tree.layout_active_of(ContainerType::Workspace)
            .unwrap_or_else(|_| {
                warn!("Could not tile workspace");
            });
    }
}

pub fn split_vertical() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.0.toggle_active_layout(Layout::Vertical).ok();
    }
}

pub fn split_horizontal() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.0.toggle_active_layout(Layout::Horizontal).ok();
    }
}

pub fn focus_left() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Left)
            .unwrap_or_else(|_| {
                warn!("Could not focus left");
            });
    }
}

pub fn focus_right() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Right)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            });
    }
}

pub fn focus_up() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Up)
            .unwrap_or_else(|_| {
                warn!("Could not focus up");
            });
    }
}

pub fn focus_down() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Down)
            .unwrap_or_else(|_| {
                warn!("Could not focus down");
            });
    }
}

pub fn move_active_left() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Left)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            })
    }
}

pub fn move_active_right() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Right)
            .unwrap_or_else(|_| {
                error!("Could not focus right");
            })
    }
}

pub fn move_active_up() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Up)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            })
    }
}

pub fn move_active_down() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Down)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            })
    }
}

pub fn tree_as_json() -> Json {
    if let Ok(tree) = try_lock_tree() {
        tree.0.to_json()
    } else {
        Json::Null
    }
}

/// Returns a copy of the action behind the lock.
pub fn performing_action() -> Option<Action> {
    if let Ok(action) = try_lock_action() {
        *action
    } else {
        error!("Could not lock action mutex!");
        None
    }
}

/// Sets the value behind the lock to the provided value.
///
/// None means an action is done being performed.
pub fn set_performing_action(val: Option<Action>) -> CommandResult {
    if let Ok(mut action) = lock_action() {
        *action = val;
        Ok(())
    } else {
        error!("Action mutex was poisoned");
        panic!("Action mutex was poisoned");
    }
}

/* These commands are the interface that the rest of Way Cooler has to the
 * tree. Any action done, whether through a callback, or from the IPC/Lua thread
 * it will have to go through one of these methods.
 */

impl Tree {
    /// Gets the uuid of the active container, if there is an active container
    pub fn active_id(&self) -> Option<Uuid> {
        if let Some(active_ix) = self.0.active_container {
            Some(self.0.tree[active_ix].get_id())
        } else {
            None
        }
    }

    pub fn toggle_float(&mut self) -> CommandResult {
        if let Some(uuid) = self.active_id() {
            let is_floating: Result<bool, _> = self.0.lookup(uuid)
                .and_then(|container| Ok(container.floating()));
            try!(match is_floating {
                Ok(true) => self.ground_container(uuid),
                Ok(false) => self.float_container(uuid),
                Err(err) => return Err(err)
            });
        }
        Ok(())
    }

    pub fn toggle_floating_focus(&mut self) -> CommandResult {
        self.0.toggle_floating_focus()
    }

    pub fn move_active(&mut self, maybe_uuid: Option<Uuid>, direction: Direction) -> CommandResult {
        let uuid = try!(maybe_uuid
                        .or_else(|| self.0.get_active_container()
                                 .and_then(|container| Some(container.get_id())))
                        .ok_or(TreeError::NoActiveContainer));
        try!(self.0.move_container(uuid, direction));
        // NOTE Make this not layout the active, but actually the node index's workspace.
        try!(self.layout_active_of(ContainerType::Output));
        Ok(())
    }

    /// Attempts to drag the window around the screen.
    pub fn try_drag_active(&mut self, point: Point) -> CommandResult {
        if let Some(mut action) = performing_action() {
            let old_point = action.grab;
            let active_ix = try!(self.0.active_container
                                .ok_or(TreeError::NoActiveContainer));
            try!(self.0.drag_floating(active_ix, point, old_point));
            action.grab = point;
            set_performing_action(Some(action)).unwrap();
            Ok(())
        } else {
            Err(TreeError::PerformingAction(false))
        }
    }

    /// Adds an Output to the tree. Never fails
    pub fn add_output(&mut self, output: WlcOutput) -> CommandResult {
        self.0.add_output(output);
        Ok(())
    }

    /// Adds a Workspace to the tree. Never fails
    pub fn switch_to_workspace(&mut self, name: &str) -> CommandResult {
        self.0.switch_to_workspace(name);
        Ok(())
    }

    /// Tiles the active container of some container type. Never fails
    pub fn layout_active_of(&mut self, c_type: ContainerType) -> CommandResult {
        self.0.layout_active_of(c_type);
        Ok(())
    }

    /// Attempts to set the node behind the id to be floating
    pub fn float_container(&mut self, id: Uuid) -> CommandResult {
        self.0.float_container(id)
    }

    /// Attempts to set the node behind the id to be not floating
    pub fn ground_container(&mut self, id: Uuid) -> CommandResult {
        self.0.ground_container(id)
    }

    /// Adds a view to the workspace of the active container
    pub fn add_view(&mut self, view: WlcView) -> CommandResult {
        let tree = &mut self.0;
        let output = view.get_output();
        if tree.get_active_container().is_none() {
            return Err(TreeError::NoActiveContainer)
        }
        view.set_mask(output.get_mask());
        let v_type = view.get_type();
        let v_class = view.get_class();
        // If it is empty, don't add to tree
        if v_type != ViewType::empty() {
            // Now focused on something outside the tree,
            // have to unset the active container
            if !tree.active_is_root() {
                tree.unset_active_container();
            }
            return Ok(())
        }
        if v_class.as_str() == "Background" {
            info!("Setting background: {}", view.get_title());
            view.send_to_back();
            let output = view.get_output();
            let resolution = output.get_resolution()
                .expect("Couldn't get output resolution");
            let fullscreen = Geometry {
                origin: Point { x: 0, y: 0 },
                size: resolution
            };
            view.set_geometry(ResizeEdge::empty(), fullscreen);
            return Ok(());
        }
        try!(tree.add_view(view));
        tree.normalize_view(view);
        tree.layout_active_of(ContainerType::Workspace);
        Ok(())
    }

    /// Attempts to remove a view from the tree. If it is not in the tree it fails.
    ///
    /// This will NOT close the handle behind the view, and should only be called
    /// on views that have already been slated for removal from the wlc pool.
    /// Otherwise you leak a `WlcView`
    pub fn remove_view(&mut self, view: WlcView) -> CommandResult {
        let result;
        match self.0.remove_view(&view) {
            Err(err)  => {
                warn!("Remove view error: {:?}\n {:#?}", err, *self.0);
                result = Err(err)
            },
            Ok(Container::View { handle, id, .. }) => {
                trace!("Removed container {:?}", id);
                handle.close();
                trace!("Close wlc view {:?}", handle);
                result = Ok(())
            },
            _ => unreachable!()
        }
        let root_ix = self.0.tree.root_ix();
        self.0.layout(root_ix);
        result
    }

    /// Attempts to remove a container based on UUID. Fails if the container
    /// cannot be removed or if the container does not exist.
    ///
    /// This WILL close the view, and should never be called from the
    /// `view_destroyed` callback, as it's possible the view from that callback is invalid.
    pub fn remove_view_by_id(&mut self, id: Uuid) -> CommandResult {
        match try!(self.0.lookup(id)).get_handle() {
            Some(Handle::View(view)) => return self.remove_view(view),
            Some(Handle::Output(_)) | None => {
                Err(TreeError::UuidNotAssociatedWith(ContainerType::View))
            }
        }
    }

    /// Sets the view to be the new active container. Never fails
    pub fn set_active_view(&mut self, view: WlcView) -> CommandResult {
        try!(self.0.set_active_view(view.clone()));
        view.focus();
        Ok(())
    }

    #[allow(dead_code)]
    /// Sets the active container to be the container at the UUID
    /// Fails if the container is not a container or view, or if the
    /// container does not exist
    ///
    /// Can also not set floating containers to be active.
    pub fn set_active_container_by_id(&mut self, id: Uuid) -> CommandResult {
        self.0.set_active_container(id)
    }

    /// Destroy the tree
    pub fn destroy_tree(&mut self) -> CommandResult {
        self.0.destroy_tree();
        Ok(())
    }

    pub fn move_focus(&mut self, dir: Direction) -> CommandResult {
        try!(self.0.move_focus(dir));
        Ok(())
    }

    /// Moves the active container to a workspace
    pub fn send_active_to_workspace(&mut self, workspace_name: &str) -> CommandResult {
        self.0.send_active_to_workspace(workspace_name);
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use lib::alias_dist::AliasDistribution;
use lib::error::MarkovpassError;

struct MarkovChainIterator<'a> {
    markov_chain: &'a PassphraseMarkovChain,
    current: &'a str,
}

impl<'a> Iterator for MarkovChainIterator<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        let last = self.current;
        self.current = self.markov_chain.get_next_ngram(&self.current);

        Some(last)
    }
}

#[derive(Debug)]
struct MarkovNode<T> {
    pub value: T,
    transitions: Vec<T>,
    dist: AliasDistribution,
}

impl<T> MarkovNode<T> {
    pub fn new(value: T, values: Vec<T>, weights: Vec<f64>) -> MarkovNode<T> {
        MarkovNode {
            value: value,
            transitions: values,
            dist: AliasDistribution::new(weights).unwrap(),
        }
    }

    pub fn next(&self) -> &T {
        &self.transitions[self.dist.choice()]
    }

    pub fn entropy(&self) -> f64 {
        self.dist.entropy
    }
}

#[derive(Debug)]
pub struct PassphraseMarkovChain {
    nodes: HashMap<String, MarkovNode<String>>,
    starting_ngrams: Vec<String>,
    starting_dist: AliasDistribution,
}

impl PassphraseMarkovChain {
    pub fn new(ngrams: Vec<String>) -> Result<PassphraseMarkovChain, MarkovpassError> {
        // Count transitions and viable starting ngrams.
        // To get natural sounding words, starting ngrams should be at word start.
        let mut transition_counters: HashMap<String, HashMap<String, usize>> = HashMap::new();
        let mut starting_ngram_counts: HashMap<String, usize> = HashMap::new();

        if ngrams.len() == 0 {
            return Err(MarkovpassError::NoNgrams);
        }
        let mut a = ngrams[0].clone();
        for b in ngrams
            .into_iter()
            .skip(1)
            .chain(Some(a.clone()).into_iter())
        {
            if a.starts_with(" ") {
                *starting_ngram_counts.entry(a.clone()).or_insert(0) += 1;
            }
            let transitions = transition_counters.entry(a).or_insert(HashMap::new());
            *transitions.entry(b.clone()).or_insert(0) += 1;
            a = b;
        }

        // Generate the starting ngram probability distribution.
        let mut starting_ngrams = Vec::with_capacity(starting_ngram_counts.len());
        let mut weights = Vec::with_capacity(starting_ngram_counts.len());
        for (value, weight) in starting_ngram_counts.into_iter() {
            starting_ngrams.push(value);
            weights.push(weight as f64);
        }
        let starting_dist = AliasDistribution::new(weights).unwrap();

        // Build all the MarkovNodes from the tranition counts.
        let mut nodes: HashMap<String, MarkovNode<String>> = HashMap::new();
        let mut total_entropy: f64 = 0.0;
        for (ngram, transition_counts) in transition_counters.into_iter() {
            let mut values = Vec::with_capacity(transition_counts.len());
            let mut weights = Vec::with_capacity(transition_counts.len());
            for (value, weight) in transition_counts.into_iter() {
                values.push(value.clone());
                weights.push(weight as f64);
            }

            let node = MarkovNode::new(ngram.clone(), values, weights);
            total_entropy += node.entropy();
            nodes.insert(ngram.to_string(), node);
        }

        if total_entropy == 0.0 {
            return Err(MarkovpassError::NoEntropy);
        } else if starting_dist.entropy == 0.0 {
            return Err(MarkovpassError::NoStartOfWordEntropy);
        };

        Ok(PassphraseMarkovChain {
            nodes: nodes,
            starting_ngrams: starting_ngrams,
            starting_dist: starting_dist,
        })
    }

    pub fn passphrase(&self, min_entropy: f64) -> (String, f64) {
        let mut selected_ngrams = Vec::new();
        let mut entropy = self.starting_dist.entropy;

        for ngram in self.iter() {
            selected_ngrams.push(ngram.clone());
            entropy += self.ngram_entropy(&ngram);
            if entropy >= min_entropy && ngram.ends_with(" ") {
                break;
            }
        }

        // Include the first character from each ngram, and the whole final ngram.
        let tail = selected_ngrams.last().unwrap().chars().skip(1);
        let chars = selected_ngrams
            .iter()
            .map(|n| n.chars().next().unwrap())
            .chain(tail);
        let passphrase = chars.collect::<String>().trim().to_string();

        (passphrase, entropy)
    }

    fn iter(&self) -> MarkovChainIterator {
        MarkovChainIterator {
            markov_chain: &self,
            current: &self.get_starting_ngram(),
        }
    }

    fn get_starting_ngram(&self) -> &str {
        &self.nodes
            .get(&self.starting_ngrams[self.starting_dist.choice()])
            .unwrap()
            .value
    }

    fn get_next_ngram(&self, ngram: &str) -> &str {
        self.nodes.get(ngram).unwrap().next()
    }

    fn ngram_entropy(&self, ngram: &str) -> f64 {
        self.nodes.get(ngram).unwrap().entropy()
    }
}

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

    #[test]
    fn test_passphrasemarkovchain_new() {
        let ngrams = vec![" ti", "tic", "ic ", "c t", " to", "toc", "oc ", "c t"];
        let ngrams: Vec<String> = ngrams.iter().map(|x| x.to_string()).collect();
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_ok());
        let chain = result.unwrap();
        assert_eq!(chain.starting_ngrams.len(), 2);
        assert!(chain.starting_ngrams.contains(&" ti".to_string()));
        assert!(chain.starting_ngrams.contains(&" to".to_string()));
        assert_eq!(chain.starting_dist.entropy, 1.0);
        assert!(ngrams.contains(&chain.get_starting_ngram().to_string()));
        let (p, e) = chain.passphrase(60.0);
        assert_eq!(e, 60.0);
        assert_eq!(p.len(), 239);
    }

    #[test]
    fn test_passphrase_no_ngrams() {
        let ngrams: Vec<String> = vec![];
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoNgrams);
    }

    #[test]
    fn test_passphrase_no_entropy() {
        let ngrams = vec![" ab", "abc", "bcd", "cd ", "d a"];
        let ngrams: Vec<String> = ngrams.iter().map(|x| x.to_string()).collect();
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoEntropy);
    }

    #[test]
    fn test_passphrases_no_starting_entropy() {
        let ngrams = vec![
            " ab", "abc", "bc ", "c a", " ab", "abc", "cbd", "bd ", "d a"
        ];
        let ngrams: Vec<String> = ngrams.iter().map(|x| x.to_string()).collect();
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoStartOfWordEntropy);
    }
}
<commit_msg>Minor style fixup<commit_after>use std::collections::HashMap;
use lib::alias_dist::AliasDistribution;
use lib::error::MarkovpassError;

struct MarkovChainIterator<'a> {
    markov_chain: &'a PassphraseMarkovChain,
    current: &'a str,
}

impl<'a> Iterator for MarkovChainIterator<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        let last = self.current;
        self.current = self.markov_chain.get_next_ngram(&self.current);

        Some(last)
    }
}

#[derive(Debug)]
struct MarkovNode<T> {
    pub value: T,
    transitions: Vec<T>,
    dist: AliasDistribution,
}

impl<T> MarkovNode<T> {
    pub fn new(value: T, values: Vec<T>, weights: Vec<f64>) -> MarkovNode<T> {
        MarkovNode {
            value: value,
            transitions: values,
            dist: AliasDistribution::new(weights).unwrap(),
        }
    }

    pub fn next(&self) -> &T {
        &self.transitions[self.dist.choice()]
    }

    pub fn entropy(&self) -> f64 {
        self.dist.entropy
    }
}

#[derive(Debug)]
pub struct PassphraseMarkovChain {
    nodes: HashMap<String, MarkovNode<String>>,
    starting_ngrams: Vec<String>,
    starting_dist: AliasDistribution,
}

impl PassphraseMarkovChain {
    pub fn new(ngrams: Vec<String>) -> Result<PassphraseMarkovChain, MarkovpassError> {
        // Count transitions and viable starting ngrams.
        // To get natural sounding words, starting ngrams should be at word start.
        let mut transition_counters: HashMap<String, HashMap<String, usize>> = HashMap::new();
        let mut starting_ngram_counts: HashMap<String, usize> = HashMap::new();

        if ngrams.len() == 0 {
            return Err(MarkovpassError::NoNgrams);
        }
        let mut a = ngrams[0].clone();
        for b in ngrams
            .into_iter()
            .skip(1)
            .chain(Some(a.clone()).into_iter())
        {
            if a.starts_with(" ") {
                *starting_ngram_counts.entry(a.clone()).or_insert(0) += 1;
            }
            *transition_counters
                .entry(a)
                .or_insert(HashMap::new())
                .entry(b.clone())
                .or_insert(0) += 1;
            a = b;
        }

        // Generate the starting ngram probability distribution.
        let mut starting_ngrams = Vec::with_capacity(starting_ngram_counts.len());
        let mut weights = Vec::with_capacity(starting_ngram_counts.len());
        for (value, weight) in starting_ngram_counts.into_iter() {
            starting_ngrams.push(value);
            weights.push(weight as f64);
        }
        let starting_dist = AliasDistribution::new(weights).unwrap();

        // Build all the MarkovNodes from the tranition counts.
        let mut nodes: HashMap<String, MarkovNode<String>> = HashMap::new();
        let mut total_entropy: f64 = 0.0;
        for (ngram, transition_counts) in transition_counters.into_iter() {
            let mut values = Vec::with_capacity(transition_counts.len());
            let mut weights = Vec::with_capacity(transition_counts.len());
            for (value, weight) in transition_counts.into_iter() {
                values.push(value.clone());
                weights.push(weight as f64);
            }

            let node = MarkovNode::new(ngram.clone(), values, weights);
            total_entropy += node.entropy();
            nodes.insert(ngram.to_string(), node);
        }

        if total_entropy == 0.0 {
            return Err(MarkovpassError::NoEntropy);
        } else if starting_dist.entropy == 0.0 {
            return Err(MarkovpassError::NoStartOfWordEntropy);
        };

        Ok(PassphraseMarkovChain {
            nodes: nodes,
            starting_ngrams: starting_ngrams,
            starting_dist: starting_dist,
        })
    }

    pub fn passphrase(&self, min_entropy: f64) -> (String, f64) {
        let mut selected_ngrams = Vec::new();
        let mut entropy = self.starting_dist.entropy;

        for ngram in self.iter() {
            selected_ngrams.push(ngram.clone());
            entropy += self.ngram_entropy(&ngram);
            if entropy >= min_entropy && ngram.ends_with(" ") {
                break;
            }
        }

        // Include the first character from each ngram, and the whole final ngram.
        let tail = selected_ngrams.last().unwrap().chars().skip(1);
        let chars = selected_ngrams
            .iter()
            .map(|n| n.chars().next().unwrap())
            .chain(tail);
        let passphrase = chars.collect::<String>().trim().to_string();

        (passphrase, entropy)
    }

    fn iter(&self) -> MarkovChainIterator {
        MarkovChainIterator {
            markov_chain: &self,
            current: &self.get_starting_ngram(),
        }
    }

    fn get_starting_ngram(&self) -> &str {
        &self.nodes
            .get(&self.starting_ngrams[self.starting_dist.choice()])
            .unwrap()
            .value
    }

    fn get_next_ngram(&self, ngram: &str) -> &str {
        self.nodes.get(ngram).unwrap().next()
    }

    fn ngram_entropy(&self, ngram: &str) -> f64 {
        self.nodes.get(ngram).unwrap().entropy()
    }
}

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

    #[test]
    fn test_passphrasemarkovchain_new() {
        let ngrams = vec![" ti", "tic", "ic ", "c t", " to", "toc", "oc ", "c t"];
        let ngrams: Vec<String> = ngrams.iter().map(|x| x.to_string()).collect();
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_ok());
        let chain = result.unwrap();
        assert_eq!(chain.starting_ngrams.len(), 2);
        assert!(chain.starting_ngrams.contains(&" ti".to_string()));
        assert!(chain.starting_ngrams.contains(&" to".to_string()));
        assert_eq!(chain.starting_dist.entropy, 1.0);
        assert!(ngrams.contains(&chain.get_starting_ngram().to_string()));
        let (p, e) = chain.passphrase(60.0);
        assert_eq!(e, 60.0);
        assert_eq!(p.len(), 239);
    }

    #[test]
    fn test_passphrase_no_ngrams() {
        let ngrams: Vec<String> = vec![];
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoNgrams);
    }

    #[test]
    fn test_passphrase_no_entropy() {
        let ngrams = vec![" ab", "abc", "bcd", "cd ", "d a"];
        let ngrams: Vec<String> = ngrams.iter().map(|x| x.to_string()).collect();
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoEntropy);
    }

    #[test]
    fn test_passphrases_no_starting_entropy() {
        let ngrams = vec![
            " ab", "abc", "bc ", "c a", " ab", "abc", "cbd", "bd ", "d a"
        ];
        let ngrams: Vec<String> = ngrams.iter().map(|x| x.to_string()).collect();
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoStartOfWordEntropy);
    }
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// use crate::contracts::native::factory::Factory as NativeFactory;
use crate::contracts::tools::method as method_tools;
// use crate::engines::NullEngine;
use crate::libexecutor::block::EVMBlockDataProvider;
use crate::types::reserved_addresses;
use cita_types::{Address, H160, U256};
// use evm::{Factory, VMType};
use std::str::FromStr;
// use util::BytesRef;
use crate::cita_executive::{build_evm_config, build_evm_context};
use crate::libexecutor::executor::CitaTrieDB;
use crate::types::context::Context;
use cita_vm::state::State as CitaState;
use cita_vm::Transaction as EVMTransaction;
use std::cell::RefCell;
use std::sync::Arc;

const AUTO_EXEC: &[u8] = &*b"autoExec()";

lazy_static! {
    static ref AUTO_EXEC_ADDR: H160 = H160::from_str(reserved_addresses::AUTO_EXEC).unwrap();
    static ref AUTO_EXEC_HASH: Vec<u8> = method_tools::encode_to_vec(AUTO_EXEC);
}

pub fn auto_exec(
    state: Arc<RefCell<CitaState<CitaTrieDB>>>,
    auto_exec_quota_limit: u64,
    context: Context,
) {
    let hash = &*AUTO_EXEC_HASH;
    let evm_transaction = EVMTransaction {
        from: Address::from(0x0),
        value: U256::from(0),
        gas_limit: auto_exec_quota_limit,
        gas_price: U256::from(1),
        input: hash.to_vec(),
        to: Some(*AUTO_EXEC_ADDR),
        nonce: U256::from(0),
    };

    let evm_config = build_evm_config(auto_exec_quota_limit);
    let evm_context = build_evm_context(&context);

    let block_provider = EVMBlockDataProvider::new(context.clone());
    match cita_vm::exec(
        Arc::new(block_provider),
        state,
        evm_context,
        evm_config,
        evm_transaction,
    ) {
        Ok(res) => trace!("Auto exec succeed: {:?}", res),
        Err(e) => info!("Auto exec failed: {}", e),
    }
}
<commit_msg>Fix: autoExec error (#816)<commit_after>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// use crate::contracts::native::factory::Factory as NativeFactory;
use crate::contracts::tools::method as method_tools;
// use crate::engines::NullEngine;
use crate::libexecutor::block::EVMBlockDataProvider;
use crate::types::reserved_addresses;
use cita_types::{Address, H160, U256};
// use evm::{Factory, VMType};
use std::str::FromStr;
// use util::BytesRef;
use crate::cita_executive::{build_evm_config, build_evm_context};
use crate::libexecutor::executor::CitaTrieDB;
use crate::types::context::Context;
use cita_vm::evm::InterpreterResult;
use cita_vm::state::State as CitaState;
use cita_vm::Transaction as EVMTransaction;
use std::cell::RefCell;
use std::sync::Arc;

const AUTO_EXEC: &[u8] = &*b"autoExec()";

lazy_static! {
    static ref AUTO_EXEC_ADDR: H160 = H160::from_str(reserved_addresses::AUTO_EXEC).unwrap();
    static ref AUTO_EXEC_HASH: Vec<u8> = method_tools::encode_to_vec(AUTO_EXEC);
}

pub fn auto_exec(
    state: Arc<RefCell<CitaState<CitaTrieDB>>>,
    auto_exec_quota_limit: u64,
    context: Context,
) {
    let hash = &*AUTO_EXEC_HASH;
    let evm_transaction = EVMTransaction {
        from: Address::from(0x0),
        value: U256::from(0),
        gas_limit: auto_exec_quota_limit,
        gas_price: U256::from(1),
        input: hash.to_vec(),
        to: Some(*AUTO_EXEC_ADDR),
        nonce: U256::from(0),
    };

    let mut evm_config = build_evm_config(auto_exec_quota_limit);

    // Do not check nonce and balance for auto exec
    evm_config.check_nonce = false;
    evm_config.check_balance = false;
    let evm_context = build_evm_context(&context);

    let block_provider = EVMBlockDataProvider::new(context.clone());
    match cita_vm::exec(
        Arc::new(block_provider),
        state,
        evm_context,
        evm_config,
        evm_transaction,
    ) {
        Ok(res) => match res {
            InterpreterResult::Normal(_, _, _) => {
                trace!("Auto exec run succeed.");
            }
            InterpreterResult::Revert(_, _) => {
                info!("Auto exec run Revert!");
            }
            _ => {
                info!("Auto exec should not run as create");
            }
        },
        Err(e) => info!("Auto exec failed: {}", e),
    }
}
<|endoftext|>


<commit_before>//! Memory management unit.

use core;

use kernel::mm::physical;
use kernel::mm::physical::Phys;

pub type Frame = [u8, ..PAGE_SIZE];

static PAGE_SIZE: uint = 0x1000;
static PAGE_SIZE_LOG2: uint = 12;

// kinda clever
define_flags!(Flags: u32 {
    SECTION = 0b10010,

    BUFFER = 1 << 2,
    CACHE,
    RW     = 1 << 10,
    CLIENT_ACCESS
})

#[repr(packed)]
pub struct Descriptor(u32);

#[repr(packed)]
struct PageTableCoarse {
    pages: [Descriptor, ..256]
}

#[allow(visible_private_types)]
#[repr(packed)]
pub struct PageDirectory {
    entries: [Descriptor, ..4096]
}

pub static mut directory: *mut PageDirectory = 0 as *mut PageDirectory;

define_reg!(CR, CRFlags: uint {
    CR_M  = 1 << 0,  // MMU enable
    CR_A  = 1 << 1,
    CR_C  = 1 << 2,  // Data cache enable
    CR_W  = 1 << 3,
    CR_P  = 1 << 4,  // 32-bit exception handler
    CR_D  = 1 << 5,  // 32-bit data address range
    CR_L  = 1 << 6,  // Implementation defined
    CR_B  = 1 << 7,  // Endianness
    CR_S  = 1 << 8,
    CR_R  = 1 << 9,
    CR_F  = 1 << 10, // Implementation defined
    CR_Z  = 1 << 11, // Implementation defined
    CR_I  = 1 << 12, // Instruction cache enable
    CR_V  = 1 << 13,
    CR_RR = 1 << 14,
    CR_L4 = 1 << 15
})

// Each of the 16 domains can be either allowed full access (manager)
// to a region of memory or restricted access to some pages in that region (client).
define_flags!(DomainTypeMask: uint {
    KERNEL = 0b11 << 0,
    USER   = 0b11 << 2,
    NOACCESS = 0,
    CLIENT   = 0b01 * 0x55555555,
    MANAGER  = 0b11 * 0x55555555
})

impl CR {
    #[inline] #[allow(dead_code)]
    pub fn read() -> CRFlags {
        unsafe {
            let flags;
            asm!(concat!("mrc p15, 0, $0, c1, c0, 0") : "=r"(flags));
            CRFlags(flags)
        }
    }

    #[inline] #[allow(dead_code)]
    pub fn write(f: CRFlags) {
        match f {
            CRFlags(val) => unsafe {
                asm!(concat!("mcr p15, 0, $0, c1, c0, 0") :: "r"(val) :: "volatile");
            }
        }
    }
}

pub unsafe fn init() {
    let dir: Phys<PageDirectory> = physical::zero_alloc_frames(4);

    (*dir.as_ptr()).entries[0] = Descriptor::section(0, RW);

    switch_directory(dir);
    enable_paging();
}

pub fn switch_directory(dir: Phys<PageDirectory>) {
    // Memory protection is determined by control register c1 bits S and R,
    // domain access reg. c3 and per-page domain number and permission bits.
    let cpu_domain = KERNEL & MANAGER | USER & MANAGER;

    unsafe {
        asm!("mcr p15, 0, $0, c3, c0, 0     // load domain access register
              mcr p15, 0, $1, c2, c0, 0     // load page table pointer
            " :: "r"(cpu_domain), "r"(dir.offset()) : "ip" : "volatile");
    }
}

fn enable_paging() {
    unsafe {
        asm!("mov ip, 0
              mcr p15, 0, ip, c7, c5, 0     // invalidate I & D cache
              mcr p15, 0, ip, c7, c10, 4    // drain write buffer
              mcr p15, 0, ip, c8, c7, 0     // invalidate I & D TLBs
            " ::: "ip" : "volatile");

        CR::write(CR - (CR_A | CR_W | CR_P | CR_D | CR_R | CR_F | CR_Z | CR_V | CR_RR)
                     | (CR_S | CR_I | CR_C | CR_M));
    }
}

pub unsafe fn map(_: *mut u8, _: uint, _: Flags) {
    // TODO
}

impl Descriptor {
    fn section(base: u32, flags: Flags) -> Descriptor {
        // make a section descriptor
        Descriptor(base) | flags | SECTION
    }
}

impl_ops!(Descriptor, Flags)

impl PageDirectory {
    pub unsafe fn map(&self, _: *mut u8, _: uint, _: Flags) {
        // TODO
    }

    pub unsafe fn clone(&mut self) -> Phys<PageDirectory> {
        Phys::at(self as *mut PageDirectory as uint)
    }
}
<commit_msg>Use bitflags on ARM<commit_after>//! Memory management unit.

use core;

use kernel::mm::physical;
use kernel::mm::physical::Phys;

pub type Frame = [u8, ..PAGE_SIZE];

static PAGE_SIZE: uint = 0x1000;
static PAGE_SIZE_LOG2: uint = 12;

// kinda clever
bitflags!(flags Flags: u32 {
    static SECTION = 0b10010,

    static BUFFER = 1 << 2,
    static CACHE  = 1 << 3,
    static RW     = 1 << 10,
    static CLIENT_ACCESS = 1 << 11
})

#[repr(packed)]
pub struct Descriptor(u32);

#[repr(packed)]
struct PageTableCoarse {
    pages: [Descriptor, ..256]
}

#[allow(visible_private_types)]
#[repr(packed)]
pub struct PageDirectory {
    entries: [Descriptor, ..4096]
}

pub static mut directory: *mut PageDirectory = 0 as *mut PageDirectory;

define_reg!(CR, CRFlags: uint {
    CR_M  = 1 << 0,  // MMU enable
    CR_A  = 1 << 1,
    CR_C  = 1 << 2,  // Data cache enable
    CR_W  = 1 << 3,
    CR_P  = 1 << 4,  // 32-bit exception handler
    CR_D  = 1 << 5,  // 32-bit data address range
    CR_L  = 1 << 6,  // Implementation defined
    CR_B  = 1 << 7,  // Endianness
    CR_S  = 1 << 8,
    CR_R  = 1 << 9,
    CR_F  = 1 << 10, // Implementation defined
    CR_Z  = 1 << 11, // Implementation defined
    CR_I  = 1 << 12, // Instruction cache enable
    CR_V  = 1 << 13,
    CR_RR = 1 << 14,
    CR_L4 = 1 << 15
})

// Each of the 16 domains can be either allowed full access (manager)
// to a region of memory or restricted access to some pages in that region (client).
bitflags!(flags DomainTypeMask: uint {
    static KERNEL = 0b11 << 0,
    static USER   = 0b11 << 2,
    static NOACCESS = 0,
    static CLIENT   = 0b01 * 0x55555555,
    static MANAGER  = 0b11 * 0x55555555
})

impl CR {
    #[inline] #[allow(dead_code)]
    pub fn read() -> CRFlags {
        unsafe {
            let flags;
            asm!(concat!("mrc p15, 0, $0, c1, c0, 0") : "=r"(flags));
            CRFlags(flags)
        }
    }

    #[inline] #[allow(dead_code)]
    pub fn write(f: CRFlags) {
        match f {
            CRFlags(val) => unsafe {
                asm!(concat!("mcr p15, 0, $0, c1, c0, 0") :: "r"(val) :: "volatile");
            }
        }
    }
}

pub unsafe fn init() {
    let dir: Phys<PageDirectory> = physical::zero_alloc_frames(4);

    (*dir.as_ptr()).entries[0] = Descriptor::section(0, RW);

    switch_directory(dir);
    enable_paging();
}

pub fn switch_directory(dir: Phys<PageDirectory>) {
    // Memory protection is determined by control register c1 bits S and R,
    // domain access reg. c3 and per-page domain number and permission bits.
    let cpu_domain = KERNEL & MANAGER | USER & MANAGER;

    unsafe {
        asm!("mcr p15, 0, $0, c3, c0, 0     // load domain access register
              mcr p15, 0, $1, c2, c0, 0     // load page table pointer
            " :: "r"(cpu_domain), "r"(dir.offset()) : "ip" : "volatile");
    }
}

fn enable_paging() {
    unsafe {
        asm!("mov ip, 0
              mcr p15, 0, ip, c7, c5, 0     // invalidate I & D cache
              mcr p15, 0, ip, c7, c10, 4    // drain write buffer
              mcr p15, 0, ip, c8, c7, 0     // invalidate I & D TLBs
            " ::: "ip" : "volatile");

        CR::write(CR - (CR_A | CR_W | CR_P | CR_D | CR_R | CR_F | CR_Z | CR_V | CR_RR)
                     | (CR_S | CR_I | CR_C | CR_M));
    }
}

pub unsafe fn map(_: *mut u8, _: uint, _: Flags) {
    // TODO
}

impl Descriptor {
    fn section(base: u32, flags: Flags) -> Descriptor {
        // make a section descriptor
        Descriptor(base) | flags | SECTION
    }
}

impl_ops!(Descriptor, Flags)

impl PageDirectory {
    pub unsafe fn map(&self, _: *mut u8, _: uint, _: Flags) {
        // TODO
    }

    pub unsafe fn clone(&mut self) -> Phys<PageDirectory> {
        Phys::at(self as *mut PageDirectory as uint)
    }
}
<|endoftext|>


<commit_before>//! The dump module contains code related for outputing/dumping data.
use std::fmt::Display;
use std::convert::From;
use super::errors::*;

/// Enum which provides all possible output value formats supported by the dump module.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum OutputFormat {
    Hex,
    Decimal,
    Octal,
    Binary,
}

impl From<String> for OutputFormat {
    fn from(format_string: String) -> Self {
        match format_string.to_lowercase().as_ref() {
            "hex" => OutputFormat::Hex,
            "dec" => OutputFormat::Decimal,
            "oct" => OutputFormat::Octal,
            "bin" => OutputFormat::Binary,
            _ => panic!("Invalid output format"),
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct OutputSettings {
    start_address: u32,
    show_address: bool,
    group_size: usize,
    columns: usize,
    show_interpretation: bool,
    output_fmt: OutputFormat,
}

impl OutputSettings {
    pub fn new() -> OutputSettings {
        OutputSettings {
            start_address: 0,
            show_address: true,
            group_size: 1,
            columns: 8,
            show_interpretation: true,
            output_fmt: OutputFormat::Hex,
        }
    }

    pub fn bytes_per_line(&self) -> usize {
        self.columns * self.group_size
    }

    pub fn start_address(mut self, address: u32) -> Self {
        self.start_address = address;
        self
    }

    pub fn show_address(mut self, show: bool) -> Self {
        self.show_address = show;
        self
    }

    pub fn group_size(mut self, size: usize) -> Self {
        self.group_size = size;
        self
    }

    pub fn columns(mut self, columns: usize) -> Self {
        self.columns = columns;
        self
    }

    pub fn show_interpretation(mut self, show: bool) -> Self {
        self.show_interpretation = show;
        self
    }

    pub fn format(mut self, fmt: OutputFormat) -> Self {
        self.output_fmt = fmt;
        self
    }
}

/// The `OutputLine` struct contains all  information needed to dump/output a single line of data.
#[derive(Debug)]
pub struct OutputLine<'a> {
    output_settings: OutputSettings,
    data: &'a [u8],
}

impl<'a> OutputLine<'a> {
    pub fn new(data: &[u8]) -> OutputLine {
        OutputLine {
            output_settings: OutputSettings::new(),
            data: data,
        }
    }

    pub fn format(self, settings: OutputSettings) -> Self {
        OutputLine {
            output_settings: settings,
            data: self.data,
        }
    }

    fn write_address(&self, f: &mut ::fmt::Formatter) -> Result<()> {
        write!(f, "{:08.X}: ", self.output_settings.start_address).map_err(|e| e.into())
    }

    fn write_bytes(&self, f: &mut ::fmt::Formatter) -> Result<()> {
        let mut byte_count = 0;
        for b in self.data.iter() {
            byte_count += 1;
            let is_seperator_necessary = byte_count % self.output_settings.group_size == 0;
            if is_seperator_necessary {
                self.write_formated_byte(f, b)?;
                write!(f, " ")?
            } else {
                self.write_formated_byte(f, b)?
            }
        }
        Ok(())
    }

    fn write_formated_byte(&self, f: &mut ::fmt::Formatter, byte: &u8) -> Result<()> {
        match self.output_settings.output_fmt {
            OutputFormat::Hex => write!(f, "{:02.X}", byte).map_err(|e| e.into()),
            OutputFormat::Octal => write!(f, "{:03.o}", byte).map_err(|e| e.into()),
            OutputFormat::Decimal => write!(f, "{:03}", byte).map_err(|e| e.into()),
            OutputFormat::Binary => write!(f, "{:08b}", byte).map_err(|e| e.into()),
        }
    }

    fn write_interpretation(&self, f: &mut ::fmt::Formatter) -> Result<()> {
        write!(f, "   ");
        for b in self.data.iter() {
            match *b {
                character @ 20u8...126u8 => write!(f, "{}", character as char)?,
                _ => write!(f, "{}", ".")?,
            }
        }
        Ok(())
    }
}

impl<'a> ::fmt::Display for OutputLine<'a> {
    fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
        if self.output_settings.show_address {
            self.write_address(f);
        }
        self.write_bytes(f);
        if self.output_settings.show_interpretation {
            self.write_interpretation(f);
        }
        Ok(())
    }
}

mod test {
    // FIXME NICO: consider different sizes of the output formatats -> eg. oct 377 -> hex: ff ..

    use super::*;
    use std::fmt::Write;

    struct TestFixture {
        data: [u8; 8],
        small_data: [u8; 5],
    }

    impl TestFixture {
        fn new() -> Self {
            TestFixture {
                data: [0, 255, 127, 128, 56, 65, 1, 33],
                small_data: [0, 255, 80, 44, 7],
            }
        }

        fn data(&self) -> &[u8] {
            &self.data
        }

        fn small_data(&self) -> &[u8] {
            &self.small_data
        }
    }

    #[test]
    fn output_settings_can_be_constructed() {
        let output_settings = OutputSettings::new();
        assert!(true);
    }

    #[test]
    fn output_settings_builder() {
        let format = OutputFormat::Binary;
        let start_address = 0xFF00AABB;
        let group_size = 2;
        let show_address = false;
        let show_interpretation = false;

        let mut output_settings = OutputSettings::new()
            .format(format)
            .start_address(start_address)
            .group_size(group_size)
            .show_address(show_address)
            .show_interpretation(show_interpretation);

        assert_eq!(output_settings.output_fmt, format);
        assert_eq!(output_settings.start_address, start_address);
        assert_eq!(output_settings.group_size, group_size);
        assert_eq!(output_settings.show_address, show_address);
        assert_eq!(output_settings.show_interpretation, show_interpretation);
    }

    #[test]
    fn output_settings_get_bytes_per_line() {
        {
            let group_size = 8;
            let columns = 2;
            let mut output_settings = OutputSettings::new().columns(columns).group_size(group_size);
            assert_eq!(group_size * columns, output_settings.bytes_per_line())
        }
        {
            let group_size = 5;
            let columns = 4;
            let mut output_settings = OutputSettings::new().columns(columns).group_size(group_size);
            assert_eq!(group_size * columns, output_settings.bytes_per_line())
        }
        {
            let group_size = 9;
            let columns = 4;
            let mut output_settings = OutputSettings::new().columns(columns).group_size(group_size);
            assert_eq!(group_size * columns, output_settings.bytes_per_line())
        }
    }

    #[test]
    fn output_settings_from_string() {
        assert_eq!(OutputFormat::Binary, OutputFormat::from("bin".to_string()));
        assert_eq!(OutputFormat::Hex, OutputFormat::from("hex".to_string()));
        assert_eq!(OutputFormat::Octal, OutputFormat::from("oct".to_string()));
        assert_eq!(OutputFormat::Decimal, OutputFormat::from("dec".to_string()));

        assert_eq!(OutputFormat::Binary, OutputFormat::from("Bin".to_string()));
        assert_eq!(OutputFormat::Hex, OutputFormat::from("hEx".to_string()));
        assert_eq!(OutputFormat::Octal, OutputFormat::from("ocT".to_string()));
        assert_eq!(OutputFormat::Decimal, OutputFormat::from("DEC".to_string()));
    }

    #[test]
    fn outputline_can_be_constructed() {
        let fixture = TestFixture::new();
        let output_line = OutputLine::new(fixture.data());
        assert!(true);
    }

    #[test]
    fn default_output_format_for_a_single_line() {
        let fixture = TestFixture::new();
        let output_line = OutputLine::new(fixture.data());
        let expected_output = "00000000: 00 FF 7F 80 38 41 01 21    ....8A.!";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    // FIXME NICO: padding needs to be added if there are insufficient byte for a single line
    #[ignore]
    #[test]
    fn default_output_format_for_a_single_line_with_padding() {
        let fixture = TestFixture::new();
        let output_line = OutputLine::new(fixture.small_data());
        let expected_output = "00000000: 00 FF 50 2C 07             ..P,.";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn octal_output_format_on_a_single_line() {
        let fixture = TestFixture::new();
        let output_settings = OutputSettings::new().format(OutputFormat::Octal);
        let output_line = OutputLine::new(fixture.data()).format(output_settings);
        let expected_output = "00000000: 000 377 177 200 070 101 001 041    ....8A.!";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn binary_output_format_on_a_single_line() {
        // data: [0, 255, 127, 128, 56, 65, 1, 33],
        // small_data: [0, 255, 80, 44, 7],
        let fixture = TestFixture::new();
        let output_settings = OutputSettings::new().format(OutputFormat::Binary);
        let output_line = OutputLine::new(fixture.data()).format(output_settings);
        let expected_output = "00000000: 00000000 11111111 01111111 10000000 00111000 01000001 00000001 00100001    ....8A.!";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }
}
<commit_msg>Add padding while dumping incomplete lines<commit_after>//! The dump module contains code related for outputing/dumping data.
use std::fmt::Display;
use std::convert::From;
use super::errors::*;

/// Enum which provides all possible output value formats supported by the dump module.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum OutputFormat {
    Hex,
    Decimal,
    Octal,
    Binary,
}

impl From<String> for OutputFormat {
    fn from(format_string: String) -> Self {
        match format_string.to_lowercase().as_ref() {
            "hex" => OutputFormat::Hex,
            "dec" => OutputFormat::Decimal,
            "oct" => OutputFormat::Octal,
            "bin" => OutputFormat::Binary,
            _ => panic!("Invalid output format"),
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct OutputSettings {
    start_address: u32,
    show_address: bool,
    group_size: usize,
    columns: usize,
    show_interpretation: bool,
    output_fmt: OutputFormat,
}

impl OutputSettings {
    pub fn new() -> OutputSettings {
        OutputSettings {
            start_address: 0,
            show_address: true,
            group_size: 1,
            columns: 8,
            show_interpretation: true,
            output_fmt: OutputFormat::Hex,
        }
    }

    pub fn bytes_per_line(&self) -> usize {
        self.columns * self.group_size
    }

    pub fn start_address(mut self, address: u32) -> Self {
        self.start_address = address;
        self
    }

    pub fn show_address(mut self, show: bool) -> Self {
        self.show_address = show;
        self
    }

    pub fn group_size(mut self, size: usize) -> Self {
        self.group_size = size;
        self
    }

    pub fn columns(mut self, columns: usize) -> Self {
        self.columns = columns;
        self
    }

    pub fn show_interpretation(mut self, show: bool) -> Self {
        self.show_interpretation = show;
        self
    }

    pub fn format(mut self, fmt: OutputFormat) -> Self {
        self.output_fmt = fmt;
        self
    }
}

/// The `OutputLine` struct contains all  information needed to dump/output a single line of data.
#[derive(Debug)]
pub struct OutputLine<'a> {
    output_settings: OutputSettings,
    data: &'a [u8],
}

impl<'a> OutputLine<'a> {
    pub fn new(data: &[u8]) -> OutputLine {
        OutputLine {
            output_settings: OutputSettings::new(),
            data: data,
        }
    }

    pub fn format(self, settings: OutputSettings) -> Self {
        OutputLine {
            output_settings: settings,
            data: self.data,
        }
    }

    fn write_address(&self, f: &mut ::fmt::Formatter) -> Result<usize> {
        write!(f, "{:08.X}: ", self.output_settings.start_address)?;
        Ok(10)
    }

    fn write_bytes(&self, f: &mut ::fmt::Formatter) -> Result<usize> {
        let mut byte_count = 0;
        let mut bytes_written = 0;
        for b in self.data.iter() {
            byte_count += 1;
            let is_seperator_necessary = byte_count % self.output_settings.group_size == 0;
            if is_seperator_necessary {
                bytes_written += self.write_formated_byte(f, b)?;
                write!(f, " ")?;
                bytes_written += 1;
            } else {
                bytes_written += self.write_formated_byte(f, b)?;
            }
        }
        Ok(bytes_written)
    }

    fn write_formated_byte(&self, f: &mut ::fmt::Formatter, byte: &u8) -> Result<usize> {
        match self.output_settings.output_fmt {
            OutputFormat::Hex => {
                write!(f, "{:02.X}", byte)?;
                Ok(2)
            }
            OutputFormat::Octal => {
                write!(f, "{:03.o}", byte)?;
                Ok(3)
            }
            OutputFormat::Decimal => {
                write!(f, "{:03}", byte)?;
                Ok(3)
            }
            OutputFormat::Binary => {
                write!(f, "{:08b}", byte)?;
                Ok(8)
            }
        }
    }

    fn write_interpretation(&self, f: &mut ::fmt::Formatter) -> Result<usize> {
        write!(f, "   ");
        for b in self.data.iter() {
            match *b {
                character @ 20u8...126u8 => write!(f, "{}", character as char)?,
                _ => write!(f, "{}", ".")?,
            }
        }
        Ok(self.data.len())
    }
}

impl<'a> ::fmt::Display for OutputLine<'a> {
    fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
        let format_size = |fmt: OutputFormat| match fmt {
            OutputFormat::Hex => 2,
            OutputFormat::Octal => 3,
            OutputFormat::Decimal => 3,
            OutputFormat::Binary => 8,
        };
        if self.output_settings.show_address {
            self.write_address(f);
        }
        // FIXME NiCo: whats the issues here?!
        let bytes_written = self.write_bytes(f).unwrap();
        let expected_length = self.output_settings.columns * self.output_settings.group_size *
                              format_size(self.output_settings.output_fmt) +
                              (self.output_settings.columns);
        let padding = expected_length - bytes_written;
        for i in 0..padding {
            write!(f, " ")?;
        }
        if self.output_settings.show_interpretation {
            self.write_interpretation(f);
        }
        Ok(())
    }
}

mod test {

    use super::*;
    use std::fmt::Write;

    struct TestFixture {
        data: [u8; 8],
        small_data: [u8; 5],
    }

    impl TestFixture {
        fn new() -> Self {
            TestFixture {
                data: [0, 255, 127, 128, 56, 65, 1, 33],
                small_data: [0, 255, 80, 44, 7],
            }
        }

        fn data(&self) -> &[u8] {
            &self.data
        }

        fn small_data(&self) -> &[u8] {
            &self.small_data
        }
    }

    #[test]
    fn output_settings_can_be_constructed() {
        let output_settings = OutputSettings::new();
        assert!(true);
    }

    #[test]
    fn output_settings_builder() {
        let format = OutputFormat::Binary;
        let start_address = 0xFF00AABB;
        let group_size = 2;
        let show_address = false;
        let show_interpretation = false;

        let mut output_settings = OutputSettings::new()
            .format(format)
            .start_address(start_address)
            .group_size(group_size)
            .show_address(show_address)
            .show_interpretation(show_interpretation);

        assert_eq!(output_settings.output_fmt, format);
        assert_eq!(output_settings.start_address, start_address);
        assert_eq!(output_settings.group_size, group_size);
        assert_eq!(output_settings.show_address, show_address);
        assert_eq!(output_settings.show_interpretation, show_interpretation);
    }

    #[test]
    fn output_settings_get_bytes_per_line() {
        {
            let group_size = 8;
            let columns = 2;
            let mut output_settings = OutputSettings::new().columns(columns).group_size(group_size);
            assert_eq!(group_size * columns, output_settings.bytes_per_line())
        }
        {
            let group_size = 5;
            let columns = 4;
            let mut output_settings = OutputSettings::new().columns(columns).group_size(group_size);
            assert_eq!(group_size * columns, output_settings.bytes_per_line())
        }
        {
            let group_size = 9;
            let columns = 4;
            let mut output_settings = OutputSettings::new().columns(columns).group_size(group_size);
            assert_eq!(group_size * columns, output_settings.bytes_per_line())
        }
    }

    #[test]
    fn output_settings_from_string() {
        assert_eq!(OutputFormat::Binary, OutputFormat::from("bin".to_string()));
        assert_eq!(OutputFormat::Hex, OutputFormat::from("hex".to_string()));
        assert_eq!(OutputFormat::Octal, OutputFormat::from("oct".to_string()));
        assert_eq!(OutputFormat::Decimal, OutputFormat::from("dec".to_string()));

        assert_eq!(OutputFormat::Binary, OutputFormat::from("Bin".to_string()));
        assert_eq!(OutputFormat::Hex, OutputFormat::from("hEx".to_string()));
        assert_eq!(OutputFormat::Octal, OutputFormat::from("ocT".to_string()));
        assert_eq!(OutputFormat::Decimal, OutputFormat::from("DEC".to_string()));
    }

    #[test]
    fn outputline_can_be_constructed() {
        let fixture = TestFixture::new();
        let output_line = OutputLine::new(fixture.data());
        assert!(true);
    }

    #[test]
    fn default_output_format_for_a_single_line() {
        let fixture = TestFixture::new();
        let output_line = OutputLine::new(fixture.data());
        let expected_output = "00000000: 00 FF 7F 80 38 41 01 21    ....8A.!";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn default_output_format_for_a_single_line_with_padding() {
        let fixture = TestFixture::new();
        let output_line = OutputLine::new(fixture.small_data());
        let expected_output = "00000000: 00 FF 50 2C 07             ..P,.";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn octal_output_format_on_a_single_line() {
        let fixture = TestFixture::new();
        let output_settings = OutputSettings::new().format(OutputFormat::Octal);
        let output_line = OutputLine::new(fixture.data()).format(output_settings);
        let expected_output = "00000000: 000 377 177 200 070 101 001 041    ....8A.!";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn octal_output_format_for_a_single_line_with_padding() {
        let fixture = TestFixture::new();
        let output_settings = OutputSettings::new().format(OutputFormat::Octal);
        let output_line = OutputLine::new(fixture.small_data()).format(output_settings);
        let expected_output = "00000000: 000 377 120 054 007                ..P,.";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn binary_output_format_on_a_single_line() {
        let fixture = TestFixture::new();
        let output_settings = OutputSettings::new().format(OutputFormat::Binary);
        let output_line = OutputLine::new(fixture.data()).format(output_settings);
        let expected_output = "00000000: 00000000 11111111 01111111 10000000 00111000 01000001 00000001 00100001    ....8A.!";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn binary_output_format_for_a_single_line_with_padding() {
        // small_data: [0, 255, 80, 44, 7],
        let fixture = TestFixture::new();
        let output_settings = OutputSettings::new().format(OutputFormat::Binary);
        let output_line = OutputLine::new(fixture.small_data()).format(output_settings);
        let expected_output = "00000000: 00000000 11111111 01010000 00101100 00000111                               ..P,.";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }
}
<|endoftext|>