<commit_before>use core::ops::DerefMut;

use redox::*;

/* Magic Macros { */
static mut application: *mut Application = 0 as *mut Application;

macro_rules! exec {
    ($cmd:expr) => ({
        unsafe {
            (*application).on_command(&$cmd);
        }
    })
}
/* } Magic Macros */

pub struct Command {
    pub name: String,
    pub main: Box<Fn(&Vec<String>)>
}

impl Command {
    pub fn vec() -> Vec<Command> {
        let mut commands: Vec<Command> = Vec::new();

        commands.push(Command {
            name: "break".to_string(),
            main: box |args: &Vec<String>|{
                unsafe{
                    asm!("int 3" : : : : "intel");
                }
            }
        });

        commands.push(Command {
            name: "echo".to_string(),
            main: box |args: &Vec<String>|{
                let mut echo = String::new();
                let mut first = true;
                for i in 1..args.len() {
                    match args.get(i) {
                        Option::Some(arg) => {
                            if first {
                                first = false
                            }else{
                                echo = echo + " ";
                            }
                            echo = echo + arg;
                        },
                        Option::None => ()
                    }
                }
                println!(echo);
            }
        });

        commands.push(Command {
            name: "open".to_string(),
            main: box |args: &Vec<String>|{
                match args.get(1) {
                    Option::Some(arg) => OpenEvent{ url_string: arg.clone() }.trigger(),
                    Option::None => ()
                }
            }
        });

        commands.push(Command {
            name: "run".to_string(),
            main: box |args: &Vec<String>|{
                match args.get(1) {
                    Option::Some(arg) => {
                        let path = arg.clone();
                        println!("URL: ".to_string() + &path);

                        let mut resource = File::open(&path);

                        let mut vec: Vec<u8> = Vec::new();
                        resource.read_to_end(&mut vec);

                        let commands = String::from_utf8(&vec);
                        for command in commands.split("\n".to_string()) {
                            exec!(command);
                        }
                    },
                    Option::None => ()
                }
            }
        });

        commands.push(Command {
            name: "send".to_string(),
            main: box |args: &Vec<String>|{
                let path;
                match args.get(1) {
                    Option::Some(arg) => path = arg.clone(),
                    Option::None => path = String::new()
                }
                println!("URL: ".to_string() + &path);

                let mut resource = File::open(&path);

                let mut vec: Vec<u8> = Vec::new();
                for i in 2..args.len() {
                    match args.get(i) {
                        Option::Some(arg) => {
                            if i == 2 {
                                vec.push_all(&arg.to_utf8())
                            }else{
                                vec.push_all(&(" ".to_string() + arg).to_utf8())
                            }
                        },
                        Option::None => vec = Vec::new()
                    }
                }
                vec.push_all(&"\r\n\r\n".to_string().to_utf8());

                match resource.write(&vec.as_slice()) {
                    Option::Some(size) => println!("Wrote ".to_string() + size + " bytes"),
                    Option::None => println!("Failed to write".to_string())
                }

                vec = Vec::new();
                match resource.read_to_end(&mut vec) {
                    Option::Some(size) => println!(String::from_utf8(&vec)),
                    Option::None => println!("Failed to read".to_string())
                }
            }
        });

        commands.push(Command {
            name: "url".to_string(),
            main: box |args: &Vec<String>|{
                let path;
                match args.get(1) {
                    Option::Some(arg) => path = arg.clone(),
                    Option::None => path = String::new()
                }
                println!("URL: ".to_string() + &path);

                let mut resource = File::open(&path);

                let mut vec: Vec<u8> = Vec::new();
                match resource.read_to_end(&mut vec) {
                    Option::Some(_) => println!(String::from_utf8(&vec)),
                    Option::None => println!("Failed to read".to_string())
                }
            }
        });

        commands.push(Command {
            name: "url_hex".to_string(),
            main: box |args: &Vec<String>|{
                let path;
                match args.get(1) {
                    Option::Some(arg) => path = arg.clone(),
                    Option::None => path = String::new()
                }
                println!("URL: ".to_string() + &path);

                let mut resource = File::open(&path);

                let mut vec: Vec<u8> = Vec::new();
                match resource.read_to_end(&mut vec) {
                    Option::Some(_) => {
                        let mut line = "HEX:".to_string();
                        for byte in vec.iter() {
                            line = line + ' ' + String::from_num_radix(*byte as usize, 16);
                        }
                        println!(line);
                    },
                    Option::None => println!("Failed to read".to_string())
                }
            }
        });

        return commands;
    }
}

pub struct Variable {
    pub name: String,
    pub value: String
}

pub struct Mode {
    value: bool
}

pub struct Application {
    commands: Vec<Command>,
    variables: Vec<Variable>,
    modes: Vec<Mode>
}

impl Application {
    pub fn new() -> Application {
        return Application {
            commands: Command::vec(),
            variables: Vec::new(),
            modes: Vec::new()
        };
    }

    fn on_command(&mut self, command_string: &String){
        //Comment
        if command_string[0] == '#' {
            return;
        }

        //Show variables
        if *command_string == "$".to_string() {
            let mut variables = String::new();
            for variable in self.variables.iter() {
                variables = variables + '\n' + &variable.name + "=" + &variable.value;
            }
            println!(&variables);
            return;
        }

        //Explode into arguments, replace variables
        let mut args: Vec<String> = Vec::<String>::new();
        for arg in command_string.split(" ".to_string()) {
            if arg.len() > 0 {
                if arg[0] == '$' {
                    let name = arg.substr(1, arg.len() - 1);
                    for variable in self.variables.iter() {
                        if variable.name == name {
                            args.push(variable.value.clone());
                            break;
                        }
                    }
                }else{
                    args.push(arg);
                }
            }
        }

        //Execute commands
        match args.get(0) {
            Option::Some(cmd) => {
                if *cmd == "if".to_string() {
                    let mut value = false;

                    match args.get(1) {
                        Option::Some(left) => match args.get(2) {
                            Option::Some(cmp) => match args.get(3) {
                                Option::Some(right) => {
                                    if *cmp == "==".to_string() {
                                        value = *left == *right;
                                    }else if *cmp == "!=".to_string() {
                                        value = *left != *right;
                                    }else if *cmp == ">".to_string() {
                                        value = left.to_num_signed() > right.to_num_signed();
                                    }else if *cmp == ">=".to_string() {
                                        value = left.to_num_signed() >= right.to_num_signed();
                                    }else if *cmp == "<".to_string() {
                                        value = left.to_num_signed() < right.to_num_signed();
                                    }else if *cmp == "<=".to_string() {
                                        value = left.to_num_signed() <= right.to_num_signed();
                                    }else{
                                        println!(&("Unknown comparison: ".to_string() + cmp));
                                    }
                                },
                                Option::None => ()
                            },
                            Option::None => ()
                        },
                        Option::None => ()
                    }

                    self.modes.insert(0, Mode{
                        value: value
                    });
                    return;
                }

                if *cmd == "else".to_string() {
                    let mut syntax_error = false;
                    match self.modes.get(0) {
                        Option::Some(mode) => mode.value = !mode.value,
                        Option::None => syntax_error = true
                    }
                    if syntax_error {
                        println!(&"Syntax error: else found with no previous if".to_string());
                    }
                    return;
                }

                if *cmd == "fi".to_string() {
                    let mut syntax_error = false;
                    match self.modes.remove(0) {
                        Option::Some(_) => (),
                        Option::None => syntax_error = true
                    }
                    if syntax_error {
                        println!(&"Syntax error: fi found with no previous if".to_string());
                    }
                    return;
                }

                for mode in self.modes.iter() {
                    if ! mode.value {
                        return;
                    }
                }

                //Set variables
                match cmd.find("=".to_string()) {
                    Option::Some(i) => {
                        let name = cmd.substr(0, i);
                        let mut value = cmd.substr(i + 1, cmd.len() - i - 1);

                        if name.len() == 0 {
                            return;
                        }

                        for i in 1..args.len() {
                            match args.get(i) {
                                Option::Some(arg) => value = value + ' ' + arg.clone(),
                                Option::None => ()
                            }
                        }

                        if value.len() == 0 {
                            let mut remove = -1;
                            for i in 0..self.variables.len() {
                                match self.variables.get(i) {
                                    Option::Some(variable) => if variable.name == name {
                                        remove = i as isize;
                                        break;
                                    },
                                    Option::None => break
                                }
                            }

                            if remove >= 0 {
                                self.variables.remove(remove as usize);
                            }
                        }else{
                            for variable in self.variables.iter() {
                                if variable.name == name {
                                    variable.value = value;
                                    return;
                                }
                            }

                            self.variables.push(Variable{
                                name: name,
                                value: value
                            });
                        }
                        return;
                    },
                    Option::None => ()
                }

                //Commands
                for command in self.commands.iter() {
                    if command.name == *cmd {
                        (*command.main)(&args);
                        return;
                    }
                }

                let mut help = "Commands:".to_string();
                for command in self.commands.iter() {
                    help = help + ' ' + &command.name;
                }
                println!(&help);
            },
            Option::None => ()
        }
    }

    fn main(&mut self){
        console_title(&"Terminal".to_string());

        while let Option::Some(command) = readln!() {
            println!("# ".to_string() + &command);
            if command.len() > 0 {
                self.on_command(&command);
            }
        }
    }
}

pub fn main(){
    unsafe {
        let mut app = box Application::new();
        application = app.deref_mut();
        app.main();
    }
}
<commit_msg>Terminal will run given scripts<commit_after>use core::ops::DerefMut;

use redox::*;

/* Magic Macros { */
static mut application: *mut Application = 0 as *mut Application;

macro_rules! exec {
    ($cmd:expr) => ({
        unsafe {
            (*application).on_command(&$cmd);
        }
    })
}
/* } Magic Macros */

pub struct Command {
    pub name: String,
    pub main: Box<Fn(&Vec<String>)>
}

