<commit_before>// Copyright 2015 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.

//! Command-line interface of the rustbuild build system.
//!
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process;

use getopts::{Matches, Options};

use Build;
use config::Config;
use metadata;
use step;

/// Deserialized version of all flags for this compile.
pub struct Flags {
    pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
    pub on_fail: Option<String>,
    pub stage: Option<u32>,
    pub keep_stage: Option<u32>,
    pub build: String,
    pub host: Vec<String>,
    pub target: Vec<String>,
    pub config: Option<PathBuf>,
    pub src: Option<PathBuf>,
    pub jobs: Option<u32>,
    pub cmd: Subcommand,
    pub incremental: bool,
}

impl Flags {
    pub fn verbose(&self) -> bool {
        self.verbose > 0
    }

    pub fn very_verbose(&self) -> bool {
        self.verbose > 1
    }
}

pub enum Subcommand {
    Build {
        paths: Vec<PathBuf>,
    },
    Doc {
        paths: Vec<PathBuf>,
    },
    Test {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
    },
    Bench {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
    },
    Clean,
    Dist {
        paths: Vec<PathBuf>,
        install: bool,
    },
}

impl Flags {
    pub fn parse(args: &[String]) -> Flags {
        let mut opts = Options::new();
        opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
        opts.optflag("i", "incremental", "use incremental compilation");
        opts.optopt("", "config", "TOML configuration file for build", "FILE");
        opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
        opts.optmulti("", "host", "host targets to build", "HOST");
        opts.optmulti("", "target", "target targets to build", "TARGET");
        opts.optopt("", "on-fail", "command to run on failure", "CMD");
        opts.optopt("", "stage", "stage to build", "N");
        opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
        opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
        opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
        opts.optflag("h", "help", "print this help message");

        let usage = |n, opts: &Options| -> ! {
            let command = args.get(0).map(|s| &**s);
            let brief = format!("Usage: x.py {} [options] [<args>...]",
                                command.unwrap_or("<command>"));

            println!("{}", opts.usage(&brief));
            match command {
                Some("build") => {
                    println!("\
Arguments:
    This subcommand accepts a number of positional arguments of directories to
    the crates and/or artifacts to compile. For example:

        ./x.py build src/libcore
        ./x.py build src/libproc_macro
        ./x.py build src/libstd --stage 1

    If no arguments are passed then the complete artifacts for that stage are
    also compiled.

        ./x.py build
        ./x.py build --stage 1

    For a quick build with a usable compile, you can pass:

        ./x.py build --stage 1 src/libtest
");
                }

                Some("test") => {
                    println!("\
Arguments:
    This subcommand accepts a number of positional arguments of directories to
    tests that should be compiled and run. For example:

        ./x.py test src/test/run-pass
        ./x.py test src/libstd --test-args hash_map
        ./x.py test src/libstd --stage 0

    If no arguments are passed then the complete artifacts for that stage are
    compiled and tested.

        ./x.py test
        ./x.py test --stage 1
");
                }

                Some("doc") => {
                    println!("\
Arguments:
    This subcommand accepts a number of positional arguments of directories of
    documentation to build. For example:

        ./x.py doc src/doc/book
        ./x.py doc src/doc/nomicon
        ./x.py doc src/libstd

    If no arguments are passed then everything is documented:

        ./x.py doc
        ./x.py doc --stage 1
");
                }

                _ => {}
            }

            if let Some(command) = command {
                if command == "build" ||
                   command == "dist" ||
                   command == "doc" ||
                   command == "test" ||
                   command == "bench" ||
                   command == "clean"  {
                    println!("Available invocations:");
                    if args.iter().any(|a| a == "-v") {
                        let flags = Flags::parse(&["build".to_string()]);
                        let mut config = Config::default();
                        config.build = flags.build.clone();
                        let mut build = Build::new(flags, config);
                        metadata::build(&mut build);
                        step::build_rules(&build).print_help(command);
                    } else {
                        println!("    ... elided, run `./x.py {} -h -v` to see",
                                 command);
                    }

                    println!("");
                }
            }

println!("\
Subcommands:
    build       Compile either the compiler or libraries
    test        Build and run some test suites
    bench       Build and run some benchmarks
    doc         Build documentation
    clean       Clean out build directories
    dist        Build and/or install distribution artifacts

To learn more about a subcommand, run `./x.py <command> -h`
");

            process::exit(n);
        };
        if args.len() == 0 {
            println!("a command must be passed");
            usage(1, &opts);
        }
        let parse = |opts: &Options| {
            let m = opts.parse(&args[1..]).unwrap_or_else(|e| {
                println!("failed to parse options: {}", e);
                usage(1, opts);
            });
            if m.opt_present("h") {
                usage(0, opts);
            }
            return m
        };

        let cwd = t!(env::current_dir());
        let remaining_as_path = |m: &Matches| {
            m.free.iter().map(|p| cwd.join(p)).collect::<Vec<_>>()
        };

        let m: Matches;
        let cmd = match &args[0][..] {
            "build" => {
                m = parse(&opts);
                Subcommand::Build { paths: remaining_as_path(&m) }
            }
            "doc" => {
                m = parse(&opts);
                Subcommand::Doc { paths: remaining_as_path(&m) }
            }
            "test" => {
                opts.optmulti("", "test-args", "extra arguments", "ARGS");
                m = parse(&opts);
                Subcommand::Test {
                    paths: remaining_as_path(&m),
                    test_args: m.opt_strs("test-args"),
                }
            }
            "bench" => {
                opts.optmulti("", "test-args", "extra arguments", "ARGS");
                m = parse(&opts);
                Subcommand::Bench {
                    paths: remaining_as_path(&m),
                    test_args: m.opt_strs("test-args"),
                }
            }
            "clean" => {
                m = parse(&opts);
                if m.free.len() > 0 {
                    println!("clean takes no arguments");
                    usage(1, &opts);
                }
                Subcommand::Clean
            }
            "dist" => {
                opts.optflag("", "install", "run installer as well");
                m = parse(&opts);
                Subcommand::Dist {
                    paths: remaining_as_path(&m),
                    install: m.opt_present("install"),
                }
            }
            "--help" => usage(0, &opts),
            cmd => {
                println!("unknown command: {}", cmd);
                usage(1, &opts);
            }
        };

        let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| {
            if fs::metadata("config.toml").is_ok() {
                Some(PathBuf::from("config.toml"))
            } else {
                None
            }
        });

        let mut stage = m.opt_str("stage").map(|j| j.parse().unwrap());

        let incremental = m.opt_present("i");

        if incremental {
            if stage.is_none() {
                stage = Some(1);
            }
        }

        Flags {
            verbose: m.opt_count("v"),
            stage: stage,
            on_fail: m.opt_str("on-fail"),
            keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()),
            build: m.opt_str("build").unwrap_or_else(|| {
                env::var("BUILD").unwrap()
            }),
            host: split(m.opt_strs("host")),
            target: split(m.opt_strs("target")),
            config: cfg_file,
            src: m.opt_str("src").map(PathBuf::from),
            jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()),
            cmd: cmd,
            incremental: incremental,
        }
    }
}

impl Subcommand {
    pub fn test_args(&self) -> Vec<&str> {
        match *self {
            Subcommand::Test { ref test_args, .. } |
            Subcommand::Bench { ref test_args, .. } => {
                test_args.iter().flat_map(|s| s.split_whitespace()).collect()
            }
            _ => Vec::new(),
        }
    }
}

fn split(s: Vec<String>) -> Vec<String> {
    s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect()
}
<commit_msg>Refer to a subcommand as a subcommand.<commit_after>// Copyright 2015 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.

//! Command-line interface of the rustbuild build system.
//!
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process;

use getopts::{Matches, Options};

use Build;
use config::Config;
use metadata;
use step;

/// Deserialized version of all flags for this compile.
pub struct Flags {
    pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
    pub on_fail: Option<String>,
    pub stage: Option<u32>,
    pub keep_stage: Option<u32>,
    pub build: String,
    pub host: Vec<String>,
    pub target: Vec<String>,
    pub config: Option<PathBuf>,
    pub src: Option<PathBuf>,
    pub jobs: Option<u32>,
    pub cmd: Subcommand,
    pub incremental: bool,
}

impl Flags {
    pub fn verbose(&self) -> bool {
        self.verbose > 0
    }