impl Command {
    pub fn vec() -> Vec<Command> {
        let mut commands: Vec<Command> = Vec::new();

        commands.push(Command {
            name: "break".to_string(),
            main: box |args: &Vec<String>|{
                unsafe{
                    asm!("int 3" : : : : "intel");
                }
            }
        });

        commands.push(Command {
            name: "echo".to_string(),
            main: box |args: &Vec<String>|{
                let mut echo = String::new();
                let mut first = true;
                for i in 1..args.len() {
                    match args.get(i) {
                        Option::Some(arg) => {
                            if first {
                                first = false
                            }else{
                                echo = echo + " ";
                            }
                            echo = echo + arg;
                        },
                        Option::None => ()
                    }
                }
                println!(echo);
            }
        });

        commands.push(Command {
            name: "open".to_string(),
            main: box |args: &Vec<String>|{
                match args.get(1) {
                    Option::Some(arg) => OpenEvent{ url_string: arg.clone() }.trigger(),
                    Option::None => ()
                }
            }
        });

        commands.push(Command {
            name: "run".to_string(),
            main: box |args: &Vec<String>|{
                match args.get(1) {
                    Option::Some(arg) => {
                        let path = arg.clone();
                        println!("URL: ".to_string() + &path);

                        let mut resource = File::open(&path);

                        let mut vec: Vec<u8> = Vec::new();
                        resource.read_to_end(&mut vec);

                        let commands = String::from_utf8(&vec);
                        for command in commands.split("\n".to_string()) {
                            exec!(command);
                        }
                    },
                    Option::None => ()
                }
            }
        });

        commands.push(Command {
            name: "send".to_string(),
            main: box |args: &Vec<String>|{
                let path;
                match args.get(1) {
                    Option::Some(arg) => path = arg.clone(),
                    Option::None => path = String::new()
                }
                println!("URL: ".to_string() + &path);

                let mut resource = File::open(&path);

                let mut vec: Vec<u8> = Vec::new();
                for i in 2..args.len() {
                    match args.get(i) {
                        Option::Some(arg) => {
                            if i == 2 {
                                vec.push_all(&arg.to_utf8())
                            }else{
                                vec.push_all(&(" ".to_string() + arg).to_utf8())
                            }
                        },
                        Option::None => vec = Vec::new()
                    }
                }
                vec.push_all(&"\r\n\r\n".to_string().to_utf8());

                match resource.write(&vec.as_slice()) {
                    Option::Some(size) => println!("Wrote ".to_string() + size + " bytes"),
                    Option::None => println!("Failed to write".to_string())
                }

                vec = Vec::new();
                match resource.read_to_end(&mut vec) {
                    Option::Some(size) => println!(String::from_utf8(&vec)),
                    Option::None => println!("Failed to read".to_string())
                }
            }
        });

        commands.push(Command {
            name: "url".to_string(),
            main: box |args: &Vec<String>|{
                let path;
                match args.get(1) {
                    Option::Some(arg) => path = arg.clone(),
                    Option::None => path = String::new()
                }
                println!("URL: ".to_string() + &path);

                let mut resource = File::open(&path);

                let mut vec: Vec<u8> = Vec::new();
                match resource.read_to_end(&mut vec) {
                    Option::Some(_) => println!(String::from_utf8(&vec)),
                    Option::None => println!("Failed to read".to_string())
                }
            }
        });

        commands.push(Command {
            name: "url_hex".to_string(),
            main: box |args: &Vec<String>|{
                let path;
                match args.get(1) {
                    Option::Some(arg) => path = arg.clone(),
                    Option::None => path = String::new()
                }
                println!("URL: ".to_string() + &path);

                let mut resource = File::open(&path);

                let mut vec: Vec<u8> = Vec::new();
                match resource.read_to_end(&mut vec) {
                    Option::Some(_) => {
                        let mut line = "HEX:".to_string();
                        for byte in vec.iter() {
                            line = line + ' ' + String::from_num_radix(*byte as usize, 16);
                        }
                        println!(line);
                    },
                    Option::None => println!("Failed to read".to_string())
                }
            }
        });

        return commands;
    }
}

pub struct Variable {
    pub name: String,
    pub value: String
}

pub struct Mode {
    value: bool
}

pub struct Application {
    commands: Vec<Command>,
    variables: Vec<Variable>,
    modes: Vec<Mode>
}

impl Application {
    pub fn new() -> Application {
        return Application {
            commands: Command::vec(),
            variables: Vec::new(),
            modes: Vec::new()
        };
    }

    fn on_command(&mut self, command_string: &String){
        //Comment
        if command_string[0] == '#' {
            return;
        }

        //Show variables
        if *command_string == "$".to_string() {
            let mut variables = String::new();
            for variable in self.variables.iter() {
                variables = variables + '\n' + &variable.name + "=" + &variable.value;
            }
            println!(&variables);
            return;
        }

        //Explode into arguments, replace variables
        let mut args: Vec<String> = Vec::<String>::new();
        for arg in command_string.split(" ".to_string()) {
            if arg.len() > 0 {
                if arg[0] == '$' {
                    let name = arg.substr(1, arg.len() - 1);
                    for variable in self.variables.iter() {
                        if variable.name == name {
                            args.push(variable.value.clone());
                            break;
                        }
                    }
                }else{
                    args.push(arg);
                }
            }
        }

        //Execute commands
        match args.get(0) {
            Option::Some(cmd) => {
                if *cmd == "if".to_string() {
                    let mut value = false;

                    match args.get(1) {
                        Option::Some(left) => match args.get(2) {
                            Option::Some(cmp) => match args.get(3) {
                                Option::Some(right) => {
                                    if *cmp == "==".to_string() {
                                        value = *left == *right;
                                    }else if *cmp == "!=".to_string() {
                                        value = *left != *right;
                                    }else if *cmp == ">".to_string() {
                                        value = left.to_num_signed() > right.to_num_signed();
                                    }else if *cmp == ">=".to_string() {
                                        value = left.to_num_signed() >= right.to_num_signed();
                                    }else if *cmp == "<".to_string() {
                                        value = left.to_num_signed() < right.to_num_signed();
                                    }else if *cmp == "<=".to_string() {
                                        value = left.to_num_signed() <= right.to_num_signed();
                                    }else{
                                        println!(&("Unknown comparison: ".to_string() + cmp));
                                    }
                                },
                                Option::None => ()
                            },
                            Option::None => ()
                        },
                        Option::None => ()
                    }

                    self.modes.insert(0, Mode{
                        value: value
                    });
                    return;
                }

                if *cmd == "else".to_string() {
                    let mut syntax_error = false;
                    match self.modes.get(0) {
                        Option::Some(mode) => mode.value = !mode.value,
                        Option::None => syntax_error = true
                    }
                    if syntax_error {
                        println!(&"Syntax error: else found with no previous if".to_string());
                    }
                    return;
                }

                if *cmd == "fi".to_string() {
                    let mut syntax_error = false;
                    match self.modes.remove(0) {
                        Option::Some(_) => (),
                        Option::None => syntax_error = true
                    }
                    if syntax_error {
                        println!(&"Syntax error: fi found with no previous if".to_string());
                    }
                    return;
                }

                for mode in self.modes.iter() {
                    if ! mode.value {
                        return;
                    }
                }

                //Set variables
                match cmd.find("=".to_string()) {
                    Option::Some(i) => {
                        let name = cmd.substr(0, i);
                        let mut value = cmd.substr(i + 1, cmd.len() - i - 1);

                        if name.len() == 0 {
                            return;
                        }

                        for i in 1..args.len() {
                            match args.get(i) {
                                Option::Some(arg) => value = value + ' ' + arg.clone(),
                                Option::None => ()
                            }
                        }

                        if value.len() == 0 {
                            let mut remove = -1;
                            for i in 0..self.variables.len() {
                                match self.variables.get(i) {
                                    Option::Some(variable) => if variable.name == name {
                                        remove = i as isize;
                                        break;
                                    },
                                    Option::None => break
                                }
                            }

                            if remove >= 0 {
                                self.variables.remove(remove as usize);
                            }
                        }else{
                            for variable in self.variables.iter() {
                                if variable.name == name {
                                    variable.value = value;
                                    return;
                                }
                            }

                            self.variables.push(Variable{
                                name: name,
                                value: value
                            });
                        }
                        return;
                    },
                    Option::None => ()
                }

                //Commands
                for command in self.commands.iter() {
                    if command.name == *cmd {
                        (*command.main)(&args);
                        return;
                    }
                }

                let mut help = "Commands:".to_string();
                for command in self.commands.iter() {
                    help = help + ' ' + &command.name;
                }
                println!(&help);
            },
            Option::None => ()
        }
    }

    fn main(&mut self){
        console_title(&"Terminal".to_string());

        if let Option::Some(arg) = args().get(1) {
            let command = "run ".to_string() + arg;
            println!("# ".to_string() + &command);
            self.on_command(&command);
        }

        while let Option::Some(command) = readln!() {
            println!("# ".to_string() + &command);
            if command.len() > 0 {
                self.on_command(&command);
            }
        }
    }
}

pub fn main(){
    unsafe {
        let mut app = box Application::new();
        application = app.deref_mut();
        app.main();
    }
}
<|endoftext|>


<commit_before><commit_msg>Create main.rs<commit_after>extern crate ws;
extern crate serde;
extern crate serde_json;

use serde_json::Value;
use serde_json::value::Map;

struct BenchHandler {
    ws: ws::Sender,
    count: u32
}

impl ws::Handler for BenchHandler {
    fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> {
        if let Some((Some(msg_type), payload)) = msg.into_text().ok()
            .map(|v| v.as_str().to_owned())
            .and_then(|body: String| serde_json::from_str(body.as_str()).ok())
            .and_then(|j: Value| j.as_object().map(move |obj: &Map<String, Value>| {
                let t = obj.get("type").and_then(|t| t.as_str()).map(|s| s.to_owned());
                let p: Value = obj.get("payload").unwrap_or(&Value::Null).clone();
                (t, p)
            })) {
                match msg_type.as_ref() {
                    "echo" => {
                        try!(self.ws.send(format!("{}", payload)));
                    },
                    "broadcast" => {
                        try!(self.ws.broadcast(format!("{}", payload)));
                        try!(self.ws.send(format!("{{\"type\": \"broadcastResult\", \"listenCount\": {}, \"payload\": {}}}", self.count, payload)))
                    },
                    _ => {}
                };
            };
        Ok(())
    }

    fn on_open(&mut self, _: ws::Handshake) -> ws::Result<()> {
        self.count += 1;
        println!("Connection Open! {}", self.count);
        Ok(())
    }

    fn on_close(&mut self,_: ws::CloseCode, _: &str) {
        self.count -= 1;
        println!("Connection Closed! {}", self.count);
    }
}

fn main() {
    if let Err(error) = ws::listen("127.0.0.1:3012", |out| {
        BenchHandler { ws: out, count: 0 }
    }) {
        println!("Failed to create WebSocket due to {:?}", error);
    }
}
<|endoftext|>


<commit_before><commit_msg>Make `write` more general and get better code reuse.<commit_after><|endoftext|>


<commit_before><commit_msg>Remove hint about secret number<commit_after><|endoftext|>


<commit_before><commit_msg>Docs for metric sinks and formatters<commit_after><|endoftext|>


<commit_before><commit_msg>Auto merge of #382 - sru:tests, r=kbknapp<commit_after><|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(rustc_private)]

extern crate rustc;
extern crate rustc_driver;
extern crate rustc_lint;
extern crate rustc_metadata;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate syntax;

use rustc::session::{build_session, Session};
use rustc::session::config::{basic_options, Input,
                             OutputType, OutputTypes};
use rustc_driver::driver::{compile_input, CompileController};
use rustc_metadata::cstore::CStore;
use rustc_errors::registry::Registry;
use syntax::codemap::FileName;
use rustc_codegen_utils::codegen_backend::CodegenBackend;

use std::path::PathBuf;
use std::rc::Rc;

fn main() {
    let src = r#"
    fn main() {}
    "#;

    let args: Vec<String> = std::env::args().collect();

    if args.len() < 4 {
        panic!("expected rustc path");
    }

    let tmpdir = PathBuf::from(&args[1]);

    let mut sysroot = PathBuf::from(&args[3]);
    sysroot.pop();
    sysroot.pop();

    compile(src.to_string(), tmpdir.join("out"), sysroot.clone());

    compile(src.to_string(), tmpdir.join("out"), sysroot.clone());
}

fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>, Box<CodegenBackend>) {
    let mut opts = basic_options();
    opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
    opts.maybe_sysroot = Some(sysroot);
    if let Ok(linker) = std::env::var("RUSTC_LINKER") {
        opts.cg.linker = Some(linker.into());
    }

    let descriptions = Registry::new(&rustc::DIAGNOSTICS);
    let sess = build_session(opts, None, descriptions);
    let codegen_backend = rustc_driver::get_codegen_backend(&sess);
    let cstore = Rc::new(CStore::new(codegen_backend.metadata_loader()));
    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
    (sess, cstore, codegen_backend)
}

fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
    syntax::with_globals(|| {
        let (sess, cstore, codegen_backend) = basic_sess(sysroot);
        let control = CompileController::basic();
        let input = Input::Str { name: FileName::Anon, input: code };
        let _ = compile_input(
            codegen_backend,
            &sess,
            &cstore,
            &None,
            &input,
            &None,
            &Some(output),
            None,
            &control
        );
    });
}
<commit_msg>Create thread-pool<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(rustc_private)]

extern crate rustc;
extern crate rustc_driver;
extern crate rustc_lint;
extern crate rustc_metadata;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate syntax;

use rustc::session::{build_session, Session};
use rustc::session::config::{basic_options, Input, Options,
                             OutputType, OutputTypes};
use rustc_driver::driver::{self, compile_input, CompileController};
use rustc_metadata::cstore::CStore;
use rustc_errors::registry::Registry;
use syntax::codemap::FileName;
use rustc_codegen_utils::codegen_backend::CodegenBackend;

use std::path::PathBuf;
use std::rc::Rc;

fn main() {
    let src = r#"
    fn main() {}
    "#;

    let args: Vec<String> = std::env::args().collect();

    if args.len() < 4 {
        panic!("expected rustc path");
    }

    let tmpdir = PathBuf::from(&args[1]);

    let mut sysroot = PathBuf::from(&args[3]);
    sysroot.pop();
    sysroot.pop();

    compile(src.to_string(), tmpdir.join("out"), sysroot.clone());

    compile(src.to_string(), tmpdir.join("out"), sysroot.clone());
}

fn basic_sess(opts: Options) -> (Session, Rc<CStore>, Box<CodegenBackend>) {
    let descriptions = Registry::new(&rustc::DIAGNOSTICS);
    let sess = build_session(opts, None, descriptions);
    let codegen_backend = rustc_driver::get_codegen_backend(&sess);
    let cstore = Rc::new(CStore::new(codegen_backend.metadata_loader()));
    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
    (sess, cstore, codegen_backend)
}

fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
    syntax::with_globals(|| {
        let mut opts = basic_options();
        opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
        opts.maybe_sysroot = Some(sysroot);
        if let Ok(linker) = std::env::var("RUSTC_LINKER") {
            opts.cg.linker = Some(linker.into());
        }
        driver::spawn_thread_pool(opts, |opts| {
            let (sess, cstore, codegen_backend) = basic_sess(opts);
            let control = CompileController::basic();
            let input = Input::Str { name: FileName::Anon, input: code };
            let _ = compile_input(
                codegen_backend,
                &sess,
                &cstore,
                &None,
                &input,
                &None,
                &Some(output),
                None,
                &control
            );
        });
    });
}
<|endoftext|>


<commit_before><commit_msg>72 times faster<commit_after><|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

//! The filesystem abstraction code
//!
//! # Problem
//!
//! First, we had a compiletime backend for the store. This means that the actual filesystem
//! operations were compiled into the store either as real filesystem operations (in a normal debug
//! or release build) but as a in-memory variant in the 'test' case.
//! So tests did not hit the filesystem when running.
//! This gave us us the possibility to run tests concurrently with multiple
//! stores that did not interfere with eachother.
//!
//! This approach worked perfectly well until we started to test not the
//! store itself but crates that depend on the store implementation.
//! When running tests in a crate that depends on the store, the store
//! itself was compiled with the filesystem-hitting-backend.
//! This was problematic, as tests could not be implemented without hitting
//! the filesystem.
//!
//! Hence we implemented this.
//!
//! # Implementation
//!
//! The filesystem is abstracted via a trait `FileAbstraction` which
//! contains the essential functions for working with the filesystem.
//!
//! Two implementations are provided in the code:
//!
//! * FSFileAbstraction
//! * InMemoryFileAbstraction
//!
//! whereas the first actually works with the filesystem and the latter
//! works with an in-memory HashMap that is used as filesystem.
//!
//! Further, the trait `FileAbstractionInstance` was introduced for
//! functions which are executed on actual instances of content from the
//! filesystem, which was previousely tied into the general abstraction
//! mechanism.
//!
//! So, the `FileAbstraction` trait is for working with the filesystem, the
//! `FileAbstractionInstance` trait is for working with instances of content
//! from the filesystem (speak: actual Files).
//!
//! In case of the `FSFileAbstractionInstance`, which is the implementation
//! of the `FileAbstractionInstance` for the actual filesystem-hitting code,
//! the underlying resource is managed like with the old code before.
//! The `InMemoryFileAbstractionInstance` implementation is corrosponding to
//! the `InMemoryFileAbstraction` implementation - for the in-memory
//! "filesystem".
//!
//! The implementation of the `get_file_content()` function had to be
//! changed to return a `String` rather than a `&mut Read` because of
//! lifetime issues.
//! This change is store-internally and the API of the store itself was not
//! affected.
//!

use std::path::PathBuf;
use std::fmt::Debug;

use error::StoreError as SE;

pub use self::fs::FSFileAbstraction;
pub use self::fs::FSFileAbstractionInstance;
pub use self::inmemory::InMemoryFileAbstraction;
pub use self::inmemory::InMemoryFileAbstractionInstance;

// TODO:
// This whole thing can be written better with a trait based mechanism that is embedded into the
// store. However it would mean rewriting most things to be generic which can be a pain in the ass.

/// An abstraction trait over filesystem actions
pub trait FileAbstraction : Debug {
    fn remove_file(&self, path: &PathBuf) -> Result<(), SE>;
    fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE>;
    fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE>;
    fn create_dir_all(&self, _: &PathBuf) -> Result<(), SE>;

    fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance>;
}

/// An abstraction trait over actions on files
pub trait FileAbstractionInstance : Debug {
    fn get_file_content(&mut self) -> Result<String, SE>;
    fn write_file_content(&mut self, buf: &[u8]) -> Result<(), SE>;
}

mod fs {
    use std::fs::{File, OpenOptions, create_dir_all, remove_file, copy, rename};
    use std::io::{Seek, SeekFrom, Read};
    use std::path::{Path, PathBuf};

    use error::{MapErrInto, StoreError as SE, StoreErrorKind as SEK};

    use super::FileAbstraction;
    use super::FileAbstractionInstance;

    #[derive(Debug)]
    pub enum FSFileAbstractionInstance {
        Absent(PathBuf),
        File(File, PathBuf)
    }

    impl FileAbstractionInstance for FSFileAbstractionInstance {

        /**
         * Get the content behind this file
         */
        fn get_file_content(&mut self) -> Result<String, SE> {
            debug!("Getting lazy file: {:?}", self);
            let (file, path) = match *self {
                FSFileAbstractionInstance::File(ref mut f, _) => return {
                    // We seek to the beginning of the file since we expect each
                    // access to the file to be in a different context
                    try!(f.seek(SeekFrom::Start(0))
                        .map_err_into(SEK::FileNotSeeked));

                    let mut s = String::new();
                    f.read_to_string(&mut s)
                        .map_err_into(SEK::IoError)
                        .map(|_| s)
                },
                FSFileAbstractionInstance::Absent(ref p) =>
                    (try!(open_file(p).map_err_into(SEK::FileNotFound)), p.clone()),
            };
            *self = FSFileAbstractionInstance::File(file, path);
            if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
                let mut s = String::new();
                f.read_to_string(&mut s)
                    .map_err_into(SEK::IoError)
                    .map(|_| s)
            } else {
                unreachable!()
            }
        }