    pub fn very_verbose(&self) -> bool {
        self.verbose > 1
    }
}

pub enum Subcommand {
    Build {
        paths: Vec<PathBuf>,
    },
    Doc {
        paths: Vec<PathBuf>,
    },
    Test {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
    },
    Bench {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
    },
    Clean,
    Dist {
        paths: Vec<PathBuf>,
        install: bool,
    },
}

impl Flags {
    pub fn parse(args: &[String]) -> Flags {
        let mut opts = Options::new();
        opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
        opts.optflag("i", "incremental", "use incremental compilation");
        opts.optopt("", "config", "TOML configuration file for build", "FILE");
        opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
        opts.optmulti("", "host", "host targets to build", "HOST");
        opts.optmulti("", "target", "target targets to build", "TARGET");
        opts.optopt("", "on-fail", "command to run on failure", "CMD");
        opts.optopt("", "stage", "stage to build", "N");
        opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
        opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
        opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
        opts.optflag("h", "help", "print this help message");

        let usage = |n, opts: &Options| -> ! {
            let subcommand = args.get(0).map(|s| &**s);
            let brief = format!("Usage: x.py <subcommand> [options] [<args>...]");

            println!("{}", opts.usage(&brief));
            match subcommand {
                Some("build") => {
                    println!("\
Arguments:
    This subcommand accepts a number of positional arguments of directories to
    the crates and/or artifacts to compile. For example:

        ./x.py build src/libcore
        ./x.py build src/libproc_macro
        ./x.py build src/libstd --stage 1

    If no arguments are passed then the complete artifacts for that stage are
    also compiled.

        ./x.py build
        ./x.py build --stage 1

    For a quick build with a usable compile, you can pass:

        ./x.py build --stage 1 src/libtest
");
                }

                Some("test") => {
                    println!("\
Arguments:
    This subcommand accepts a number of positional arguments of directories to
    tests that should be compiled and run. For example:

        ./x.py test src/test/run-pass
        ./x.py test src/libstd --test-args hash_map
        ./x.py test src/libstd --stage 0

    If no arguments are passed then the complete artifacts for that stage are
    compiled and tested.

        ./x.py test
        ./x.py test --stage 1
");
                }

                Some("doc") => {
                    println!("\
Arguments:
    This subcommand accepts a number of positional arguments of directories of
    documentation to build. For example:

        ./x.py doc src/doc/book
        ./x.py doc src/doc/nomicon
        ./x.py doc src/libstd

    If no arguments are passed then everything is documented:

        ./x.py doc
        ./x.py doc --stage 1
");
                }

                _ => {}
            }

            if let Some(subcommand) = subcommand {
                if subcommand == "build" ||
                   subcommand == "dist" ||
                   subcommand == "doc" ||
                   subcommand == "test" ||
                   subcommand == "bench" ||
                   subcommand == "clean"  {
                    println!("Available invocations:");
                    if args.iter().any(|a| a == "-v") {
                        let flags = Flags::parse(&["build".to_string()]);
                        let mut config = Config::default();
                        config.build = flags.build.clone();
                        let mut build = Build::new(flags, config);
                        metadata::build(&mut build);
                        step::build_rules(&build).print_help(subcommand);
                    } else {
                        println!("    ... elided, run `./x.py {} -h -v` to see",
                                 subcommand);
                    }

                    println!("");
                }
            }

println!("\
Subcommands:
    build       Compile either the compiler or libraries
    test        Build and run some test suites
    bench       Build and run some benchmarks
    doc         Build documentation
    clean       Clean out build directories
    dist        Build and/or install distribution artifacts

To learn more about a subcommand, run `./x.py <subcommand> -h`
");

            process::exit(n);
        };
        if args.len() == 0 {
            println!("a subcommand must be passed");
            usage(1, &opts);
        }
        let parse = |opts: &Options| {
            let m = opts.parse(&args[1..]).unwrap_or_else(|e| {
                println!("failed to parse options: {}", e);
                usage(1, opts);
            });
            if m.opt_present("h") {
                usage(0, opts);
            }
            return m
        };

        let cwd = t!(env::current_dir());
        let remaining_as_path = |m: &Matches| {
            m.free.iter().map(|p| cwd.join(p)).collect::<Vec<_>>()
        };

        let m: Matches;
        let cmd = match &args[0][..] {
            "build" => {
                m = parse(&opts);
                Subcommand::Build { paths: remaining_as_path(&m) }
            }
            "doc" => {
                m = parse(&opts);
                Subcommand::Doc { paths: remaining_as_path(&m) }
            }
            "test" => {
                opts.optmulti("", "test-args", "extra arguments", "ARGS");
                m = parse(&opts);
                Subcommand::Test {
                    paths: remaining_as_path(&m),
                    test_args: m.opt_strs("test-args"),
                }
            }
            "bench" => {
                opts.optmulti("", "test-args", "extra arguments", "ARGS");
                m = parse(&opts);
                Subcommand::Bench {
                    paths: remaining_as_path(&m),
                    test_args: m.opt_strs("test-args"),
                }
            }
            "clean" => {
                m = parse(&opts);
                if m.free.len() > 0 {
                    println!("clean takes no arguments");
                    usage(1, &opts);
                }
                Subcommand::Clean
            }
            "dist" => {
                opts.optflag("", "install", "run installer as well");
                m = parse(&opts);
                Subcommand::Dist {
                    paths: remaining_as_path(&m),
                    install: m.opt_present("install"),
                }
            }
            "--help" => usage(0, &opts),
            cmd => {
                println!("unknown subcommand: {}", cmd);
                usage(1, &opts);
            }
        };

        let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| {
            if fs::metadata("config.toml").is_ok() {
                Some(PathBuf::from("config.toml"))
            } else {
                None
            }
        });

        let mut stage = m.opt_str("stage").map(|j| j.parse().unwrap());

        let incremental = m.opt_present("i");

        if incremental {
            if stage.is_none() {
                stage = Some(1);
            }
        }

        Flags {
            verbose: m.opt_count("v"),
            stage: stage,
            on_fail: m.opt_str("on-fail"),
            keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()),
            build: m.opt_str("build").unwrap_or_else(|| {
                env::var("BUILD").unwrap()
            }),
            host: split(m.opt_strs("host")),
            target: split(m.opt_strs("target")),
            config: cfg_file,
            src: m.opt_str("src").map(PathBuf::from),
            jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()),
            cmd: cmd,
            incremental: incremental,
        }
    }
}

impl Subcommand {
    pub fn test_args(&self) -> Vec<&str> {
        match *self {
            Subcommand::Test { ref test_args, .. } |
            Subcommand::Bench { ref test_args, .. } => {
                test_args.iter().flat_map(|s| s.split_whitespace()).collect()
            }
            _ => Vec::new(),
        }
    }
}

fn split(s: Vec<String>) -> Vec<String> {
    s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect()
}
<|endoftext|>


<commit_before>
#[test]
fn test_tokenize() {
    assert tokenize( ~"(1 2 3)" ) == ~[~"(", ~"1", ~"2", ~"3", ~")"];
}

#[test]
fn test_tokenize_empty() {
    assert tokenize( ~"" ) == ~[];
}

#[test]
fn test_tokenize_no_spaces() {
    assert tokenize( ~"one" ) == ~[~"one"];
}

#[test]
fn test_pad_parentheses() {
    assert pad_parentheses( ~"(1 2 3)" ) == ~" ( 1 2 3 ) "
}

#[test]
fn test_pad_parentheses_empty() {
    assert pad_parentheses( ~"" ) == ~""
}

#[test]
fn test_pad_parentheses_one() {
    assert pad_parentheses( ~"(" ) == ~" ( ";
    assert pad_parentheses( ~")" ) == ~" ) ";
}

fn pad_parentheses( input:&str ) -> ~str {
    str::replace(str::replace(input, ")", " ) "), "(", " ( ")
}

fn tokenize( input:&str ) -> ~[~str] {
    str::words(pad_parentheses(input))
}

#[test]
fn test_that_atom_can_read_bools() {
    assert atom(~"#t") == Bool(true)
}

#[test]
fn test_that_atom_can_read_a_symbol() {
    match atom(~"hello") {
        Symbol(~"hello") => (),
            _ => fail
    }
}

#[test]
fn test_that_a_plus_sign_becomes_a_symbol() {
    match atom(~"+") {
        Symbol(~"+") => (),
        _ => fail fmt!("+ became: %s", atom(~"+").to_str())
    }
}

#[test]
fn test_that_a_minus_sign_becomes_a_symbol() {
    match atom(~"-") {
        Symbol(~"-") => (),
        _ => fail fmt!("- became: %s", atom(~"-").to_str())
    }
}

#[test]
fn test_that_atom_can_read_an_int() {
    match atom(~"10") {
        Int(10) => (),
            _ => fail
    }
}

#[test]
fn test_that_atom_can_read_a_float() {
    match atom(~"10.1") {
        Float(10.1) => (),
            _ => fail
    }
}

fn atom( input:~str ) -> Expression {
    match input {
        ~"#t" => Bool( true ),
        ~"#f" => Bool( false ),
        ~"+" => Symbol( ~"+" ),
        ~"-" => Symbol( ~"-" ),
        _ => match int::from_str(input) {
            Some(number) => Int(number),
            None => match float::from_str(input) {
                Some(number) => Float(number),
                None => Symbol(input)
            }
        }
    }
}

#[test]
fn test_that_read_can_read_an_atom() {
    let atom = read( ~[~"12"] );
    match atom {
        Int(12) => (),
            _ => fail
    }
}

#[test]
fn test_that_read_can_read_a_list() {
    let list = read( ~[ ~"(", ~"1", ~")" ] );
    match list {
        List([Int(1)]) => (),
            _ => fail ~"not a list"
    }
}

#[test]
fn test_that_read_can_read_a_nested_list() {
    let list = read( ~[ ~"(", ~"1", ~"(", ~"2", ~")", ~"3", ~")" ] );
    match list {
        List([Int(1), List([Int(2)]), Int(3)]) => (),
        _ => fail
    }
}

fn read( tokens:~[~str] ) -> Expression {
    fn subexpression( tokens:~[~str] ) -> (Expression, ~[~str]) {
        let mut remainder = copy tokens;
        let token = remainder.remove(0);
        match token {
            ~"(" => {
                let mut accumulator:~[Expression] = ~[];
                while remainder.len() > 0 && remainder[0] != ~")" {
                    let (expr, new_remainder) = subexpression( remainder );
                    accumulator.push(expr);
                    remainder = new_remainder
                }
                // remove the final close paren, this will fail if the parens
                // aren't closed properly due to an assert in remove
                remainder.remove(0);
                (List(accumulator), remainder)
            }
            ~")" => fail,
                _ => (atom(token), remainder)
        }
    }

    let (expression, _remainder) = subexpression( tokens );
    expression
}

pub fn parse( program:&str ) -> Expression {
    read( tokenize( program ) )
}
<commit_msg>Return an error instead of failing on bad parens<commit_after>
#[test]
fn test_tokenize() {
    assert tokenize( ~"(1 2 3)" ) == ~[~"(", ~"1", ~"2", ~"3", ~")"];
}

#[test]
fn test_tokenize_empty() {
    assert tokenize( ~"" ) == ~[];
}

#[test]
fn test_tokenize_no_spaces() {
    assert tokenize( ~"one" ) == ~[~"one"];
}

#[test]
fn test_pad_parentheses() {
    assert pad_parentheses( ~"(1 2 3)" ) == ~" ( 1 2 3 ) "
}

#[test]
fn test_pad_parentheses_empty() {
    assert pad_parentheses( ~"" ) == ~""
}

#[test]
fn test_pad_parentheses_one() {
    assert pad_parentheses( ~"(" ) == ~" ( ";
    assert pad_parentheses( ~")" ) == ~" ) ";
}

fn pad_parentheses( input:&str ) -> ~str {
    str::replace(str::replace(input, ")", " ) "), "(", " ( ")
}

fn tokenize( input:&str ) -> ~[~str] {
    str::words(pad_parentheses(input))
}

#[test]
fn test_that_atom_can_read_bools() {
    assert atom(~"#t") == Bool(true)
}

#[test]
fn test_that_atom_can_read_a_symbol() {
    match atom(~"hello") {
        Symbol(~"hello") => (),
            _ => fail
    }
}

#[test]
fn test_that_a_plus_sign_becomes_a_symbol() {
    match atom(~"+") {
        Symbol(~"+") => (),
        _ => fail fmt!("+ became: %s", atom(~"+").to_str())
    }
}

#[test]
fn test_that_a_minus_sign_becomes_a_symbol() {
    match atom(~"-") {
        Symbol(~"-") => (),
        _ => fail fmt!("- became: %s", atom(~"-").to_str())
    }
}

#[test]
fn test_that_atom_can_read_an_int() {
    match atom(~"10") {
        Int(10) => (),
            _ => fail
    }
}

#[test]
fn test_that_atom_can_read_a_float() {
    match atom(~"10.1") {
        Float(10.1) => (),
            _ => fail
    }
}

fn atom( input:~str ) -> Expression {
    match input {
        ~"#t" => Bool( true ),
        ~"#f" => Bool( false ),
        ~"+" => Symbol( ~"+" ),
        ~"-" => Symbol( ~"-" ),
        _ => match int::from_str(input) {
            Some(number) => Int(number),
            None => match float::from_str(input) {
                Some(number) => Float(number),
                None => Symbol(input)
            }
        }
    }
}

#[test]
fn test_that_read_can_read_an_atom() {
    let atom = read( ~[~"12"] );
    match atom {
        Int(12) => (),
            _ => fail
    }
}

#[test]
fn test_that_read_can_read_a_list() {
    let list = read( ~[ ~"(", ~"1", ~")" ] );
    match list {
        List([Int(1)]) => (),
            _ => fail ~"not a list"
    }
}

#[test]
fn test_that_read_can_read_a_nested_list() {
    let list = read( ~[ ~"(", ~"1", ~"(", ~"2", ~")", ~"3", ~")" ] );
    match list {
        List([Int(1), List([Int(2)]), Int(3)]) => (),
        _ => fail
    }
}

fn read( tokens:~[~str] ) -> Expression {
    fn subexpression( tokens:~[~str] ) -> (Expression, ~[~str]) {
        let mut remainder = copy tokens;
        let token = remainder.remove(0);
        match token {
            ~"(" => {
                let mut accumulator:~[Expression] = ~[];
                while remainder.len() > 0 && remainder[0] != ~")" {
                    let (expr, new_remainder) = subexpression( remainder );
                    accumulator.push(expr);
                    remainder = new_remainder
                }
                if remainder.len() == 0 {
                    (Error(~"Unexpected end of input (mismatched parens?)"), remainder)
                } else {
                    // remove the close paren
                    remainder.remove(0);
                    (List(accumulator), remainder)
                }
            }
            ~")" => fail,
            _ => (atom(token), remainder)
        }
    }

    let (expression, _remainder) = subexpression( tokens );
    expression
}

pub fn parse( program:&str ) -> Expression {
    read( tokenize( program ) )
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 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.

//! An implementation of SipHash 2-4.

use ptr;
use prelude::*;
use super::Hasher;

/// An implementation of SipHash 2-4.
///
/// See: http://131002.net/siphash/
///
/// Consider this as a main "general-purpose" hash for all hashtables: it
/// runs at good speed (competitive with spooky and city) and permits
/// strong _keyed_ hashing. Key your hashtables from a strong RNG,
/// such as `rand::Rng`.
///
/// Although the SipHash algorithm is considered to be cryptographically
/// strong, this implementation has not been reviewed for such purposes.
/// As such, all cryptographic uses of this implementation are strongly
/// discouraged.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct SipHasher {
    k0: u64,
    k1: u64,
    length: usize, // how many bytes we've processed
    v0: u64,      // hash state
    v1: u64,
    v2: u64,
    v3: u64,
    tail: u64, // unprocessed bytes le
    ntail: usize,  // how many bytes in tail are valid
}

// sadly, these macro definitions can't appear later,
// because they're needed in the following defs;
// this design could be improved.

macro_rules! u8to64_le {
    ($buf:expr, $i:expr) =>
    ($buf[0+$i] as u64 |
     ($buf[1+$i] as u64) << 8 |
     ($buf[2+$i] as u64) << 16 |
     ($buf[3+$i] as u64) << 24 |
     ($buf[4+$i] as u64) << 32 |
     ($buf[5+$i] as u64) << 40 |
     ($buf[6+$i] as u64) << 48 |
     ($buf[7+$i] as u64) << 56);
    ($buf:expr, $i:expr, $len:expr) =>
    ({
        let mut t = 0;
        let mut out = 0;
        while t < $len {
            out |= ($buf[t+$i] as u64) << t*8;
            t += 1;
        }
        out
    });
}

/// Load a full u64 word from a byte stream, in LE order. Use
/// `copy_nonoverlapping` to let the compiler generate the most efficient way
/// to load u64 from a possibly unaligned address.
///
/// Unsafe because: unchecked indexing at i..i+8
#[inline]
unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
    debug_assert!(i + 8 <= buf.len());
    let mut data = 0u64;
    ptr::copy_nonoverlapping(buf.get_unchecked(i),
                             &mut data as *mut _ as *mut u8, 8);
    data.to_le()
}

macro_rules! rotl {
    ($x:expr, $b:expr) =>
    (($x << $b) | ($x >> (64_i32.wrapping_sub($b))))
}

macro_rules! compress {
    ($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
    ({
        $v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0;
        $v0 = rotl!($v0, 32);
        $v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2;
        $v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0;
        $v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2;
        $v2 = rotl!($v2, 32);
    })
}

impl SipHasher {
    /// Creates a new `SipHasher` with the two initial keys set to 0.
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new() -> SipHasher {
        SipHasher::new_with_keys(0, 0)
    }

    /// Creates a `SipHasher` that is keyed off the provided keys.
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
        let mut state = SipHasher {
            k0: key0,
            k1: key1,
            length: 0,
            v0: 0,
            v1: 0,
            v2: 0,
            v3: 0,
            tail: 0,
            ntail: 0,
        };
        state.reset();
        state
    }

    #[inline]
    fn reset(&mut self) {
        self.length = 0;
        self.v0 = self.k0 ^ 0x736f6d6570736575;
        self.v1 = self.k1 ^ 0x646f72616e646f6d;
        self.v2 = self.k0 ^ 0x6c7967656e657261;
        self.v3 = self.k1 ^ 0x7465646279746573;
        self.ntail = 0;
    }

    #[inline]
    fn write(&mut self, msg: &[u8]) {
        let length = msg.len();
        self.length += length;

        let mut needed = 0;

        if self.ntail != 0 {
            needed = 8 - self.ntail;
            if length < needed {
                self.tail |= u8to64_le!(msg, 0, length) << 8*self.ntail;
                self.ntail += length;
                return
            }

            let m = self.tail | u8to64_le!(msg, 0, needed) << 8*self.ntail;

            self.v3 ^= m;
            compress!(self.v0, self.v1, self.v2, self.v3);
            compress!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= m;

            self.ntail = 0;
        }

        // Buffered tail is now flushed, process new input.
        let len = length - needed;
        let left = len & 0x7;

        let mut i = needed;
        while i < len - left {
            let mi = unsafe { load_u64_le(msg, i) };

            self.v3 ^= mi;
            compress!(self.v0, self.v1, self.v2, self.v3);
            compress!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= mi;

            i += 8;
        }

        self.tail = u8to64_le!(msg, i, left);
        self.ntail = left;
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Hasher for SipHasher {
    #[inline]
    fn write(&mut self, msg: &[u8]) {
        self.write(msg)
    }

    #[inline]
    fn finish(&self) -> u64 {
        let mut v0 = self.v0;
        let mut v1 = self.v1;
        let mut v2 = self.v2;
        let mut v3 = self.v3;

        let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;

        v3 ^= b;
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        v0 ^= b;

        v2 ^= 0xff;
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);

        v0 ^ v1 ^ v2 ^ v3
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Clone for SipHasher {
    #[inline]
    fn clone(&self) -> SipHasher {
        SipHasher {
            k0: self.k0,
            k1: self.k1,
            length: self.length,
            v0: self.v0,
            v1: self.v1,
            v2: self.v2,
            v3: self.v3,
            tail: self.tail,
            ntail: self.ntail,
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Default for SipHasher {
    fn default() -> SipHasher {
        SipHasher::new()
    }
}
<commit_msg>siphash: Reorder hash state in the struct<commit_after>// Copyright 2012-2015 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.

//! An implementation of SipHash 2-4.

use ptr;
use prelude::*;
use super::Hasher;

/// An implementation of SipHash 2-4.
///
/// See: http://131002.net/siphash/
///
/// Consider this as a main "general-purpose" hash for all hashtables: it
/// runs at good speed (competitive with spooky and city) and permits
/// strong _keyed_ hashing. Key your hashtables from a strong RNG,
/// such as `rand::Rng`.
///
/// Although the SipHash algorithm is considered to be cryptographically
/// strong, this implementation has not been reviewed for such purposes.
/// As such, all cryptographic uses of this implementation are strongly
/// discouraged.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct SipHasher {
    k0: u64,
    k1: u64,
    length: usize, // how many bytes we've processed
    // v0, v2 and v1, v3 show up in pairs in the algorithm,
    // and simd implementations of SipHash will use vectors
    // of v02 and v13. By placing them in this order in the struct,
    // the compiler can pick up on just a few simd optimizations by itself.
    v0: u64,      // hash state
    v2: u64,
    v1: u64,
    v3: u64,
    tail: u64, // unprocessed bytes le
    ntail: usize,  // how many bytes in tail are valid
}

// sadly, these macro definitions can't appear later,
// because they're needed in the following defs;
// this design could be improved.

macro_rules! u8to64_le {
    ($buf:expr, $i:expr) =>
    ($buf[0+$i] as u64 |
     ($buf[1+$i] as u64) << 8 |
     ($buf[2+$i] as u64) << 16 |
     ($buf[3+$i] as u64) << 24 |
     ($buf[4+$i] as u64) << 32 |
     ($buf[5+$i] as u64) << 40 |
     ($buf[6+$i] as u64) << 48 |
     ($buf[7+$i] as u64) << 56);
    ($buf:expr, $i:expr, $len:expr) =>
    ({
        let mut t = 0;
        let mut out = 0;
        while t < $len {
            out |= ($buf[t+$i] as u64) << t*8;
            t += 1;
        }
        out
    });
}

/// Load a full u64 word from a byte stream, in LE order. Use
/// `copy_nonoverlapping` to let the compiler generate the most efficient way
/// to load u64 from a possibly unaligned address.
///
/// Unsafe because: unchecked indexing at i..i+8
#[inline]
unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
    debug_assert!(i + 8 <= buf.len());
    let mut data = 0u64;
    ptr::copy_nonoverlapping(buf.get_unchecked(i),
                             &mut data as *mut _ as *mut u8, 8);
    data.to_le()
}

macro_rules! rotl {
    ($x:expr, $b:expr) =>
    (($x << $b) | ($x >> (64_i32.wrapping_sub($b))))
}

macro_rules! compress {
    ($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
    ({
        $v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0;
        $v0 = rotl!($v0, 32);
        $v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2;
        $v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0;
        $v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2;
        $v2 = rotl!($v2, 32);
    })
}

impl SipHasher {
    /// Creates a new `SipHasher` with the two initial keys set to 0.
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new() -> SipHasher {
        SipHasher::new_with_keys(0, 0)
    }

    /// Creates a `SipHasher` that is keyed off the provided keys.
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
        let mut state = SipHasher {
            k0: key0,
            k1: key1,
            length: 0,
            v0: 0,
            v1: 0,
            v2: 0,
            v3: 0,
            tail: 0,
            ntail: 0,
        };
        state.reset();
        state
    }

    #[inline]
    fn reset(&mut self) {
        self.length = 0;
        self.v0 = self.k0 ^ 0x736f6d6570736575;
        self.v1 = self.k1 ^ 0x646f72616e646f6d;
        self.v2 = self.k0 ^ 0x6c7967656e657261;
        self.v3 = self.k1 ^ 0x7465646279746573;
        self.ntail = 0;
    }

    #[inline]
    fn write(&mut self, msg: &[u8]) {
        let length = msg.len();
        self.length += length;

        let mut needed = 0;

        if self.ntail != 0 {
            needed = 8 - self.ntail;
            if length < needed {
                self.tail |= u8to64_le!(msg, 0, length) << 8*self.ntail;
                self.ntail += length;
                return
            }

            let m = self.tail | u8to64_le!(msg, 0, needed) << 8*self.ntail;

            self.v3 ^= m;
            compress!(self.v0, self.v1, self.v2, self.v3);
            compress!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= m;

            self.ntail = 0;
        }

        // Buffered tail is now flushed, process new input.
        let len = length - needed;
        let left = len & 0x7;

        let mut i = needed;
        while i < len - left {
            let mi = unsafe { load_u64_le(msg, i) };

            self.v3 ^= mi;
            compress!(self.v0, self.v1, self.v2, self.v3);
            compress!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= mi;

            i += 8;
        }

        self.tail = u8to64_le!(msg, i, left);
        self.ntail = left;
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Hasher for SipHasher {
    #[inline]
    fn write(&mut self, msg: &[u8]) {
        self.write(msg)
    }

    #[inline]
    fn finish(&self) -> u64 {
        let mut v0 = self.v0;
        let mut v1 = self.v1;
        let mut v2 = self.v2;
        let mut v3 = self.v3;

        let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;

        v3 ^= b;
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        v0 ^= b;

        v2 ^= 0xff;
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);

        v0 ^ v1 ^ v2 ^ v3
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Clone for SipHasher {
    #[inline]
    fn clone(&self) -> SipHasher {
        SipHasher {
            k0: self.k0,
            k1: self.k1,
            length: self.length,
            v0: self.v0,
            v1: self.v1,
            v2: self.v2,
            v3: self.v3,
            tail: self.tail,
            ntail: self.ntail,
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Default for SipHasher {
    fn default() -> SipHasher {
        SipHasher::new()
    }
}
<|endoftext|>


<commit_before>use std::fs::read_link;
use std::path::Path;

pub fn container_ver(name: &String) -> Result<String, String> {
    let lnk = try!(read_link(&Path::new("/work/.vagga")
                             .join(name.as_slice()))
                   .map_err(|e| format!("Error reading link: {}", e)));
    let lnkcmp = lnk.str_components().collect::<Vec<Option<&str>>>();
    if lnkcmp.len() < 3 || lnkcmp[lnkcmp.len()-2].is_none() {
        return Err(format!("Broken container link"));
    }
    return Ok(lnkcmp[lnkcmp.len()-2].unwrap().to_string());
}
<commit_msg>Fix container/vagga.rs<commit_after>use std::fs::read_link;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;

pub fn container_ver(name: &String) -> Result<String, String> {
    let lnk = try!(read_link(&Path::new("/work/.vagga").join(&name))
                   .map_err(|e| format!("Error reading link: {}", e)));
    let lnkcmp = lnk.iter().collect::<Vec<_>>();
    if lnkcmp.len() < 3 || lnkcmp[lnkcmp.len()-2].to_str().is_none() {
        return Err(format!("Broken container link"));
    }
    return Ok(lnkcmp[lnkcmp.len()-2].to_str().unwrap().to_string());
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use core::types::{ZInt, MapPos, Size2};
use core::core::{ObjectTypes, Unit, UnitClass};
use core::map;
use core::game_state::{GameState};
use core::dir::{Dir};

#[derive(Clone)]
pub struct MoveCost{pub n: ZInt}

#[derive(Clone)]
pub struct MapPath {
    nodes: Vec<(MoveCost, MapPos)>,
    total_cost: MoveCost,
}

impl MapPath {
    // pub fn len(&self) -> ZInt {
    //     self.nodes.len() as ZInt
    // }

    pub fn destination(&self) -> &MapPos {
        let &(_, ref pos) = self.nodes.last().unwrap();
        pos
    }

    pub fn nodes(&self) -> &Vec<(MoveCost, MapPos)> {
        &self.nodes
    }

    pub fn total_cost(&self) -> &MoveCost {
        &self.total_cost
    }
}

struct Tile {
    cost: MoveCost,
    parent: Option<Dir>,
}

impl Tile {
    pub fn parent(&self) -> &Option<Dir> { &self.parent }
}

struct Map {
    size: Size2<ZInt>,
    tiles: Vec<Tile>,
}

const MAX_COST: MoveCost = MoveCost{n: 30000};

impl<'a> Map {
    pub fn tile_mut(&'a mut self, pos: &MapPos) -> &'a mut Tile {
        self.tiles.get_mut((pos.v.x + pos.v.y * self.size.w) as usize)
            .expect("bad tile index")
    }

    pub fn tile(&'a self, pos: &MapPos) -> &'a Tile {
        assert!(self.is_inboard(pos));
        &self.tiles[(pos.v.x + pos.v.y * self.size.w) as usize]
    }

    pub fn is_inboard(&self, pos: &MapPos) -> bool {
        let x = pos.v.x;
        let y = pos.v.y;
        x >= 0 && y >= 0 && x < self.size.w && y < self.size.h
    }

    pub fn get_size(&self) -> &Size2<ZInt> {
        &self.size
    }
}

pub struct Pathfinder {
    queue: Vec<MapPos>,
    map: Map,
}

fn create_tiles(tiles_count: ZInt) -> Vec<Tile> {
    let mut tiles = Vec::new();
    for _ in range(0, tiles_count) {
        tiles.push(Tile {
            cost: MoveCost{n: 0},
            parent: None,
        });
    }
    tiles
}

impl Pathfinder {
    pub fn new(map_size: &Size2<ZInt>) -> Pathfinder {
        let tiles_count = map_size.w * map_size.h;
        Pathfinder {
            queue: Vec::new(),
            map: Map {
                size: map_size.clone(),
                tiles: create_tiles(tiles_count),
            },
        }
    }

    pub fn get_map(&self) -> &Map {
        &self.map
    }

    fn tile_cost(
        &self,
        object_types: &ObjectTypes,
        state: &GameState,
        unit: &Unit,
        pos: &MapPos,
    ) -> ZInt { // TODO: ZInt -> MoveCost
        let unit_type = object_types.get_unit_type(&unit.type_id);
        let tile = state.map.tile(pos);
        match unit_type.class {
            UnitClass::Infantry => match tile {
                &map::Tile::Plain => 1,
                &map::Tile::Trees => 2,
                &map::Tile::Building => 2,
            },
            UnitClass::Vehicle => match tile {
                &map::Tile::Plain => 1,
                &map::Tile::Trees => 5,
                &map::Tile::Building => 10,
            },
        }
    }

    fn process_neighbour_pos(
        &mut self,
        object_types: &ObjectTypes,
        state: &GameState,
        unit: &Unit,
        original_pos: &MapPos,
        neighbour_pos: &MapPos
    ) {
        let old_cost = self.map.tile(original_pos).cost.clone();
        let tile_cost = self.tile_cost(object_types, state, unit, neighbour_pos);
        let tile = self.map.tile_mut(neighbour_pos);
        let new_cost = MoveCost{n: old_cost.n + tile_cost};
        let units_count = state.units_at(neighbour_pos).len();
        if tile.cost.n > new_cost.n
            && units_count == 0
            && new_cost.n <= unit.move_points
        {
            tile.cost = new_cost;
            tile.parent = Some(Dir::get_dir_from_to(
                neighbour_pos, original_pos));
            self.queue.push(neighbour_pos.clone());
        }
    }

    fn clean_map(&mut self) {
        for tile in self.map.tiles.iter_mut() {
            tile.cost = MAX_COST;
            tile.parent = None;
        }
    }

    fn try_to_push_neighbours(
        &mut self,
        object_types: &ObjectTypes,
        state: &GameState,
        unit: &Unit,
        pos: MapPos,
    ) {
        assert!(self.map.is_inboard(&pos));
        for i in range(0, 6) {
            let dir = Dir::from_int(i as ZInt);
            let neighbour_pos = Dir::get_neighbour_pos(&pos, &dir);
            if self.map.is_inboard(&neighbour_pos) {
                self.process_neighbour_pos(
                    object_types, state, unit, &pos, &neighbour_pos);
            }
        }
    }

    fn push_start_pos_to_queue(&mut self, start_pos: MapPos) {
        let start_tile = self.map.tile_mut(&start_pos);
        start_tile.cost = MoveCost{n: 0};
        start_tile.parent = None;
        self.queue.push(start_pos);
    }

    pub fn fill_map(&mut self, object_types: &ObjectTypes, state: &GameState, unit: &Unit) {
        assert!(self.queue.len() == 0);
        self.clean_map();
        self.push_start_pos_to_queue(unit.pos.clone());
        while self.queue.len() != 0 {
            let pos = self.queue.remove(0);
            self.try_to_push_neighbours(object_types, state, unit, pos);
        }
    }

    /*
    pub fn is_reachable(&self, pos: &MapPos) -> bool {
        self.map.tile(pos).cost.n != MAX_COST.n
    }
    */

    pub fn get_path(&self, destination: &MapPos) -> Option<MapPath> {
        let mut total_cost = MoveCost{n: 0};
        let mut path = Vec::new();
        let mut pos = destination.clone();
        if self.map.tile(&pos).cost.n == MAX_COST.n {
            return None;
        }
        assert!(self.map.is_inboard(&pos));
        path.push((MoveCost{n: 0}, destination.clone()));
        while self.map.tile(&pos).cost.n != 0 {
            let parent_dir = match self.map.tile(&pos).parent() {
                &Some(ref dir) => dir,
                &None => return None,
            };
            pos = Dir::get_neighbour_pos(&pos, parent_dir);
            assert!(self.map.is_inboard(&pos));
            // let tile_cost = self.tile_cost(object_types, state, unit, pos); // TODO: use actual cost
            let cost = MoveCost{n: 1}; // ...
            total_cost.n += cost.n;
            path.push((cost, pos.clone()));
        }
        path.reverse();
        Some(MapPath {
            nodes: path,
            total_cost: total_cost,
        })
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>Fixed costs of PathNodes<commit_after>// See LICENSE file for copyright and license details.

use core::types::{ZInt, MapPos, Size2};
use core::core::{ObjectTypes, Unit, UnitClass};
use core::map;
use core::game_state::{GameState};
use core::dir::{Dir};

#[derive(Clone)]
pub struct MoveCost{pub n: ZInt}

#[derive(Clone)]
pub struct MapPath {
    nodes: Vec<(MoveCost, MapPos)>,
    total_cost: MoveCost,
}

impl MapPath {
    // pub fn len(&self) -> ZInt {
    //     self.nodes.len() as ZInt
    // }

    pub fn destination(&self) -> &MapPos {
        let &(_, ref pos) = self.nodes.last().unwrap();
        pos
    }

    pub fn nodes(&self) -> &Vec<(MoveCost, MapPos)> {
        &self.nodes
    }

    pub fn total_cost(&self) -> &MoveCost {
        &self.total_cost
    }
}

struct Tile {
    cost: MoveCost,
    parent: Option<Dir>,
}

impl Tile {
    pub fn parent(&self) -> &Option<Dir> { &self.parent }
}

struct Map {
    size: Size2<ZInt>,
    tiles: Vec<Tile>,
}

const MAX_COST: MoveCost = MoveCost{n: 30000};

impl<'a> Map {
    pub fn tile_mut(&'a mut self, pos: &MapPos) -> &'a mut Tile {
        self.tiles.get_mut((pos.v.x + pos.v.y * self.size.w) as usize)
            .expect("bad tile index")
    }

    pub fn tile(&'a self, pos: &MapPos) -> &'a Tile {
        assert!(self.is_inboard(pos));
        &self.tiles[(pos.v.x + pos.v.y * self.size.w) as usize]
    }

    pub fn is_inboard(&self, pos: &MapPos) -> bool {
        let x = pos.v.x;
        let y = pos.v.y;
        x >= 0 && y >= 0 && x < self.size.w && y < self.size.h
    }

    pub fn get_size(&self) -> &Size2<ZInt> {
        &self.size
    }
}

pub struct Pathfinder {
    queue: Vec<MapPos>,
    map: Map,
}

fn create_tiles(tiles_count: ZInt) -> Vec<Tile> {
    let mut tiles = Vec::new();
    for _ in range(0, tiles_count) {
        tiles.push(Tile {
            cost: MoveCost{n: 0},
            parent: None,
        });
    }
    tiles
}

impl Pathfinder {
    pub fn new(map_size: &Size2<ZInt>) -> Pathfinder {
        let tiles_count = map_size.w * map_size.h;
        Pathfinder {
            queue: Vec::new(),
            map: Map {
                size: map_size.clone(),
                tiles: create_tiles(tiles_count),
            },
        }
    }

    pub fn get_map(&self) -> &Map {
        &self.map
    }

    fn tile_cost(
        &self,
        object_types: &ObjectTypes,
        state: &GameState,
        unit: &Unit,
        pos: &MapPos,
    ) -> ZInt { // TODO: ZInt -> MoveCost
        let unit_type = object_types.get_unit_type(&unit.type_id);
        let tile = state.map.tile(pos);
        match unit_type.class {
            UnitClass::Infantry => match tile {
                &map::Tile::Plain => 1,
                &map::Tile::Trees => 2,
                &map::Tile::Building => 2,
            },
            UnitClass::Vehicle => match tile {
                &map::Tile::Plain => 1,
                &map::Tile::Trees => 5,
                &map::Tile::Building => 10,
            },
        }
    }

    fn process_neighbour_pos(
        &mut self,
        object_types: &ObjectTypes,
        state: &GameState,
        unit: &Unit,
        original_pos: &MapPos,
        neighbour_pos: &MapPos
    ) {
        let old_cost = self.map.tile(original_pos).cost.clone();
        let tile_cost = self.tile_cost(object_types, state, unit, neighbour_pos);
        let tile = self.map.tile_mut(neighbour_pos);
        let new_cost = MoveCost{n: old_cost.n + tile_cost};
        let units_count = state.units_at(neighbour_pos).len();
        if tile.cost.n > new_cost.n
            && units_count == 0
            && new_cost.n <= unit.move_points
        {
            tile.cost = new_cost;
            tile.parent = Some(Dir::get_dir_from_to(
                neighbour_pos, original_pos));
            self.queue.push(neighbour_pos.clone());
        }
    }

    fn clean_map(&mut self) {
        for tile in self.map.tiles.iter_mut() {
            tile.cost = MAX_COST;
            tile.parent = None;
        }
    }

    fn try_to_push_neighbours(
        &mut self,
        object_types: &ObjectTypes,
        state: &GameState,
        unit: &Unit,
        pos: MapPos,
    ) {
        assert!(self.map.is_inboard(&pos));
        for i in range(0, 6) {
            let dir = Dir::from_int(i as ZInt);
            let neighbour_pos = Dir::get_neighbour_pos(&pos, &dir);
            if self.map.is_inboard(&neighbour_pos) {
                self.process_neighbour_pos(
                    object_types, state, unit, &pos, &neighbour_pos);
            }
        }
    }

    fn push_start_pos_to_queue(&mut self, start_pos: MapPos) {
        let start_tile = self.map.tile_mut(&start_pos);
        start_tile.cost = MoveCost{n: 0};
        start_tile.parent = None;
        self.queue.push(start_pos);
    }

    pub fn fill_map(&mut self, object_types: &ObjectTypes, state: &GameState, unit: &Unit) {
        assert!(self.queue.len() == 0);
        self.clean_map();
        self.push_start_pos_to_queue(unit.pos.clone());
        while self.queue.len() != 0 {
            let pos = self.queue.remove(0);
            self.try_to_push_neighbours(object_types, state, unit, pos);
        }
    }

    /*
    pub fn is_reachable(&self, pos: &MapPos) -> bool {
        self.map.tile(pos).cost.n != MAX_COST.n
    }
    */

    pub fn get_path(&self, destination: &MapPos) -> Option<MapPath> {
        let total_cost = self.map.tile(destination).cost.clone();
        let mut path = Vec::new();
        let mut pos = destination.clone();
        if self.map.tile(&pos).cost.n == MAX_COST.n {
            return None;
        }
        assert!(self.map.is_inboard(&pos));
        let start_cost = self.map.tile(&pos).cost.clone();
        path.push((start_cost, pos.clone()));
        while self.map.tile(&pos).cost.n != 0 {
            let parent_dir = match self.map.tile(&pos).parent() {
                &Some(ref dir) => dir,
                &None => return None,
            };
            pos = Dir::get_neighbour_pos(&pos, parent_dir);
            assert!(self.map.is_inboard(&pos));
            let cost = self.map.tile(&pos).cost.clone();
            path.push((cost, pos.clone()));
        }
        path.reverse();
        Some(MapPath {
            nodes: path,
            total_cost: total_cost,
        })
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// 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; either
// version 2.1 of the License, or (at your option) any later version.
//
// 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

use ffi;
use gstr;
use types::gchar;

use std::mem;
use std::str;
use std::sync::atomic;

#[deriving(Copy, Eq, PartialEq)]
pub struct Quark(ffi::GQuark);

pub struct StaticQuark(pub &'static [u8], pub atomic::AtomicUint);

impl Quark {

    #[inline]
    pub unsafe fn new(raw: ffi::GQuark) -> Quark {
        Quark(raw)
    }

    #[inline]
    pub fn from_static_str(s: &'static str) -> Quark {
        debug_assert!(s.ends_with("\0"));
        unsafe {
            let p = s.as_ptr() as *const gchar;
            Quark::new(ffi::g_quark_from_static_string(p))
        }
    }

    #[inline]
    pub fn to_uint(&self) -> uint {
        let Quark(raw) = *self;
        raw as uint
    }

    pub fn to_bytes(&self) -> &'static [u8] {
        let Quark(raw) = *self;
        unsafe {
            let s = ffi::g_quark_to_string(raw);
            let r = mem::copy_lifetime("", &s);
            gstr::parse_as_bytes(r)
        }
    }

    #[inline]
    pub fn to_str(&self) -> Result<&'static str, str::Utf8Error> {
        str::from_utf8(self.to_bytes())
    }
}

impl StaticQuark {

    pub fn get(&self) -> Quark {
        let StaticQuark(s, ref cached) = *self;
        let mut q = cached.load(atomic::Ordering::Relaxed);
        if q == 0 {
            unsafe {
                let p = s.as_ptr() as *const gchar;
                q = ffi::g_quark_from_static_string(p) as uint;
            }
            cached.store(q, atomic::Ordering::Relaxed);
        }
        unsafe { Quark::new(q as ffi::GQuark) }
    }
}
<commit_msg>Added Quark::from_static_bytes<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// 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; either
// version 2.1 of the License, or (at your option) any later version.
//
// 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

use ffi;
use gstr;
use types::gchar;

use std::mem;
use std::str;
use std::sync::atomic;

#[deriving(Copy, Eq, PartialEq)]
pub struct Quark(ffi::GQuark);

pub struct StaticQuark(pub &'static [u8], pub atomic::AtomicUint);

impl Quark {

    #[inline]
    pub unsafe fn new(raw: ffi::GQuark) -> Quark {
        Quark(raw)
    }

    #[inline]
    pub fn from_static_str(s: &'static str) -> Quark {
        Quark::from_static_bytes(s.as_bytes())
    }

    pub fn from_static_bytes(s: &'static [u8]) -> Quark {
        assert!(s[s.len() - 1] == 0);
        unsafe {
            let p = s.as_ptr() as *const gchar;
            let q = ffi::g_quark_from_static_string(p);
            Quark::new(q)
        }
    }

    #[inline]
    pub fn to_uint(&self) -> uint {
        let Quark(raw) = *self;
        raw as uint
    }

    pub fn to_bytes(&self) -> &'static [u8] {
        let Quark(raw) = *self;
        unsafe {
            let s = ffi::g_quark_to_string(raw);
            let r = mem::copy_lifetime("", &s);
            gstr::parse_as_bytes(r)
        }
    }

    #[inline]
    pub fn to_str(&self) -> Result<&'static str, str::Utf8Error> {
        str::from_utf8(self.to_bytes())
    }
}

impl StaticQuark {

    pub fn get(&self) -> Quark {
        let StaticQuark(s, ref cached) = *self;
        let mut q = cached.load(atomic::Ordering::Relaxed);
        if q == 0 {
            unsafe {
                let p = s.as_ptr() as *const gchar;
                q = ffi::g_quark_from_static_string(p) as uint;
            }
            cached.store(q, atomic::Ordering::Relaxed);
        }
        unsafe { Quark::new(q as ffi::GQuark) }
    }
}
<|endoftext|>


<commit_before>use std::io::IoError;
use std::os::errno;
use std::ptr::null;
use std::time::Duration;
use std::collections::PriorityQueue;
use std::collections::HashMap;
use time::{Timespec, get_time};
use libc::{c_int, c_void};
use libc::consts::os::posix88::{EINTR, ETIMEDOUT, EAGAIN, ECHILD};
use libc::consts::os::posix88::{SIGTERM, SIGINT, SIGQUIT};

use super::signal;

static SIGCHLD: c_int = 17;

pub enum Event<Name> {
    Signal(signal::Signal),
    Timeout(Name),
    Input(Name),
}

struct FileDesc(c_int);

struct Unordered<T>(T);

impl<T> PartialOrd for Unordered<T> {
    fn partial_cmp(&self, _: &Unordered<T>) -> Option<Ordering> { Some(Equal) }
}
impl<T> Ord for Unordered<T> {
    fn cmp(&self, _: &Unordered<T>) -> Ordering { Equal }
}
impl<T> PartialEq for Unordered<T> {
    fn eq(&self, _: &Unordered<T>) -> bool { false }
}
impl<T> Eq for Unordered<T> {}

pub struct Loop<Name> {
    queue: PriorityQueue<(i64, Unordered<Name>)>,
    epoll_fd: FileDesc,
    signal_fd: FileDesc,
    inputs: HashMap<c_int, Name>,
}

extern {
    fn create_epoll() -> c_int;
    fn create_signalfd() -> c_int;
    fn close(fd: c_int) -> c_int;
    fn epoll_add_read(efd: c_int, fd: c_int) -> c_int;
    fn epoll_wait_read(epfd: c_int, timeout: c_int) -> c_int;
    fn read_signal(rd: c_int) -> c_int;
}

pub fn time_to_ms(ts: Timespec) -> i64 {
    return (ts.sec as i64) * 1000 + (ts.nsec as i64) / 1000000;
}

pub fn get_time_ms() -> i64 {
    return time_to_ms(get_time());
}

impl<Name: Clone> Loop<Name> {
    pub fn new() -> Result<Loop<Name>, IoError> {
        let efd = unsafe { create_epoll() };
        if efd < 0 {
            return Err(IoError::last_error());
        }
        let epoll = FileDesc(efd);
        let sfd = unsafe { create_signalfd() };
        if sfd < 0 {
            return Err(IoError::last_error());
        }
        let sig = FileDesc(sfd);
        if unsafe { epoll_add_read(efd, sfd) } < 0 {
            return Err(IoError::last_error());
        }
        return Ok(Loop {
            queue: PriorityQueue::new(),
            epoll_fd: epoll,
            signal_fd: sig,
            inputs: HashMap::new(),
        });
    }
    pub fn add_timeout(&mut self, duration: Duration, name: Name) {
        self.queue.push((-time_to_ms(get_time() + duration), Unordered(name)));
    }
    fn get_timeout(&mut self) -> c_int {
        self.queue.top()
            .map(|&(ts, _)| (-ts) - get_time_ms())
            .map(|ts| if ts >= 0 { ts } else { 0 })
            .unwrap_or(-1)
            as i32
    }
    pub fn poll(&mut self) -> Event<Name> {
        loop {
            if let Some(sig) = signal::check_children() {
                return Signal(sig);
            }
            let timeo = self.get_timeout();
            let FileDesc(sfd) = self.signal_fd;
            let FileDesc(efd) = self.epoll_fd;
            let fd = unsafe { epoll_wait_read(efd, timeo) };
            if fd == -ETIMEDOUT { // Timeout
                debug!("Timeout");
                if self.get_timeout() != 0 {
                    continue;
                }
                let (_, Unordered(name)) = self.queue.pop().unwrap();
                return Timeout(name);
            } else if fd == -EINTR {
                continue
            } else if fd < 0 {
                fail!(format!("Error in epoll: {}", IoError::last_error()));
            } else if fd == sfd { // Signal
                debug!("Signal");
                let rc =  unsafe { read_signal(sfd) };
                if rc == EINTR || rc == EAGAIN {
                    continue;
                } else if rc <= 0 {
                    fail!(format!("Error in read_signal: {}",
                        IoError::last_error()));
                } else {
                    match rc {
                        sig@SIGTERM | sig@SIGINT | sig@SIGQUIT => {
                            return Signal(signal::Terminate(sig as int));
                        }
                        SIGCHLD => {
                            continue;  // Will waitpid on next iteration
                        }
                        _ => {
                            warn!("Signal {} ignored", rc);
                            continue;
                        }
                    }
                }
            } else {
                debug!("Input {}", fd);
                return Input(self.inputs[fd].clone());
            }
            unreachable!();
        }
    }
}

impl Drop for FileDesc {
    fn drop(&mut self) {
        let FileDesc(fd) = *self;
        unsafe { close(fd) };
    }
}
<commit_msg>Fix bug in signal reading loop<commit_after>use std::io::IoError;
use std::os::errno;
use std::ptr::null;
use std::time::Duration;
use std::collections::PriorityQueue;
use std::collections::HashMap;
use time::{Timespec, get_time};
use libc::{c_int, c_void};
use libc::consts::os::posix88::{EINTR, ETIMEDOUT, EAGAIN, ECHILD};
use libc::consts::os::posix88::{SIGTERM, SIGINT, SIGQUIT};

use super::signal;

static SIGCHLD: c_int = 17;

pub enum Event<Name> {
    Signal(signal::Signal),
    Timeout(Name),
    Input(Name),
}

struct FileDesc(c_int);

struct Unordered<T>(T);

impl<T> PartialOrd for Unordered<T> {
    fn partial_cmp(&self, _: &Unordered<T>) -> Option<Ordering> { Some(Equal) }
}
impl<T> Ord for Unordered<T> {
    fn cmp(&self, _: &Unordered<T>) -> Ordering { Equal }
}
impl<T> PartialEq for Unordered<T> {
    fn eq(&self, _: &Unordered<T>) -> bool { false }
}
impl<T> Eq for Unordered<T> {}

pub struct Loop<Name> {
    queue: PriorityQueue<(i64, Unordered<Name>)>,
    epoll_fd: FileDesc,
    signal_fd: FileDesc,
    inputs: HashMap<c_int, Name>,
}

extern {
    fn create_epoll() -> c_int;
    fn create_signalfd() -> c_int;
    fn close(fd: c_int) -> c_int;
    fn epoll_add_read(efd: c_int, fd: c_int) -> c_int;
    fn epoll_wait_read(epfd: c_int, timeout: c_int) -> c_int;
    fn read_signal(rd: c_int) -> c_int;
}

pub fn time_to_ms(ts: Timespec) -> i64 {
    return (ts.sec as i64) * 1000 + (ts.nsec as i64) / 1000000;
}

pub fn get_time_ms() -> i64 {
    return time_to_ms(get_time());
}

impl<Name: Clone> Loop<Name> {
    pub fn new() -> Result<Loop<Name>, IoError> {
        let efd = unsafe { create_epoll() };
        if efd < 0 {
            return Err(IoError::last_error());
        }
        let epoll = FileDesc(efd);
        let sfd = unsafe { create_signalfd() };
        if sfd < 0 {
            return Err(IoError::last_error());
        }
        let sig = FileDesc(sfd);
        if unsafe { epoll_add_read(efd, sfd) } < 0 {
            return Err(IoError::last_error());
        }
        return Ok(Loop {
            queue: PriorityQueue::new(),
            epoll_fd: epoll,
            signal_fd: sig,
            inputs: HashMap::new(),
        });
    }
    pub fn add_timeout(&mut self, duration: Duration, name: Name) {
        self.queue.push((-time_to_ms(get_time() + duration), Unordered(name)));
    }
    fn get_timeout(&mut self) -> c_int {
        self.queue.top()
            .map(|&(ts, _)| (-ts) - get_time_ms())
            .map(|ts| if ts >= 0 { ts } else { 0 })
            .unwrap_or(-1)
            as i32
    }
    pub fn poll(&mut self) -> Event<Name> {
        loop {
            if let Some(sig) = signal::check_children() {
                return Signal(sig);
            }
            let timeo = self.get_timeout();
            let FileDesc(sfd) = self.signal_fd;
            let FileDesc(efd) = self.epoll_fd;
            let fd = unsafe { epoll_wait_read(efd, timeo) };
            if fd == -ETIMEDOUT { // Timeout
                debug!("Timeout");
                if self.get_timeout() != 0 {
                    continue;
                }
                let (_, Unordered(name)) = self.queue.pop().unwrap();
                return Timeout(name);
            } else if fd == -EINTR {
                continue
            } else if fd < 0 {
                fail!(format!("Error in epoll: {}", IoError::last_error()));
            } else if fd == sfd { // Signal
                debug!("Signal");
                let rc =  unsafe { read_signal(sfd) };
                if rc == -EINTR || rc == -EAGAIN {
                    continue;
                } else if rc <= 0 {
                    fail!(format!("Error in read_signal: {}",
                        IoError::last_error()));
                } else {
                    match rc {
                        sig@SIGTERM | sig@SIGINT | sig@SIGQUIT => {
                            return Signal(signal::Terminate(sig as int));
                        }
                        SIGCHLD => {
                            continue;  // Will waitpid on next iteration
                        }
                        _ => {
                            warn!("Signal {} ignored", rc);
                            continue;
                        }
                    }
                }
            } else {
                debug!("Input {}", fd);
                return Input(self.inputs[fd].clone());
            }
            unreachable!();
        }
    }
}

impl Drop for FileDesc {
    fn drop(&mut self) {
        let FileDesc(fd) = *self;
        unsafe { close(fd) };
    }
}
<|endoftext|>


<commit_before>use serde_json::value::to_value as to_json_value;

use super::base;
use config::Config;
use controller::context::{RequestContext, ResponseContext};
use controller::dto::LoginFormDto;
use model::service::DbService;

pub fn home(request: RequestContext) -> ResponseContext
{
    if let Some(_user) = request.user.as_ref() {
        base::redirect("/db/")
    } else {
        base::redirect("/user/login")
    }
}

pub fn login(request: RequestContext) -> ResponseContext
{
    if request.user.is_some() {
        return base::main_redirect_response()
    }

    let mut errors: Vec<String> = vec![];

    if request.is_post() && request.body.is_some() {
        let user = LoginFormDto::from(request.body.as_ref().unwrap()).user();
        let db = DbService::new(&user);

        match db.list() {
            Ok(db_list) => {
                let mut response = if db_list.len() > 0 {
                    base::redirect(&format!("/db/{}", db_list[0]))
                } else {
                    base::main_redirect_response()
                };
                response.user = Some(user);
                return response;
            },
            Err(error) => errors.push(format!("{}", error))
        }
    }

    base::render(&request, |_request, replacements| {
        let title = format!("{} - {}", Config::idem().app_name, "Sign In");
        replacements.insert("title".to_string(), to_json_value(title)?);
        replacements.insert("form_name".to_string(), to_json_value(LoginFormDto::form_name())?);

        replacements.insert(
            "errors".to_string(),
            to_json_value(&errors)?
        );

        Ok("user/login".to_owned())
    })
}

pub fn logout(request: RequestContext) -> ResponseContext
{
    let mut response = base::main_redirect_response();
    if request.user.is_some() {
        response.clean_user = true;
    }
    response
}<commit_msg>Change redirect for home<commit_after>use serde_json::value::to_value as to_json_value;

use super::base;
use config::Config;
use controller::context::{RequestContext, ResponseContext};
use controller::dto::LoginFormDto;
use model::service::DbService;

pub fn home(request: RequestContext) -> ResponseContext
{
    if let Some(user) = request.user.as_ref() {
        let db = DbService::new(user);

        match db.list() {
            Ok(list) => {
                if list.len() > 0 {
                    base::redirect(&format!("/db/{}", list[0]))
                } else {
                    println!("ERROR user::home - db.list for user \"{}\" is empty", user.name);
                    base::redirect("/error")
                }
            },
            Err(error) => {
                println!("ERROR user::home - {}", error);
                base::redirect("/error")
            }
        }
    } else {
        base::redirect("/user/login")
    }
}

pub fn login(request: RequestContext) -> ResponseContext
{
    if request.user.is_some() {
        return base::main_redirect_response()
    }

    let mut errors: Vec<String> = vec![];

    if request.is_post() && request.body.is_some() {
        let user = LoginFormDto::from(request.body.as_ref().unwrap()).user();
        let db = DbService::new(&user);

        match db.list() {
            Ok(list) => {
                let mut response = if list.len() > 0 {
                    base::redirect(&format!("/db/{}", list[0]))
                } else {
                    base::main_redirect_response()
                };
                response.user = Some(user);
                return response;
            },
            Err(error) => errors.push(format!("{}", error))
        }
    }

    base::render(&request, |_request, replacements| {
        let title = format!("{} - {}", Config::idem().app_name, "Sign In");
        replacements.insert("title".to_string(), to_json_value(title)?);
        replacements.insert("form_name".to_string(), to_json_value(LoginFormDto::form_name())?);

        replacements.insert(
            "errors".to_string(),
            to_json_value(&errors)?
        );

        Ok("user/login".to_owned())
    })
}

pub fn logout(request: RequestContext) -> ResponseContext
{
    let mut response = base::main_redirect_response();
    if request.user.is_some() {
        response.clean_user = true;
    }
    response
}<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs::File;
use std::vec::Vec;
use std::path::Path;
use self::Setting::*;

pub type Key = String;

#[derive(Debug)]
pub enum Setting {
	Int(isize),
	Float(f32),
	String(String),
	Vector(f32, f32),
	Bool(bool),
	Error
}

pub struct Settings<'a> {
	settings_path: Path,
	key_value_pair: HashMap<Key, Setting>

}

impl<'a> Settings<'a> {

	pub fn new(settings_path_raw: &str) -> Settings<'a>{
		let path = Path::new(settings_path_raw);

		if path.exists() {
			let contents = File::open(&path).read_to_str().unwrap();
			let key_value_pair = Settings::parse(contents);

			Settings { settings_path: path, key_value_pair: key_value_pair }
	    }
	    else {
	    	let key_value_pair = HashMap::new();

	    	Settings { settings_path: path, key_value_pair: key_value_pair }
	    }
	}

	pub fn get_setting<'a>(&'a mut self, name: Key, default_value: Setting) -> &'a mut Setting {
		return  self.key_value_pair.find_or_insert(name, default_value)
	}

	fn gen_setting(name: &str, valueStr: &str) -> Setting {

		match name.char_at(0) {

			'i' => {
				let value = isize::from_str(valueStr).unwrap();
				Int(value)
			},

			'f' => {
				let value = f32::from_str(valueStr).unwrap();
				Float(value)
			},

			's' => {
				return String(valueStr.to_owned());
			},

			'v' => {
				let floatPair : Vec<&str> = valueStr.split(' ').collect();

				let float1 = f32::from_str(*floatPair.get(0)).unwrap();
				let float2 = f32::from_str(*floatPair.get(1)).unwrap();
				Vector(float1, float2)
			},

			'b' => {
				let value = valueStr == "true";
				Bool(value)
			},

			_ => {
				Error
			}
		}
	}

	fn parse(data: String) -> HashMap<Key, Setting> {

		let mut key_value_pair = HashMap::new();

		let dataLines : Vec<&str> = data.split('\n').collect();

		for &line in dataLines.iter() {
			let dataPair : Vec<&str> = line.split(':').collect();

			if dataPair.len() != 2 {
			//	warn!("faulty data pair: {}", dataPair);
				continue;
			}

			let name = dataPair.get(0).trim();
			let valueStr = dataPair.get(1).trim();

			let setting = Settings::gen_setting(name, valueStr);

			//debug!("name: {}, Setting: {}", name, setting);
			key_value_pair.insert(name.to_owned(), setting);
		}

		key_value_pair
	}

}
<commit_msg>Simply remove the lifetime specs. and it works?<commit_after>use std::collections::HashMap;
use std::fs::File;
use std::vec::Vec;
use std::path::Path;
use self::Setting::*;

pub type Key = String;

#[derive(Debug)]
pub enum Setting {
	Int(isize),
	Float(f32),
	String(String),
	Vector(f32, f32),
	Bool(bool),
	Error
}

pub struct Settings {
	settings_path: Path,
	key_value_pair: HashMap<Key, Setting>

}

impl Settings {

	pub fn new(settings_path_raw: &str) -> Settings{
		let path = Path::new(settings_path_raw);

		if path.exists() {
			let contents = File::open(&path).read_to_str().unwrap();
			let key_value_pair = Settings::parse(contents);

			Settings { settings_path: path, key_value_pair: key_value_pair }
	    }
	    else {
	    	let key_value_pair = HashMap::new();

	    	Settings { settings_path: path, key_value_pair: key_value_pair }
	    }
	}

	pub fn get_setting(&mut self, name: Key, default_value: Setting) -> &mut Setting {
		return  self.key_value_pair.find_or_insert(name, default_value)
	}

	fn gen_setting(name: &str, valueStr: &str) -> Setting {

		match name.char_at(0) {

			'i' => {
				let value = isize::from_str(valueStr).unwrap();
				Int(value)
			},

			'f' => {
				let value = f32::from_str(valueStr).unwrap();
				Float(value)
			},

			's' => {
				return String(valueStr.to_owned());
			},

			'v' => {
				let floatPair : Vec<&str> = valueStr.split(' ').collect();

				let float1 = f32::from_str(*floatPair.get(0)).unwrap();
				let float2 = f32::from_str(*floatPair.get(1)).unwrap();
				Vector(float1, float2)
			},

			'b' => {
				let value = valueStr == "true";
				Bool(value)
			},

			_ => {
				Error
			}
		}
	}

	fn parse(data: String) -> HashMap<Key, Setting> {

		let mut key_value_pair = HashMap::new();

		let dataLines : Vec<&str> = data.split('\n').collect();

		for &line in dataLines.iter() {
			let dataPair : Vec<&str> = line.split(':').collect();

			if dataPair.len() != 2 {
			//	warn!("faulty data pair: {}", dataPair);
				continue;
			}

			let name = dataPair.get(0).trim();
			let valueStr = dataPair.get(1).trim();

			let setting = Settings::gen_setting(name, valueStr);

			//debug!("name: {}, Setting: {}", name, setting);
			key_value_pair.insert(name.to_owned(), setting);
		}

		key_value_pair
	}

}
<|endoftext|>


<commit_before>//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

use std::error::Error;

pub use failable::ops::and::FailableAnd;
pub use failable::ops::bool::FailableBool;
pub use failable::ops::not::FailableNot;
pub use failable::ops::xor::FailableXOr;
pub use failable::ops::or::FailableOr;

/// Trait for converting something into a Filter
pub trait IntoFailableFilter<N, E: Error + Sized> {
    type IntoFilt: FailableFilter<N, E>;

    fn into_failable_filter(self) -> Self::IntoFilt;
}

/// All Filters can be turned into Filters
impl<N, E: Error + Sized, I: FailableFilter<N, E>> IntoFailableFilter<N, E> for I {
    type IntoFilt = I;

    fn into_failable_filter(self) -> Self::IntoFilt {
        self
    }
}

pub trait FailableFilter<N, E: Error> {
    /// The function which is used to filter something
    fn filter(&self, &N) -> Result<bool, E>;

    /// Helper to invert a filter.
    ///
    /// ```
    /// use filters::filter::Filter;
    ///
    /// let f = (|&a: &usize| { a == 1 }).not();
    ///
    /// assert!(f.filter(&2));
    /// ```
    fn not(self) -> FailableNot<Self>
        where Self: Sized
    {
        FailableNot::new(self)
    }

    /// Helper to connect two filters via logical OR
    ///
    /// ```
    /// use filters::filter::Filter;
    ///
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    /// let c = a.or(b);
    ///
    /// assert!(c.filter(&1));
    /// assert!(c.filter(&2));
    /// assert!(!c.filter(&7));
    /// ```
    fn or<F>(self, other: F) -> FailableOr<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFailableFilter<N, E> + Sized
    {
        FailableOr::new(self, other.into_failable_filter())
    }

    /// Helper to connect two filters via logical OR and NOT
    ///
    /// ```
    /// use filters::filter::Filter;
    ///
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    /// let c = a.or_not(b);
    ///
    /// assert!(c.filter(&1));
    /// assert!(!c.filter(&2));
    /// assert!(c.filter(&7));
    /// ```
    fn or_not<F>(self, other: F) -> FailableOr<Self, FailableNot<F::IntoFilt>>
        where Self: Sized,
              F: IntoFailableFilter<N, E> + Sized,
    {
        self.or(FailableNot::new(other.into_failable_filter()))
    }

    /// Helper to connect three filters via logical OR
    ///
    /// ```
    /// use filters::filter::Filter;
    ///
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    /// let c = (|&a: &usize| { a == 3 });
    /// let d = a.or3(b, c);
    ///
    /// assert!(d.filter(&1));
    /// assert!(d.filter(&2));
    /// assert!(d.filter(&3));
    /// assert!(!d.filter(&4));
    /// ```
    fn or3<F, F2>(self, other: F, other2: F2) -> FailableOr<Self, FailableOr<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFailableFilter<N, E> + Sized,
              F2: IntoFailableFilter<N, E> + Sized
    {
        FailableOr::new(self, FailableOr::new(other.into_failable_filter(), other2.into_failable_filter()))
    }

    /// Helper to connect two filters via logical NOR
    ///
    /// ```
    /// use filters::filter::Filter;
    ///
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    /// let c = a.nor(b); /* !(a == 1 || a == 2) */
    ///
    /// assert!(!c.filter(&1));
    /// assert!(!c.filter(&2));
    /// assert!(c.filter(&3));
    /// assert!(c.filter(&4));
    /// ```
    fn nor<F>(self, other: F) -> FailableNot<FailableOr<Self, F>>
        where Self: Sized,
    {
        FailableNot::new(FailableOr::new(self, other))
    }

    /// Helper to connect two filters via logical XOR
    ///
    /// ```
    /// use filters::filter::Filter;
    ///
    /// let a = (|&a: &usize| { a > 3 });
    /// let b = (|&a: &usize| { a < 7 });
    /// let c = a.xor(b);
    ///
    /// assert!(c.filter(&1));
    /// assert!(c.filter(&3));
    /// assert!(!c.filter(&4));
    /// assert!(!c.filter(&6));
    /// assert!(c.filter(&9));
    /// ```
    fn xor<F>(self, other: F) -> FailableXOr<Self, F>
        where Self: Sized,
    {
        FailableXOr::new(self, other)
    }

    /// Helper to connect two filters via logical AND
    ///
    /// ```
    /// use filters::filter::Filter;
    ///
    /// let a = (|&a: &usize| { a > 1 });
    /// let b = (|&a: &usize| { a < 7 });
    /// let c = a.and(b);
    ///
    /// assert!(!c.filter(&1));
    /// assert!(c.filter(&3));
    /// assert!(c.filter(&4));
    /// assert!(c.filter(&6));
    /// assert!(!c.filter(&9));
    /// ```
    fn and<F>(self, other: F) -> FailableAnd<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFailableFilter<N, E> + Sized
    {
        FailableAnd::new(self, other.into_failable_filter())
    }

    /// Helper to connect three filters via logical AND
    ///
    /// ```
    /// use filters::filter::Filter;
    ///
    /// let a = (|&a: &usize| { a > 1 });
    /// let b = (|&a: &usize| { a < 20 });
    /// let c = (|&a: &usize| { a % 2 == 0 });
    /// let d = a.and3(b, c);
    ///
    /// assert!(!d.filter(&1));
    /// assert!(!d.filter(&3));
    /// assert!(d.filter(&8));
    /// assert!(d.filter(&10));
    /// assert!(d.filter(&14));
    /// assert!(!d.filter(&15));
    /// assert!(!d.filter(&19));
    /// ```
    fn and3<F, F2>(self, other: F, other2: F2) -> FailableAnd<Self, FailableAnd<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFailableFilter<N, E> + Sized,
              F2: IntoFailableFilter<N, E> + Sized
    {
        FailableAnd::new(self, FailableAnd::new(other.into_failable_filter(), other2.into_failable_filter()))
    }

    /// Helper to connect two filters via logical AND and NOT
    ///
    /// ```
    /// use filters::filter::Filter;
    ///
    /// let a = (|&a: &usize| { a > 10 });
    /// let b = (|&a: &usize| { a < 20 });
    /// let c = a.and_not(b);
    ///
    /// assert!(!c.filter(&1));
    /// assert!(!c.filter(&3));
    /// assert!(!c.filter(&8));
    /// assert!(!c.filter(&11));
    /// assert!(c.filter(&24));
    /// assert!(c.filter(&25));
    /// assert!(c.filter(&29));
    /// ```
    fn and_not<F>(self, other: F) -> FailableAnd<Self, FailableNot<F::IntoFilt>>
        where Self: Sized,
              F: IntoFailableFilter<N, E> + Sized
    {
        self.and(FailableNot::new(other.into_failable_filter()))
    }

    /// Helper to connect two filters via logical NAND
    ///
    /// ```
    /// use filters::filter::Filter;
    ///
    /// let a = (|&a: &usize| { a > 10 });
    /// let b = (|&a: &usize| { a < 20 });
    /// let c = a.nand(b);
    ///
    /// assert!(c.filter(&1));
    /// assert!(c.filter(&3));
    /// assert!(c.filter(&8));
    /// assert!(!c.filter(&11));
    /// assert!(!c.filter(&14));
    /// assert!(c.filter(&25));
    /// assert!(c.filter(&29));
    /// ```
    fn nand<F>(self, other: F) -> FailableNot<FailableAnd<Self, F>>
        where Self: Sized,
    {
        FailableNot::new(FailableAnd::new(self, other))
    }

}

/// All closures that take a ref to something and return Result<bool, E> are failable filters
impl<I, E: Error, T: Fn(&I) -> Result<bool, E>> FailableFilter<I, E> for T {
    fn filter(&self, other: &I) -> Result<bool, E>{
        self(other)
    }
}

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

    #[derive(Debug)]
    struct StupError { }

    impl ::std::fmt::Display for StupError {
        fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
            Ok(())
        }
    }

    impl Error for StupError {
         fn description(&self) -> &str {
             "stub"
         }
    }

    #[test]
    fn compile_test() {
        let a = |r: &i32| -> Result<bool, StupError> { Ok(true) };

        assert!(a.filter(&1).unwrap());
    }
}

<commit_msg>Adapt documentation-tests<commit_after>//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

use std::error::Error;

pub use failable::ops::and::FailableAnd;
pub use failable::ops::bool::FailableBool;
pub use failable::ops::not::FailableNot;
pub use failable::ops::xor::FailableXOr;
pub use failable::ops::or::FailableOr;

/// Trait for converting something into a Filter
pub trait IntoFailableFilter<N, E: Error + Sized> {
    type IntoFilt: FailableFilter<N, E>;

    fn into_failable_filter(self) -> Self::IntoFilt;
}

/// All Filters can be turned into Filters
impl<N, E: Error + Sized, I: FailableFilter<N, E>> IntoFailableFilter<N, E> for I {
    type IntoFilt = I;

    fn into_failable_filter(self) -> Self::IntoFilt {
        self
    }
}

pub trait FailableFilter<N, E: Error> {
    /// The function which is used to filter something
    fn filter(&self, &N) -> Result<bool, E>;

    /// Helper to invert a filter.
    ///
    /// ```
    /// # #[derive(Debug)]
    /// # struct ErrorStup { }
    /// #
    /// # impl ::std::fmt::Display for ErrorStup {
    /// #     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
    /// #         Ok(())
    /// #     }
    /// # }
    /// #
    /// # impl ::std::error::Error for ErrorStup {
    /// #     fn description(&self) -> &str { "stub" }
    /// # }
    /// #
    /// use filters::failable::filter::FailableFilter;
    ///
    /// let f = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a == 1) }).not();
    ///
    /// assert!(f.filter(&2).unwrap());
    /// ```
    fn not(self) -> FailableNot<Self>
        where Self: Sized
    {
        FailableNot::new(self)
    }

    /// Helper to connect two filters via logical OR
    ///
    /// ```
    /// # #[derive(Debug)]
    /// # struct ErrorStup { }
    /// #
    /// # impl ::std::fmt::Display for ErrorStup {
    /// #     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
    /// #         Ok(())
    /// #     }
    /// # }
    /// #
    /// # impl ::std::error::Error for ErrorStup {
    /// #     fn description(&self) -> &str { "stub" }
    /// # }
    /// #
    /// use filters::failable::filter::FailableFilter;
    ///
    /// let a = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a == 1) });
    /// let b = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a == 2) });
    /// let c = a.or(b);
    ///
    /// assert!(c.filter(&1).unwrap());
    /// assert!(c.filter(&2).unwrap());
    /// assert!(!c.filter(&7).unwrap());
    /// ```
    fn or<F>(self, other: F) -> FailableOr<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFailableFilter<N, E> + Sized
    {
        FailableOr::new(self, other.into_failable_filter())
    }

    /// Helper to connect two filters via logical OR and NOT
    ///
    /// ```
    /// # #[derive(Debug)]
    /// # struct ErrorStup { }
    /// #
    /// # impl ::std::fmt::Display for ErrorStup {
    /// #     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
    /// #         Ok(())
    /// #     }
    /// # }
    /// #
    /// # impl ::std::error::Error for ErrorStup {
    /// #     fn description(&self) -> &str { "stub" }
    /// # }
    /// #
    /// use filters::failable::filter::FailableFilter;
    ///
    /// let a = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a == 1) });
    /// let b = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a == 2) });
    /// let c = a.or_not(b);
    ///
    /// assert!(c.filter(&1).unwrap());
    /// assert!(!c.filter(&2).unwrap());
    /// assert!(c.filter(&7).unwrap());
    /// ```
    fn or_not<F>(self, other: F) -> FailableOr<Self, FailableNot<F::IntoFilt>>
        where Self: Sized,
              F: IntoFailableFilter<N, E> + Sized,
    {
        self.or(FailableNot::new(other.into_failable_filter()))
    }

    /// Helper to connect three filters via logical OR
    ///
    /// ```
    /// # #[derive(Debug)]
    /// # struct ErrorStup { }
    /// #
    /// # impl ::std::fmt::Display for ErrorStup {
    /// #     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
    /// #         Ok(())
    /// #     }
    /// # }
    /// #
    /// # impl ::std::error::Error for ErrorStup {
    /// #     fn description(&self) -> &str { "stub" }
    /// # }
    /// #
    /// use filters::failable::filter::FailableFilter;
    ///
    /// let a = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a == 1) });
    /// let b = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a == 2) });
    /// let c = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a == 3) });
    /// let d = a.or3(b, c);
    ///
    /// assert!(d.filter(&1).unwrap());
    /// assert!(d.filter(&2).unwrap());
    /// assert!(d.filter(&3).unwrap());
    /// assert!(!d.filter(&4).unwrap());
    /// ```
    fn or3<F, F2>(self, other: F, other2: F2) -> FailableOr<Self, FailableOr<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFailableFilter<N, E> + Sized,
              F2: IntoFailableFilter<N, E> + Sized
    {
        FailableOr::new(self, FailableOr::new(other.into_failable_filter(), other2.into_failable_filter()))
    }

    /// Helper to connect two filters via logical NOR
    ///
    /// ```
    /// # #[derive(Debug)]
    /// # struct ErrorStup { }
    /// #
    /// # impl ::std::fmt::Display for ErrorStup {
    /// #     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
    /// #         Ok(())
    /// #     }
    /// # }
    /// #
    /// # impl ::std::error::Error for ErrorStup {
    /// #     fn description(&self) -> &str { "stub" }
    /// # }
    /// #
    /// use filters::failable::filter::FailableFilter;
    ///
    /// let a = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a == 1) });
    /// let b = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a == 2) });
    /// let c = a.nor(b); /* !(a == 1 || a == 2) */
    ///
    /// assert!(!c.filter(&1).unwrap());
    /// assert!(!c.filter(&2).unwrap());
    /// assert!(c.filter(&3).unwrap());
    /// assert!(c.filter(&4).unwrap());
    /// ```
    fn nor<F>(self, other: F) -> FailableNot<FailableOr<Self, F>>
        where Self: Sized,
    {
        FailableNot::new(FailableOr::new(self, other))
    }

    /// Helper to connect two filters via logical XOR
    ///
    /// ```
    /// # #[derive(Debug)]
    /// # struct ErrorStup { }
    /// #
    /// # impl ::std::fmt::Display for ErrorStup {
    /// #     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
    /// #         Ok(())
    /// #     }
    /// # }
    /// #
    /// # impl ::std::error::Error for ErrorStup {
    /// #     fn description(&self) -> &str { "stub" }
    /// # }
    /// #
    /// use filters::failable::filter::FailableFilter;
    ///
    /// let a = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a > 3) });
    /// let b = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a < 7) });
    /// let c = a.xor(b);
    ///
    /// assert!(c.filter(&1).unwrap());
    /// assert!(c.filter(&3).unwrap());
    /// assert!(!c.filter(&4).unwrap());
    /// assert!(!c.filter(&6).unwrap());
    /// assert!(c.filter(&9).unwrap());
    /// ```
    fn xor<F>(self, other: F) -> FailableXOr<Self, F>
        where Self: Sized,
    {
        FailableXOr::new(self, other)
    }

    /// Helper to connect two filters via logical AND
    ///
    /// ```
    /// # #[derive(Debug)]
    /// # struct ErrorStup { }
    /// #
    /// # impl ::std::fmt::Display for ErrorStup {
    /// #     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
    /// #         Ok(())
    /// #     }
    /// # }
    /// #
    /// # impl ::std::error::Error for ErrorStup {
    /// #     fn description(&self) -> &str { "stub" }
    /// # }
    /// #
    /// use filters::failable::filter::FailableFilter;
    ///
    /// let a = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a > 1) });
    /// let b = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a < 7) });
    /// let c = a.and(b);
    ///
    /// assert!(!c.filter(&1).unwrap());
    /// assert!(c.filter(&3).unwrap());
    /// assert!(c.filter(&4).unwrap());
    /// assert!(c.filter(&6).unwrap());
    /// assert!(!c.filter(&9).unwrap());
    /// ```
    fn and<F>(self, other: F) -> FailableAnd<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFailableFilter<N, E> + Sized
    {
        FailableAnd::new(self, other.into_failable_filter())
    }

    /// Helper to connect three filters via logical AND
    ///
    /// ```
    /// # #[derive(Debug)]
    /// # struct ErrorStup { }
    /// #
    /// # impl ::std::fmt::Display for ErrorStup {
    /// #     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
    /// #         Ok(())
    /// #     }
    /// # }
    /// #
    /// # impl ::std::error::Error for ErrorStup {
    /// #     fn description(&self) -> &str { "stub" }
    /// # }
    /// #
    /// use filters::failable::filter::FailableFilter;
    ///
    /// let a = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a > 1) });
    /// let b = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a < 20) });
    /// let c = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a % 2 == 0) });
    /// let d = a.and3(b, c);
    ///
    /// assert!(!d.filter(&1).unwrap());
    /// assert!(!d.filter(&3).unwrap());
    /// assert!(d.filter(&8).unwrap());
    /// assert!(d.filter(&10).unwrap());
    /// assert!(d.filter(&14).unwrap());
    /// assert!(!d.filter(&15).unwrap());
    /// assert!(!d.filter(&19).unwrap());
    /// ```
    fn and3<F, F2>(self, other: F, other2: F2) -> FailableAnd<Self, FailableAnd<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFailableFilter<N, E> + Sized,
              F2: IntoFailableFilter<N, E> + Sized
    {
        FailableAnd::new(self, FailableAnd::new(other.into_failable_filter(), other2.into_failable_filter()))
    }

    /// Helper to connect two filters via logical AND and NOT
    ///
    /// ```
    /// # #[derive(Debug)]
    /// # struct ErrorStup { }
    /// #
    /// # impl ::std::fmt::Display for ErrorStup {
    /// #     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
    /// #         Ok(())
    /// #     }
    /// # }
    /// #
    /// # impl ::std::error::Error for ErrorStup {
    /// #     fn description(&self) -> &str { "stub" }
    /// # }
    /// #
    /// use filters::failable::filter::FailableFilter;
    ///
    /// let a = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a > 10) });
    /// let b = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a < 20) });
    /// let c = a.and_not(b);
    ///
    /// assert!(!c.filter(&1).unwrap());
    /// assert!(!c.filter(&3).unwrap());
    /// assert!(!c.filter(&8).unwrap());
    /// assert!(!c.filter(&11).unwrap());
    /// assert!(c.filter(&24).unwrap());
    /// assert!(c.filter(&25).unwrap());
    /// assert!(c.filter(&29).unwrap());
    /// ```
    fn and_not<F>(self, other: F) -> FailableAnd<Self, FailableNot<F::IntoFilt>>
        where Self: Sized,
              F: IntoFailableFilter<N, E> + Sized
    {
        self.and(FailableNot::new(other.into_failable_filter()))
    }

    /// Helper to connect two filters via logical NAND
    ///
    /// ```
    /// # #[derive(Debug)]
    /// # struct ErrorStup { }
    /// #
    /// # impl ::std::fmt::Display for ErrorStup {
    /// #     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
    /// #         Ok(())
    /// #     }
    /// # }
    /// #
    /// # impl ::std::error::Error for ErrorStup {
    /// #     fn description(&self) -> &str { "stub" }
    /// # }
    /// #
    /// use filters::failable::filter::FailableFilter;
    ///
    /// let a = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a > 10) });
    /// let b = (|&a: &usize| -> Result<bool, ErrorStup> { Ok(a < 20) });
    /// let c = a.nand(b);
    ///
    /// assert!(c.filter(&1).unwrap());
    /// assert!(c.filter(&3).unwrap());
    /// assert!(c.filter(&8).unwrap());
    /// assert!(!c.filter(&11).unwrap());
    /// assert!(!c.filter(&14).unwrap());
    /// assert!(c.filter(&25).unwrap());
    /// assert!(c.filter(&29).unwrap());
    /// ```
    fn nand<F>(self, other: F) -> FailableNot<FailableAnd<Self, F>>
        where Self: Sized,
    {
        FailableNot::new(FailableAnd::new(self, other))
    }

}

/// All closures that take a ref to something and return Result<bool, E> are failable filters
impl<I, E: Error, T: Fn(&I) -> Result<bool, E>> FailableFilter<I, E> for T {
    fn filter(&self, other: &I) -> Result<bool, E>{
        self(other)
    }
}

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

    #[derive(Debug)]
    struct StupError { }

    impl ::std::fmt::Display for StupError {
        fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
            Ok(())
        }
    }

    impl Error for StupError {
         fn description(&self) -> &str {
             "stub"
         }
    }

    #[test]
    fn compile_test() {
        let a = |r: &i32| -> Result<bool, StupError> { Ok(true) };

        assert!(a.filter(&1).unwrap());
    }
}

<|endoftext|>