        /**
         * Write the content of this file
         */
        fn write_file_content(&mut self, buf: &[u8]) -> Result<(), SE> {
            use std::io::Write;
            let (file, path) = match *self {
                FSFileAbstractionInstance::File(ref mut f, _) => return {
                    // We seek to the beginning of the file since we expect each
                    // access to the file to be in a different context
                    try!(f.seek(SeekFrom::Start(0))
                        .map_err_into(SEK::FileNotCreated));
                    f.write_all(buf).map_err_into(SEK::FileNotWritten)
                },
                FSFileAbstractionInstance::Absent(ref p) =>
                    (try!(create_file(p).map_err_into(SEK::FileNotCreated)), p.clone()),
            };
            *self = FSFileAbstractionInstance::File(file, path);
            if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
                return f.write_all(buf).map_err_into(SEK::FileNotWritten);
            }
            unreachable!();
        }

    }

    /// `FSFileAbstraction` state type
    ///
    /// A lazy file is either absent, but a path to it is available, or it is present.
    #[derive(Debug)]
    pub struct FSFileAbstraction {
    }

    impl FSFileAbstraction {
        pub fn new() -> FSFileAbstraction {
            FSFileAbstraction { }
        }
    }

    impl FileAbstraction for FSFileAbstraction {

        fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
            remove_file(path).map_err_into(SEK::FileNotRemoved)
        }

        fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            copy(from, to).map_err_into(SEK::FileNotCopied).map(|_| ())
        }

        fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            rename(from, to).map_err_into(SEK::FileNotRenamed)
        }

        fn create_dir_all(&self, path: &PathBuf) -> Result<(), SE> {
            create_dir_all(path).map_err_into(SEK::DirNotCreated)
        }

        fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
            Box::new(FSFileAbstractionInstance::Absent(p))
        }
    }

    fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
        OpenOptions::new().write(true).read(true).open(p)
    }

    fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
        if let Some(parent) = p.as_ref().parent() {
            debug!("Implicitely creating directory: {:?}", parent);
            if let Err(e) = create_dir_all(parent) {
                return Err(e);
            }
        }
        OpenOptions::new().write(true).read(true).create(true).open(p)
    }

}

mod inmemory {
    use error::StoreError as SE;
    use error::StoreErrorKind as SEK;
    use std::io::Read;
    use std::io::Cursor;
    use std::path::PathBuf;
    use std::collections::HashMap;
    use std::sync::Mutex;
    use std::cell::RefCell;
    use std::sync::Arc;

    use libimagerror::into::IntoError;

    use super::FileAbstraction;
    use super::FileAbstractionInstance;
    use error::MapErrInto;

    type Backend = Arc<Mutex<RefCell<HashMap<PathBuf, Cursor<Vec<u8>>>>>>;

    /// `FileAbstraction` type, this is the Test version!
    ///
    /// A lazy file is either absent, but a path to it is available, or it is present.
    #[derive(Debug)]
    pub struct InMemoryFileAbstractionInstance {
        fs_abstraction: Backend,
        absent_path: PathBuf,
    }

    impl InMemoryFileAbstractionInstance {

        pub fn new(fs: Backend, pb: PathBuf) -> InMemoryFileAbstractionInstance {
            InMemoryFileAbstractionInstance {
                fs_abstraction: fs,
                absent_path: pb
            }
        }

    }

    impl FileAbstractionInstance for InMemoryFileAbstractionInstance {

        /**
         * Get the mutable file behind a InMemoryFileAbstraction object
         */
        fn get_file_content(&mut self) -> Result<String, SE> {
            debug!("Getting lazy file: {:?}", self);

            let p = self.absent_path.clone();
            match self.fs_abstraction.lock() {
                Ok(mut mtx) => {
                    mtx.get_mut()
                        .get_mut(&p)
                        .ok_or(SEK::FileNotFound.into_error())
                        .and_then(|t| {
                            let mut s = String::new();
                            t.read_to_string(&mut s)
                                .map_err_into(SEK::IoError)
                                .map(|_| s)
                        })
                }

                Err(_) => Err(SEK::LockError.into_error())
            }
        }

        fn write_file_content(&mut self, buf: &[u8]) -> Result<(), SE> {
            match *self {
                InMemoryFileAbstractionInstance { ref absent_path, .. } => {
                    let mut mtx = self.fs_abstraction.lock().expect("Locking Mutex failed");
                    let mut backend = mtx.get_mut();

                    if let Some(ref mut cur) = backend.get_mut(absent_path) {
                        let mut vec = cur.get_mut();
                        vec.clear();
                        vec.extend_from_slice(buf);
                        return Ok(());
                    }
                    let vec = Vec::from(buf);
                    backend.insert(absent_path.clone(), Cursor::new(vec));
                    return Ok(());
                },
            };
        }
    }

    #[derive(Debug)]
    pub struct InMemoryFileAbstraction {
        virtual_filesystem: Backend,
    }

    impl InMemoryFileAbstraction {

        pub fn new() -> InMemoryFileAbstraction {
            InMemoryFileAbstraction {
                virtual_filesystem: Arc::new(Mutex::new(RefCell::new(HashMap::new()))),
            }
        }

        pub fn backend(&self) -> &Backend {
            &self.virtual_filesystem
        }

    }

    impl FileAbstraction for InMemoryFileAbstraction {

        fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
            debug!("Removing: {:?}", path);
            self.backend()
                .lock()
                .expect("Locking Mutex failed")
                .get_mut()
                .remove(path)
                .map(|_| ())
                .ok_or(SEK::FileNotFound.into_error())
        }

        fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            debug!("Copying : {:?} -> {:?}", from, to);
            let mut mtx = self.backend().lock().expect("Locking Mutex failed");
            let mut backend = mtx.get_mut();

            let a = try!(backend.get(from).cloned().ok_or(SEK::FileNotFound.into_error()));
            backend.insert(to.clone(), a);
            debug!("Copying: {:?} -> {:?} worked", from, to);
            Ok(())
        }

        fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            debug!("Renaming: {:?} -> {:?}", from, to);
            let mut mtx = self.backend().lock().expect("Locking Mutex failed");
            let mut backend = mtx.get_mut();

            let a = try!(backend.get(from).cloned().ok_or(SEK::FileNotFound.into_error()));
            backend.insert(to.clone(), a);
            debug!("Renaming: {:?} -> {:?} worked", from, to);
            Ok(())
        }

        fn create_dir_all(&self, _: &PathBuf) -> Result<(), SE> {
            Ok(())
        }

        fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
            Box::new(InMemoryFileAbstractionInstance::new(self.backend().clone(), p))
        }
    }

}

#[cfg(test)]
mod test {
    use super::FileAbstractionInstance;
    use super::inmemory::InMemoryFileAbstraction;
    use super::inmemory::InMemoryFileAbstractionInstance;
    use std::path::PathBuf;

    #[test]
    fn lazy_file() {
        let fs = InMemoryFileAbstraction::new();

        let mut path = PathBuf::from("/tests");
        path.set_file_name("test1");
        let mut lf = InMemoryFileAbstractionInstance::new(fs.backend().clone(), path);
        lf.write_file_content(b"Hello World").unwrap();
        let bah = lf.get_file_content().unwrap();
        assert_eq!(bah, "Hello World");
    }

}
<commit_msg>Remove "TODO"-comment<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

//! The filesystem abstraction code
//!
//! # Problem
//!
//! First, we had a compiletime backend for the store. This means that the actual filesystem
//! operations were compiled into the store either as real filesystem operations (in a normal debug
//! or release build) but as a in-memory variant in the 'test' case.
//! So tests did not hit the filesystem when running.
//! This gave us us the possibility to run tests concurrently with multiple
//! stores that did not interfere with eachother.
//!
//! This approach worked perfectly well until we started to test not the
//! store itself but crates that depend on the store implementation.
//! When running tests in a crate that depends on the store, the store
//! itself was compiled with the filesystem-hitting-backend.
//! This was problematic, as tests could not be implemented without hitting
//! the filesystem.
//!
//! Hence we implemented this.
//!
//! # Implementation
//!
//! The filesystem is abstracted via a trait `FileAbstraction` which
//! contains the essential functions for working with the filesystem.
//!
//! Two implementations are provided in the code:
//!
//! * FSFileAbstraction
//! * InMemoryFileAbstraction
//!
//! whereas the first actually works with the filesystem and the latter
//! works with an in-memory HashMap that is used as filesystem.
//!
//! Further, the trait `FileAbstractionInstance` was introduced for
//! functions which are executed on actual instances of content from the
//! filesystem, which was previousely tied into the general abstraction
//! mechanism.
//!
//! So, the `FileAbstraction` trait is for working with the filesystem, the
//! `FileAbstractionInstance` trait is for working with instances of content
//! from the filesystem (speak: actual Files).
//!
//! In case of the `FSFileAbstractionInstance`, which is the implementation
//! of the `FileAbstractionInstance` for the actual filesystem-hitting code,
//! the underlying resource is managed like with the old code before.
//! The `InMemoryFileAbstractionInstance` implementation is corrosponding to
//! the `InMemoryFileAbstraction` implementation - for the in-memory
//! "filesystem".
//!
//! The implementation of the `get_file_content()` function had to be
//! changed to return a `String` rather than a `&mut Read` because of
//! lifetime issues.
//! This change is store-internally and the API of the store itself was not
//! affected.
//!

use std::path::PathBuf;
use std::fmt::Debug;

use error::StoreError as SE;

pub use self::fs::FSFileAbstraction;
pub use self::fs::FSFileAbstractionInstance;
pub use self::inmemory::InMemoryFileAbstraction;
pub use self::inmemory::InMemoryFileAbstractionInstance;

/// An abstraction trait over filesystem actions
pub trait FileAbstraction : Debug {
    fn remove_file(&self, path: &PathBuf) -> Result<(), SE>;
    fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE>;
    fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE>;
    fn create_dir_all(&self, _: &PathBuf) -> Result<(), SE>;

    fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance>;
}

/// An abstraction trait over actions on files
pub trait FileAbstractionInstance : Debug {
    fn get_file_content(&mut self) -> Result<String, SE>;
    fn write_file_content(&mut self, buf: &[u8]) -> Result<(), SE>;
}

mod fs {
    use std::fs::{File, OpenOptions, create_dir_all, remove_file, copy, rename};
    use std::io::{Seek, SeekFrom, Read};
    use std::path::{Path, PathBuf};

    use error::{MapErrInto, StoreError as SE, StoreErrorKind as SEK};

    use super::FileAbstraction;
    use super::FileAbstractionInstance;

    #[derive(Debug)]
    pub enum FSFileAbstractionInstance {
        Absent(PathBuf),
        File(File, PathBuf)
    }

    impl FileAbstractionInstance for FSFileAbstractionInstance {

        /**
         * Get the content behind this file
         */
        fn get_file_content(&mut self) -> Result<String, SE> {
            debug!("Getting lazy file: {:?}", self);
            let (file, path) = match *self {
                FSFileAbstractionInstance::File(ref mut f, _) => return {
                    // We seek to the beginning of the file since we expect each
                    // access to the file to be in a different context
                    try!(f.seek(SeekFrom::Start(0))
                        .map_err_into(SEK::FileNotSeeked));

                    let mut s = String::new();
                    f.read_to_string(&mut s)
                        .map_err_into(SEK::IoError)
                        .map(|_| s)
                },
                FSFileAbstractionInstance::Absent(ref p) =>
                    (try!(open_file(p).map_err_into(SEK::FileNotFound)), p.clone()),
            };
            *self = FSFileAbstractionInstance::File(file, path);
            if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
                let mut s = String::new();
                f.read_to_string(&mut s)
                    .map_err_into(SEK::IoError)
                    .map(|_| s)
            } else {
                unreachable!()
            }
        }

        /**
         * Write the content of this file
         */
        fn write_file_content(&mut self, buf: &[u8]) -> Result<(), SE> {
            use std::io::Write;
            let (file, path) = match *self {
                FSFileAbstractionInstance::File(ref mut f, _) => return {
                    // We seek to the beginning of the file since we expect each
                    // access to the file to be in a different context
                    try!(f.seek(SeekFrom::Start(0))
                        .map_err_into(SEK::FileNotCreated));
                    f.write_all(buf).map_err_into(SEK::FileNotWritten)
                },
                FSFileAbstractionInstance::Absent(ref p) =>
                    (try!(create_file(p).map_err_into(SEK::FileNotCreated)), p.clone()),
            };
            *self = FSFileAbstractionInstance::File(file, path);
            if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
                return f.write_all(buf).map_err_into(SEK::FileNotWritten);
            }
            unreachable!();
        }

    }

    /// `FSFileAbstraction` state type
    ///
    /// A lazy file is either absent, but a path to it is available, or it is present.
    #[derive(Debug)]
    pub struct FSFileAbstraction {
    }

    impl FSFileAbstraction {
        pub fn new() -> FSFileAbstraction {
            FSFileAbstraction { }
        }
    }

    impl FileAbstraction for FSFileAbstraction {

        fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
            remove_file(path).map_err_into(SEK::FileNotRemoved)
        }

        fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            copy(from, to).map_err_into(SEK::FileNotCopied).map(|_| ())
        }

        fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            rename(from, to).map_err_into(SEK::FileNotRenamed)
        }

        fn create_dir_all(&self, path: &PathBuf) -> Result<(), SE> {
            create_dir_all(path).map_err_into(SEK::DirNotCreated)
        }

        fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
            Box::new(FSFileAbstractionInstance::Absent(p))
        }
    }

    fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
        OpenOptions::new().write(true).read(true).open(p)
    }

    fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
        if let Some(parent) = p.as_ref().parent() {
            debug!("Implicitely creating directory: {:?}", parent);
            if let Err(e) = create_dir_all(parent) {
                return Err(e);
            }
        }
        OpenOptions::new().write(true).read(true).create(true).open(p)
    }

}

mod inmemory {
    use error::StoreError as SE;
    use error::StoreErrorKind as SEK;
    use std::io::Read;
    use std::io::Cursor;
    use std::path::PathBuf;
    use std::collections::HashMap;
    use std::sync::Mutex;
    use std::cell::RefCell;
    use std::sync::Arc;

    use libimagerror::into::IntoError;

    use super::FileAbstraction;
    use super::FileAbstractionInstance;
    use error::MapErrInto;

    type Backend = Arc<Mutex<RefCell<HashMap<PathBuf, Cursor<Vec<u8>>>>>>;

    /// `FileAbstraction` type, this is the Test version!
    ///
    /// A lazy file is either absent, but a path to it is available, or it is present.
    #[derive(Debug)]
    pub struct InMemoryFileAbstractionInstance {
        fs_abstraction: Backend,
        absent_path: PathBuf,
    }

    impl InMemoryFileAbstractionInstance {

        pub fn new(fs: Backend, pb: PathBuf) -> InMemoryFileAbstractionInstance {
            InMemoryFileAbstractionInstance {
                fs_abstraction: fs,
                absent_path: pb
            }
        }

    }

    impl FileAbstractionInstance for InMemoryFileAbstractionInstance {

        /**
         * Get the mutable file behind a InMemoryFileAbstraction object
         */
        fn get_file_content(&mut self) -> Result<String, SE> {
            debug!("Getting lazy file: {:?}", self);

            let p = self.absent_path.clone();
            match self.fs_abstraction.lock() {
                Ok(mut mtx) => {
                    mtx.get_mut()
                        .get_mut(&p)
                        .ok_or(SEK::FileNotFound.into_error())
                        .and_then(|t| {
                            let mut s = String::new();
                            t.read_to_string(&mut s)
                                .map_err_into(SEK::IoError)
                                .map(|_| s)
                        })
                }

                Err(_) => Err(SEK::LockError.into_error())
            }
        }

        fn write_file_content(&mut self, buf: &[u8]) -> Result<(), SE> {
            match *self {
                InMemoryFileAbstractionInstance { ref absent_path, .. } => {
                    let mut mtx = self.fs_abstraction.lock().expect("Locking Mutex failed");
                    let mut backend = mtx.get_mut();

                    if let Some(ref mut cur) = backend.get_mut(absent_path) {
                        let mut vec = cur.get_mut();
                        vec.clear();
                        vec.extend_from_slice(buf);
                        return Ok(());
                    }
                    let vec = Vec::from(buf);
                    backend.insert(absent_path.clone(), Cursor::new(vec));
                    return Ok(());
                },
            };
        }
    }

    #[derive(Debug)]
    pub struct InMemoryFileAbstraction {
        virtual_filesystem: Backend,
    }

    impl InMemoryFileAbstraction {

        pub fn new() -> InMemoryFileAbstraction {
            InMemoryFileAbstraction {
                virtual_filesystem: Arc::new(Mutex::new(RefCell::new(HashMap::new()))),
            }
        }

        pub fn backend(&self) -> &Backend {
            &self.virtual_filesystem
        }

    }

    impl FileAbstraction for InMemoryFileAbstraction {

        fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
            debug!("Removing: {:?}", path);
            self.backend()
                .lock()
                .expect("Locking Mutex failed")
                .get_mut()
                .remove(path)
                .map(|_| ())
                .ok_or(SEK::FileNotFound.into_error())
        }

        fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            debug!("Copying : {:?} -> {:?}", from, to);
            let mut mtx = self.backend().lock().expect("Locking Mutex failed");
            let mut backend = mtx.get_mut();

            let a = try!(backend.get(from).cloned().ok_or(SEK::FileNotFound.into_error()));
            backend.insert(to.clone(), a);
            debug!("Copying: {:?} -> {:?} worked", from, to);
            Ok(())
        }

        fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            debug!("Renaming: {:?} -> {:?}", from, to);
            let mut mtx = self.backend().lock().expect("Locking Mutex failed");
            let mut backend = mtx.get_mut();

            let a = try!(backend.get(from).cloned().ok_or(SEK::FileNotFound.into_error()));
            backend.insert(to.clone(), a);
            debug!("Renaming: {:?} -> {:?} worked", from, to);
            Ok(())
        }

        fn create_dir_all(&self, _: &PathBuf) -> Result<(), SE> {
            Ok(())
        }

        fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
            Box::new(InMemoryFileAbstractionInstance::new(self.backend().clone(), p))
        }
    }

}

#[cfg(test)]
mod test {
    use super::FileAbstractionInstance;
    use super::inmemory::InMemoryFileAbstraction;
    use super::inmemory::InMemoryFileAbstractionInstance;
    use std::path::PathBuf;

    #[test]
    fn lazy_file() {
        let fs = InMemoryFileAbstraction::new();

        let mut path = PathBuf::from("/tests");
        path.set_file_name("test1");
        let mut lf = InMemoryFileAbstractionInstance::new(fs.backend().clone(), path);
        lf.write_file_content(b"Hello World").unwrap();
        let bah = lf.get_file_content().unwrap();
        assert_eq!(bah, "Hello World");
    }

}
<|endoftext|>


<commit_before><commit_msg>initial<commit_after>use std::os;
use std::io::File;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

fn search(needle: String, haystack: Vec<char>) -> Option<(usize, usize)> {
    let needle: Vec<char> = needle.chars().collect();

    let mut indexed_haystack = HashMap::new();
    for (idx, c) in haystack.iter().enumerate() {
        match indexed_haystack.entry(c) {
            Vacant(entry) => { entry.insert(vec![idx]); },
            Occupied(mut entry) => { (*entry.get_mut()).push(idx); }
        }
    }

    let possible_starts: &Vec<usize>;
    match indexed_haystack.get(&needle[0]) {
        Some(ref entries) => {
            possible_starts = *entries;
        },
        None => {
            return None;
        }
    }

    let second_pos: &Vec<usize>;
    match indexed_haystack.get(&needle[1]) {
        None => { return None; }
        Some(ref entries) => {
            second_pos = *entries;
        }
    }
    let mut possible_steps: Vec<(usize, usize)> = Vec::new();
    for first_pos in possible_starts.iter() {
        for second_pos in second_pos.iter() {
            if first_pos < second_pos {

                let start = *first_pos;
                let step = *second_pos - *first_pos;

                if haystack.iter().skip(start).enumerate().filter(|&(idx, _)| { idx % step == 0 }).map(|(_, char)| { char })
                        .zip(needle.iter())
                        .all(|(&x, &y)| { x == y }) {
                    return Some((start, step));
                }
            }
        }
    }

    None
}

fn main() {
    let file_to_search = &os::args()[1];
    println!("Reading in {}", file_to_search);
    let haystack: Vec<char> = File::open(&Path::new(file_to_search)).read_to_string().unwrap().chars().filter(|&x| { x.is_alphabetic() }).map(|x| { x.to_lowercase() }).collect();

    let needle = (&os::args()[2]).to_string();
    println!("Looking for {}", needle);
    match search(needle, haystack) {
        None => { println!("Not found"); }
        Some((start, step)) => { println!("Found starting at {} with step of {}", start, step); }
    }
}
<|endoftext|>


<commit_before><commit_msg>Make StoreId::is_in_collection() generic over AsRef<str><commit_after><|endoftext|>


<commit_before><commit_msg>Add support for padded range expansion. (#733)<commit_after><|endoftext|>


<commit_before>/// A graph similarity score using neighbor matching according to [this paper][1].
///
/// [1]: http://arxiv.org/abs/1009.5290 "2010, Mladen Nikolic, Measuring Similarity
///      of Graph Nodes by Neighbor Matching"

extern crate nalgebra;
extern crate munkres;

use nalgebra::{DMat, Shape, ApproxEq};
use munkres::{WeightMatrix, solve_assignment};
use std::cmp;
use std::mem;

pub type Idx = u32;

trait Edges {
    /// The number of edges
    fn len(&self) -> usize;

    /// Returns the target node of the nth-edge
    fn nth_edge(&self, n: usize) -> usize;

    /// Returns the nth edge weight
    fn nth_edge_weight(&self, _n: usize) -> f32 {
        panic!();
    }
}

impl<'a> Edges for &'a [Idx] {
    #[inline]
    fn len(&self) -> usize {
        let x: &[Idx] = self;
        x.len()
    }
    #[inline]
    fn nth_edge(&self, n: usize) -> usize {
        self[n] as usize
    }
}

#[inline]
/// Calculates the similarity of two nodes `i` and `j`.
///
/// `n_i` contains the neighborhood of i (either in or out neighbors, not both)
/// `n_j` contains the neighborhood of j (either in or out neighbors, not both)
/// `x`   the similarity matrix.
fn s_next<T: Edges>(n_i: T, n_j: T, x: &DMat<f32>) -> f32 {
    let max_deg = cmp::max(n_i.len(), n_j.len());
    let min_deg = cmp::min(n_i.len(), n_j.len());

    if min_deg == 0 {
        // in the paper, 0/0 is defined as 1.0
        return 1.0;
    }

    assert!(min_deg > 0 && max_deg > 0);

    // map indicies from 0..min(degree) to the node indices
    let mapidx = |(a, b)| (n_i.nth_edge(a), n_j.nth_edge(b));

    let mut w = WeightMatrix::from_fn(min_deg, |ab| x[mapidx(ab)]);

    let assignment = solve_assignment(&mut w);
    assert!(assignment.len() == min_deg);

    let sum: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[mapidx(ab)]);

    return sum / max_deg as f32;
}

#[inline]
/// Calculates x[k+1]
///
/// `node_color_scale((i,j))`: If two nodes `i` (of graph A) and `j` (of graph B)
/// are of different color, this can be set to return 0.0. Alternatively a
/// node-color distance (within 0...1) could be used to penalize.
fn next_x<F>(x: &DMat<f32>,
             new_x: &mut DMat<f32>,
             in_a: &[Vec<Idx>],
             in_b: &[Vec<Idx>],
             out_a: &[Vec<Idx>],
             out_b: &[Vec<Idx>],
             node_color_scale: F)
    where F: Fn((usize, usize)) -> f32
{
    let shape = x.shape();
    assert!(shape == new_x.shape());

    for i in 0..shape.0 {
        for j in 0..shape.1 {
            let in_i: &[Idx] = &in_a[i];
            let in_j: &[Idx] = &in_b[j];
            let out_i: &[Idx] = &out_a[i];
            let out_j: &[Idx] = &out_b[j];
            new_x[(i, j)] = node_color_scale((i, j)) *
                            (s_next(in_i, in_j, x) + s_next(out_i, out_j, x)) /
                            2.0;
        }
    }
}

#[derive(Debug)]
pub struct NodeSimilarityMatrix<'a> {
    graph_a: Graph<'a>,
    graph_b: Graph<'a>,
    // current version of similarity matrix
    current: DMat<f32>,
    // previous version of similarity matrix
    previous: DMat<f32>,
    // current number of iterations
    num_iters: usize,
}

#[derive(Copy, Clone, Debug)]
pub struct Graph<'a> {
    in_edges: &'a [Vec<Idx>],
    out_edges: &'a [Vec<Idx>],
}

impl<'a> Graph<'a> {
    pub fn new<'b>(in_edges: &'b [Vec<Idx>], out_edges: &'b [Vec<Idx>]) -> Graph<'b> {
        assert!(in_edges.len() == out_edges.len());
        Graph {
            in_edges: in_edges,
            out_edges: out_edges,
        }
    }

    fn num_nodes(&self) -> usize {
        let n = self.in_edges.len();
        assert!(n == self.out_edges.len());
        n
    }

    fn node_degree(&self, node_idx: usize) -> usize {
        self.in_edges[node_idx].len() + self.out_edges[node_idx].len()
    }
}

impl<'a> NodeSimilarityMatrix<'a> {
    pub fn new<'b, F>(graph_a: Graph<'b>,
                      graph_b: Graph<'b>,
                      node_color_scale: &F)
                      -> NodeSimilarityMatrix<'b>
        where F: Fn((usize, usize)) -> f32
    {
        // `x` is the node-similarity matrix.
        // we initialize `x`, so that x[i,j]=1 for all i in A.edges() and j in
        // B.edges().
        let x: DMat<f32> = DMat::from_fn(graph_a.num_nodes(), graph_b.num_nodes(), |i, j| {
            node_color_scale((i, j)) *
            if graph_a.node_degree(i) > 0 && graph_b.node_degree(j) > 0 {
                1.0
            } else {
                0.0
            }
        });

        let new_x: DMat<f32> = DMat::new_zeros(graph_a.num_nodes(), graph_b.num_nodes());

        NodeSimilarityMatrix {
            graph_a: graph_a,
            graph_b: graph_b,
            current: x,
            previous: new_x,
            num_iters: 0,
        }
    }

    fn in_eps(&self, eps: f32) -> bool {
        self.previous.approx_eq_eps(&self.current, &eps)
    }

    /// Calculates the next iteration of the similarity matrix.
    pub fn next<F>(&mut self, node_color_scale: &F)
        where F: Fn((usize, usize)) -> f32
    {
        next_x(&self.current,
               &mut self.previous,
               self.graph_a.in_edges,
               self.graph_b.in_edges,
               self.graph_a.out_edges,
               self.graph_b.out_edges,
               node_color_scale);
        mem::swap(&mut self.previous, &mut self.current);
        self.num_iters += 1;
    }

    #[inline]
    /// Iteratively calculate the similarity matrix.
    ///
    /// `eps`:   When to stop the iteration
    /// `stop_after_iter`: Stop after iteration (Calculate x(stop_after_iter))
    pub fn iterate<F>(&mut self, eps: f32, stop_after_iter: usize, node_color_scale: &F)
        where F: Fn((usize, usize)) -> f32
    {
        for _ in 0..stop_after_iter {
            if self.in_eps(eps) {
                break;
            }
            self.next(node_color_scale);
        }
    }

    pub fn matrix(&self) -> &DMat<f32> {
        &self.current
    }

    pub fn num_iterations(&self) -> usize {
        self.num_iters
    }

    fn optimal_node_assignment(&self, n: usize) -> Vec<(usize, usize)> {
        let x = &self.current;
        assert!(n > 0);
        let mut w = WeightMatrix::from_fn(n, |ij| x[ij]);
        let assignment = solve_assignment(&mut w);
        assert!(assignment.len() == n);
        assignment
    }

    fn score_optimal_sum(&self, n: usize) -> f32 {
        self.optimal_node_assignment(n).iter().fold(0.0, |acc, &ab| acc + self.current[ab])
    }

    /// Calculate a measure how good the edge weights match up.
    ///
    /// We start by calculating the optimal node assignment between nodes of graph A and
    /// graph B, then compare all outgoing edges of similar nodes by again using an
    /// assignment.
    pub fn score_outgoing_edge_weights(&self) -> f32 {
        // XXX
        0.0
    }

    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Used as default in the paper.
    pub fn score_sum_norm_min_degree(&self) -> f32 {
        let x = &self.current;
        let n = cmp::min(x.nrows(), x.ncols());
        if n > 0 {
            self.score_optimal_sum(n) / n as f32
        } else {
            0.0
        }
    }

    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Penalizes the difference in size of graphs.
    pub fn score_sum_norm_max_degree(&self) -> f32 {
        let x = &self.current;
        let n = cmp::min(x.nrows(), x.ncols());
        let m = cmp::max(x.nrows(), x.ncols());

        if n > 0 {
            assert!(m > 0);
            self.score_optimal_sum(n) / m as f32
        } else {
            0.0
        }
    }

    /// Calculates the average over the whole node similarity matrix. This is faster,
    /// as no assignment has to be found. "Graphs with greater number of automorphisms
    /// would be considered to be more self-similar than graphs without automorphisms."
    pub fn score_average(&self) -> f32 {
        let x = &self.current;
        let n = cmp::min(x.nrows(), x.ncols());
        if n > 0 {
            let sum: f32 = x.as_vec().iter().fold(0.0, |acc, &v| acc + v);
            let len = x.as_vec().len();
            assert!(len > 0);
            sum / len as f32
        } else {
            0.0
        }
    }
}

#[test]
fn test_matrix() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let node_color = |_| 1.0;
    let mut s = NodeSimilarityMatrix::new(Graph::new(&in_a, &out_a),
                                          Graph::new(&in_b, &out_b),
                                          &node_color);
    s.iterate(0.1, 100, &node_color);

    println!("{:?}", s);
    assert_eq!(1, s.num_iterations());
    let mat = s.matrix();
    assert_eq!(2, mat.nrows());
    assert_eq!(2, mat.ncols());

    // A and B are isomorphic
    assert_eq!(1.0, mat[(0, 0)]);
    assert_eq!(1.0, mat[(0, 1)]);
    assert_eq!(1.0, mat[(1, 0)]);
    assert_eq!(1.0, mat[(1, 1)]);
}

#[test]
fn test_matrix_iter1() {
    let in_a = vec![vec![0, 0, 0]];
    let out_a = vec![vec![0, 0, 0]];

    let in_b = vec![vec![0, 0, 0, 0, 0]];
    let out_b = vec![vec![0, 0, 0, 0, 0]];

    let node_color = |_| 1.0;
    let mut s = NodeSimilarityMatrix::new(Graph::new(&in_a, &out_a),
                                          Graph::new(&in_b, &out_b),
                                          &node_color);
    s.iterate(0.1, 1, &node_color);

    assert_eq!(1, s.num_iterations());
    let mat = s.matrix();
    assert_eq!(3.0 / 5.0, mat[(0, 0)]);
}

#[test]
fn test_score() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let node_color = |_| 1.0;
    let mut s = NodeSimilarityMatrix::new(Graph::new(&in_a, &out_a),
                                          Graph::new(&in_b, &out_b),
                                          &node_color);
    s.iterate(0.1, 100, &node_color);

    assert_eq!(1, s.num_iterations());

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, s.score_sum_norm_min_degree());

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, s.score_sum_norm_max_degree());
}
<commit_msg>Rename NodeSimilarityMatrix -> GraphSimilarityMatrix<commit_after>/// A graph similarity score using neighbor matching according to [this paper][1].
///
/// [1]: http://arxiv.org/abs/1009.5290 "2010, Mladen Nikolic, Measuring Similarity
///      of Graph Nodes by Neighbor Matching"

extern crate nalgebra;
extern crate munkres;

use nalgebra::{DMat, Shape, ApproxEq};
use munkres::{WeightMatrix, solve_assignment};
use std::cmp;
use std::mem;

pub type Idx = u32;

trait Edges {
    /// The number of edges
    fn len(&self) -> usize;

    /// Returns the target node of the nth-edge
    fn nth_edge(&self, n: usize) -> usize;

    /// Returns the nth edge weight
    fn nth_edge_weight(&self, _n: usize) -> f32 {
        panic!();
    }
}

impl<'a> Edges for &'a [Idx] {
    #[inline]
    fn len(&self) -> usize {
        let x: &[Idx] = self;
        x.len()
    }
    #[inline]
    fn nth_edge(&self, n: usize) -> usize {
        self[n] as usize
    }
}

#[inline]
/// Calculates the similarity of two nodes `i` and `j`.
///
/// `n_i` contains the neighborhood of i (either in or out neighbors, not both)
/// `n_j` contains the neighborhood of j (either in or out neighbors, not both)
/// `x`   the similarity matrix.
fn s_next<T: Edges>(n_i: T, n_j: T, x: &DMat<f32>) -> f32 {
    let max_deg = cmp::max(n_i.len(), n_j.len());
    let min_deg = cmp::min(n_i.len(), n_j.len());

    if min_deg == 0 {
        // in the paper, 0/0 is defined as 1.0
        return 1.0;
    }

    assert!(min_deg > 0 && max_deg > 0);

    // map indicies from 0..min(degree) to the node indices
    let mapidx = |(a, b)| (n_i.nth_edge(a), n_j.nth_edge(b));

    let mut w = WeightMatrix::from_fn(min_deg, |ab| x[mapidx(ab)]);

    let assignment = solve_assignment(&mut w);
    assert!(assignment.len() == min_deg);

    let sum: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[mapidx(ab)]);

    return sum / max_deg as f32;
}

#[inline]
/// Calculates x[k+1]
///
/// `node_color_scale((i,j))`: If two nodes `i` (of graph A) and `j` (of graph B)
/// are of different color, this can be set to return 0.0. Alternatively a
/// node-color distance (within 0...1) could be used to penalize.
fn next_x<F>(x: &DMat<f32>,
             new_x: &mut DMat<f32>,
             in_a: &[Vec<Idx>],
             in_b: &[Vec<Idx>],
             out_a: &[Vec<Idx>],
             out_b: &[Vec<Idx>],
             node_color_scale: F)
    where F: Fn((usize, usize)) -> f32
{
    let shape = x.shape();
    assert!(shape == new_x.shape());

    for i in 0..shape.0 {
        for j in 0..shape.1 {
            let in_i: &[Idx] = &in_a[i];
            let in_j: &[Idx] = &in_b[j];
            let out_i: &[Idx] = &out_a[i];
            let out_j: &[Idx] = &out_b[j];
            new_x[(i, j)] = node_color_scale((i, j)) *
                            (s_next(in_i, in_j, x) + s_next(out_i, out_j, x)) /
                            2.0;
        }
    }
}

#[derive(Debug)]
pub struct GraphSimilarityMatrix<'a> {
    graph_a: Graph<'a>,
    graph_b: Graph<'a>,
    // current version of similarity matrix
    current: DMat<f32>,
    // previous version of similarity matrix
    previous: DMat<f32>,
    // current number of iterations
    num_iters: usize,
}

#[derive(Copy, Clone, Debug)]
pub struct Graph<'a> {
    in_edges: &'a [Vec<Idx>],
    out_edges: &'a [Vec<Idx>],
}

impl<'a> Graph<'a> {
    pub fn new<'b>(in_edges: &'b [Vec<Idx>], out_edges: &'b [Vec<Idx>]) -> Graph<'b> {
        assert!(in_edges.len() == out_edges.len());
        Graph {
            in_edges: in_edges,
            out_edges: out_edges,
        }
    }

    fn num_nodes(&self) -> usize {
        let n = self.in_edges.len();
        assert!(n == self.out_edges.len());
        n
    }

    fn node_degree(&self, node_idx: usize) -> usize {
        self.in_edges[node_idx].len() + self.out_edges[node_idx].len()
    }
}

impl<'a> GraphSimilarityMatrix<'a> {
    pub fn new<'b, F>(graph_a: Graph<'b>,
                      graph_b: Graph<'b>,
                      node_color_scale: &F)
                      -> GraphSimilarityMatrix<'b>
        where F: Fn((usize, usize)) -> f32
    {
        // `x` is the node-similarity matrix.
        // we initialize `x`, so that x[i,j]=1 for all i in A.edges() and j in
        // B.edges().
        let x: DMat<f32> = DMat::from_fn(graph_a.num_nodes(), graph_b.num_nodes(), |i, j| {
            node_color_scale((i, j)) *
            if graph_a.node_degree(i) > 0 && graph_b.node_degree(j) > 0 {
                1.0
            } else {
                0.0
            }
        });

        let new_x: DMat<f32> = DMat::new_zeros(graph_a.num_nodes(), graph_b.num_nodes());

        GraphSimilarityMatrix {
            graph_a: graph_a,
            graph_b: graph_b,
            current: x,
            previous: new_x,
            num_iters: 0,
        }
    }

    fn in_eps(&self, eps: f32) -> bool {
        self.previous.approx_eq_eps(&self.current, &eps)
    }

    /// Calculates the next iteration of the similarity matrix.
    pub fn next<F>(&mut self, node_color_scale: &F)
        where F: Fn((usize, usize)) -> f32
    {
        next_x(&self.current,
               &mut self.previous,
               self.graph_a.in_edges,
               self.graph_b.in_edges,
               self.graph_a.out_edges,
               self.graph_b.out_edges,
               node_color_scale);
        mem::swap(&mut self.previous, &mut self.current);
        self.num_iters += 1;
    }

    #[inline]
    /// Iteratively calculate the similarity matrix.
    ///
    /// `eps`:   When to stop the iteration
    /// `stop_after_iter`: Stop after iteration (Calculate x(stop_after_iter))
    pub fn iterate<F>(&mut self, eps: f32, stop_after_iter: usize, node_color_scale: &F)
        where F: Fn((usize, usize)) -> f32
    {
        for _ in 0..stop_after_iter {
            if self.in_eps(eps) {
                break;
            }
            self.next(node_color_scale);
        }
    }

    pub fn matrix(&self) -> &DMat<f32> {
        &self.current
    }

    pub fn num_iterations(&self) -> usize {
        self.num_iters
    }

    fn optimal_node_assignment(&self, n: usize) -> Vec<(usize, usize)> {
        let x = &self.current;
        assert!(n > 0);
        let mut w = WeightMatrix::from_fn(n, |ij| x[ij]);
        let assignment = solve_assignment(&mut w);
        assert!(assignment.len() == n);
        assignment
    }

    fn score_optimal_sum(&self, n: usize) -> f32 {
        self.optimal_node_assignment(n).iter().fold(0.0, |acc, &ab| acc + self.current[ab])
    }

    /// Calculate a measure how good the edge weights match up.
    ///
    /// We start by calculating the optimal node assignment between nodes of graph A and
    /// graph B, then compare all outgoing edges of similar nodes by again using an
    /// assignment.
    pub fn score_outgoing_edge_weights(&self) -> f32 {
        // XXX
        0.0
    }

    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Used as default in the paper.
    pub fn score_sum_norm_min_degree(&self) -> f32 {
        let x = &self.current;
        let n = cmp::min(x.nrows(), x.ncols());
        if n > 0 {
            self.score_optimal_sum(n) / n as f32
        } else {
            0.0
        }
    }

    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Penalizes the difference in size of graphs.
    pub fn score_sum_norm_max_degree(&self) -> f32 {
        let x = &self.current;
        let n = cmp::min(x.nrows(), x.ncols());
        let m = cmp::max(x.nrows(), x.ncols());

        if n > 0 {
            assert!(m > 0);
            self.score_optimal_sum(n) / m as f32
        } else {
            0.0
        }
    }

    /// Calculates the average over the whole node similarity matrix. This is faster,
    /// as no assignment has to be found. "Graphs with greater number of automorphisms
    /// would be considered to be more self-similar than graphs without automorphisms."
    pub fn score_average(&self) -> f32 {
        let x = &self.current;
        let n = cmp::min(x.nrows(), x.ncols());
        if n > 0 {
            let sum: f32 = x.as_vec().iter().fold(0.0, |acc, &v| acc + v);
            let len = x.as_vec().len();
            assert!(len > 0);
            sum / len as f32
        } else {
            0.0
        }
    }
}

#[test]
fn test_matrix() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let node_color = |_| 1.0;
    let mut s = GraphSimilarityMatrix::new(Graph::new(&in_a, &out_a),
                                          Graph::new(&in_b, &out_b),
                                          &node_color);
    s.iterate(0.1, 100, &node_color);

    println!("{:?}", s);
    assert_eq!(1, s.num_iterations());
    let mat = s.matrix();
    assert_eq!(2, mat.nrows());
    assert_eq!(2, mat.ncols());

    // A and B are isomorphic
    assert_eq!(1.0, mat[(0, 0)]);
    assert_eq!(1.0, mat[(0, 1)]);
    assert_eq!(1.0, mat[(1, 0)]);
    assert_eq!(1.0, mat[(1, 1)]);
}

#[test]
fn test_matrix_iter1() {
    let in_a = vec![vec![0, 0, 0]];
    let out_a = vec![vec![0, 0, 0]];

    let in_b = vec![vec![0, 0, 0, 0, 0]];
    let out_b = vec![vec![0, 0, 0, 0, 0]];

    let node_color = |_| 1.0;
    let mut s = GraphSimilarityMatrix::new(Graph::new(&in_a, &out_a),
                                          Graph::new(&in_b, &out_b),
                                          &node_color);
    s.iterate(0.1, 1, &node_color);

    assert_eq!(1, s.num_iterations());
    let mat = s.matrix();
    assert_eq!(3.0 / 5.0, mat[(0, 0)]);
}

#[test]
fn test_score() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let node_color = |_| 1.0;
    let mut s = GraphSimilarityMatrix::new(Graph::new(&in_a, &out_a),
                                          Graph::new(&in_b, &out_b),
                                          &node_color);
    s.iterate(0.1, 100, &node_color);

    assert_eq!(1, s.num_iterations());

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, s.score_sum_norm_min_degree());

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, s.score_sum_norm_max_degree());
}
<|endoftext|>


<commit_before><commit_msg>The deriving Component macro (\#[component]) is now \#[SparkleComponent]<commit_after><|endoftext|>


<commit_before><commit_msg>Add regression tests to ensure stable drop order<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(dead_code, unreachable_code)]

use std::cell::RefCell;
use std::rc::Rc;
use std::panic::{self, AssertUnwindSafe, UnwindSafe};

// This struct is used to record the order in which elements are dropped
struct PushOnDrop {
    vec: Rc<RefCell<Vec<u32>>>,
    val: u32
}

impl PushOnDrop {
    fn new(val: u32, vec: Rc<RefCell<Vec<u32>>>) -> PushOnDrop {
        PushOnDrop { vec, val }
    }
}

impl Drop for PushOnDrop {
    fn drop(&mut self) {
        self.vec.borrow_mut().push(self.val)
    }
}

impl UnwindSafe for PushOnDrop { }

// Structs
struct TestStruct {
    x: PushOnDrop,
    y: PushOnDrop,
    z: PushOnDrop
}

// Tuple structs
struct TestTupleStruct(PushOnDrop, PushOnDrop, PushOnDrop);

// Enum variants
enum TestEnum {
    Tuple(PushOnDrop, PushOnDrop, PushOnDrop),
    Struct { x: PushOnDrop, y: PushOnDrop, z: PushOnDrop }
}

fn test_drop_tuple() {
    // Tuple fields are dropped in the same order they are declared
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let test_tuple = (PushOnDrop::new(1, dropped_fields.clone()),
                      PushOnDrop::new(2, dropped_fields.clone()));
    drop(test_tuple);
    assert_eq!(*dropped_fields.borrow(), &[1, 2]);

    // Panic during construction means that fields are treated as local variables
    // Therefore they are dropped in reverse order of initialization
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let cloned = AssertUnwindSafe(dropped_fields.clone());
    panic::catch_unwind(|| {
        (PushOnDrop::new(2, cloned.clone()),
         PushOnDrop::new(1, cloned.clone()),
         panic!("this panic is catched :D"));
    }).err().unwrap();
    assert_eq!(*dropped_fields.borrow(), &[1, 2]);
}

fn test_drop_struct() {
    // Struct fields are dropped in the same order they are declared
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let test_struct = TestStruct {
        x: PushOnDrop::new(1, dropped_fields.clone()),
        y: PushOnDrop::new(2, dropped_fields.clone()),
        z: PushOnDrop::new(3, dropped_fields.clone()),
    };
    drop(test_struct);
    assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);

    // The same holds for tuple structs
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let test_tuple_struct = TestTupleStruct(PushOnDrop::new(1, dropped_fields.clone()),
                                            PushOnDrop::new(2, dropped_fields.clone()),
                                            PushOnDrop::new(3, dropped_fields.clone()));
    drop(test_tuple_struct);
    assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);

    // Panic during struct construction means that fields are treated as local variables
    // Therefore they are dropped in reverse order of initialization
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let cloned = AssertUnwindSafe(dropped_fields.clone());
    panic::catch_unwind(|| {
        TestStruct {
            x: PushOnDrop::new(2, cloned.clone()),
            y: PushOnDrop::new(1, cloned.clone()),
            z: panic!("this panic is catched :D")
        };
    }).err().unwrap();
    assert_eq!(*dropped_fields.borrow(), &[1, 2]);

    // Test with different initialization order
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let cloned = AssertUnwindSafe(dropped_fields.clone());
    panic::catch_unwind(|| {
        TestStruct {
            y: PushOnDrop::new(2, cloned.clone()),
            x: PushOnDrop::new(1, cloned.clone()),
            z: panic!("this panic is catched :D")
        };
    }).err().unwrap();
    assert_eq!(*dropped_fields.borrow(), &[1, 2]);

    // The same holds for tuple structs
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let cloned = AssertUnwindSafe(dropped_fields.clone());
    panic::catch_unwind(|| {
        TestTupleStruct(PushOnDrop::new(2, cloned.clone()),
                        PushOnDrop::new(1, cloned.clone()),
                        panic!("this panic is catched :D"));
    }).err().unwrap();
    assert_eq!(*dropped_fields.borrow(), &[1, 2]);
}

fn test_drop_enum() {
    // Enum variants are dropped in the same order they are declared
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let test_struct_enum = TestEnum::Struct {
        x: PushOnDrop::new(1, dropped_fields.clone()),
        y: PushOnDrop::new(2, dropped_fields.clone()),
        z: PushOnDrop::new(3, dropped_fields.clone())
    };
    drop(test_struct_enum);
    assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);

    // The same holds for tuple enum variants
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let test_tuple_enum = TestEnum::Tuple(PushOnDrop::new(1, dropped_fields.clone()),
                                          PushOnDrop::new(2, dropped_fields.clone()),
                                          PushOnDrop::new(3, dropped_fields.clone()));
    drop(test_tuple_enum);
    assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);

    // Panic during enum construction means that fields are treated as local variables
    // Therefore they are dropped in reverse order of initialization
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let cloned = AssertUnwindSafe(dropped_fields.clone());
    panic::catch_unwind(|| {
        TestEnum::Struct {
            x: PushOnDrop::new(2, cloned.clone()),
            y: PushOnDrop::new(1, cloned.clone()),
            z: panic!("this panic is catched :D")
        };
    }).err().unwrap();
    assert_eq!(*dropped_fields.borrow(), &[1, 2]);

    // Test with different initialization order
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let cloned = AssertUnwindSafe(dropped_fields.clone());
    panic::catch_unwind(|| {
        TestEnum::Struct {
            y: PushOnDrop::new(2, cloned.clone()),
            x: PushOnDrop::new(1, cloned.clone()),
            z: panic!("this panic is catched :D")
        };
    }).err().unwrap();
    assert_eq!(*dropped_fields.borrow(), &[1, 2]);

    // The same holds for tuple enum variants
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let cloned = AssertUnwindSafe(dropped_fields.clone());
    panic::catch_unwind(|| {
        TestEnum::Tuple(PushOnDrop::new(2, cloned.clone()),
                        PushOnDrop::new(1, cloned.clone()),
                        panic!("this panic is catched :D"));
    }).err().unwrap();
    assert_eq!(*dropped_fields.borrow(), &[1, 2]);
}

fn test_drop_list() {
    // Elements in a Vec are dropped in the same order they are pushed
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let xs = vec![PushOnDrop::new(1, dropped_fields.clone()),
                  PushOnDrop::new(2, dropped_fields.clone()),
                  PushOnDrop::new(3, dropped_fields.clone())];
    drop(xs);
    assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);

    // The same holds for arrays
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let xs = [PushOnDrop::new(1, dropped_fields.clone()),
              PushOnDrop::new(2, dropped_fields.clone()),
              PushOnDrop::new(3, dropped_fields.clone())];
    drop(xs);
    assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);

    // Panic during vec construction means that fields are treated as local variables
    // Therefore they are dropped in reverse order of initialization
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let cloned = AssertUnwindSafe(dropped_fields.clone());
    panic::catch_unwind(|| {
        vec![
            PushOnDrop::new(2, cloned.clone()),
            PushOnDrop::new(1, cloned.clone()),
            panic!("this panic is catched :D")
        ];
    }).err().unwrap();
    assert_eq!(*dropped_fields.borrow(), &[1, 2]);

    // The same holds for arrays
    let dropped_fields = Rc::new(RefCell::new(Vec::new()));
    let cloned = AssertUnwindSafe(dropped_fields.clone());
    panic::catch_unwind(|| {
        [
            PushOnDrop::new(2, cloned.clone()),
            PushOnDrop::new(1, cloned.clone()),
            panic!("this panic is catched :D")
        ];
    }).err().unwrap();
    assert_eq!(*dropped_fields.borrow(), &[1, 2]);
}

fn main() {
    test_drop_tuple();
    test_drop_struct();
    test_drop_enum();
    test_drop_list();
}
<|endoftext|>


<commit_before><commit_msg>Fixes #1499: a test that shape code can walk explicit disr values<commit_after>tag color {
    red = 0xff0000;
    green = 0x00ff00;
    blue = 0x0000ff;
    black = 0x000000;
    white = 0xFFFFFF;
}

fn main() {
    assert uint::to_str(red as uint, 10u) == #fmt["%?", red];
    assert uint::to_str(green as uint, 10u) == #fmt["%?", green];
    assert uint::to_str(white as uint, 10u) == #fmt["%?", white];
}

<|endoftext|>