<commit_before>/*
 * Built-in method definitions for scheme
 *
 * Done:
 * +, -, *, / (works on lists of numbers)
 * =, >, <, >=, <= (works on list of numbers)
 * not (works on single argument)
 * list (works on any arguments)
 * list?, null?, symbol? (works on single argument)
 * cons, car, cdr, append
 * equal?
 *
 * Coming:
 * eq?
 *
 *    {'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, 'not':op.not_,
       '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
       'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':lambda x,y:[x]+y,
       'car':lambda x:x[0],'cdr':lambda x:x[1:], 'append':op.add,
       'list':lambda *x:list(x), 'list?': lambda x:isa(x,list),
       'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol)})
 *
 */

macro_rules! math_function {
    ($function:ident $identity:expr) => {
        pub fn $function( args:~[Expression], _:@Environment) -> Expression {
            match args {
                [] => $identity,
                [head] => vec::foldl($identity, ~[head], |x, y| {x.$function(y)}),
                [head, ..tail] => vec::foldl(head, tail, |x, y| {x.$function(y)})
            }
        }
    }
}

math_function!(add Int(0))
math_function!(sub Int(0))
math_function!(mul Int(1))
math_function!(div Int(1))

pub fn equals( args:~[Expression], _:@Environment) -> Expression {
    for args.tail().each() |&expr| {
        if expr != args.head() {
            return Bool(false);
        }
    }
    return Bool(true);
}

pub fn assert_number_of_args( function:~str, min:uint, max:uint, args:~[Expression] ) {
    if args.len() > max || args.len() < min {
        if max == min {
            fail fmt!("Built-in function '%s' takes only %u argument%s. It was called with %u '%s'", function, max, if max==1 {~""} else {~"s"}, args.len(), List(args).to_str());
        } else {
            fail fmt!("Built-in function '%s' takes between %u and %u arguments. It was called with %u '%s'", function, min, max, args.len(), List(args).to_str());
        }
    }
}

pub fn not( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"not", 1, 1, copy args );

    return Bool(!args[0].to_bool());
}

pub fn car( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"car", 1, 1, copy args );

    match copy args[0] {
        List(list) => list.head(),
        _ => fail fmt!("Built-in function 'car' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cdr( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"cdr", 1, 1, copy args );

    match copy args[0] {
        List(list) => List(list.tail()),
        _ => fail fmt!("Built-in function 'cdr' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cons( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"cons", 2, 2, copy args );

    match copy args[1] {
        List(list) => List( ~[args[0]] + list ),
        x => List( ~[args[0]] + ~[x] )
    }
}

pub fn append( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"append", 2, 2, copy args );

    match copy args[0] {
        List(list1) => {
            match copy args[1] {
                List(list) => List( list1 + list ),
                x => List( list1 + ~[x] )
            }
        }
        _ => fail fmt!("Built-in function 'append' requires a list as the first arguments. It was called with %s", List(args).to_str())
    }
}

pub fn length( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"length", 1, 1, copy args );

    match copy args[0] {
        List(list) => Int(list.len() as int),
        _ => fail fmt!("Built-in function 'append' requires a list argument. It was called with %s", List(args).to_str())
    }
}

pub fn equal_( args:~[Expression], _:@Environment ) -> Expression {
    assert_number_of_args( ~"equal?", 2, 2, copy args );

    Bool(args[0] == args[1])
}

pub fn symbol_( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"symbol?", 1, 1, copy args );

    match args[0] {
        Symbol(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn list_( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"list?", 1, 1, copy args );

    match args[0] {
        List(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn null_( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"null?", 1, 1, copy args );

    match copy args[0] {
        List(list) => Bool(list.len() == 0),
        _ => Bool(false)
    }
}

pub fn list( args:~[Expression], _:@Environment) -> Expression {
    List(args)
}

pub fn eq_( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"eq?", 2, 2, copy args );

    Bool( args[0] == args[1] )
}

pub fn eqv_( args:~[Expression], _env:@Environment) -> Expression {
    assert_number_of_args( ~"eq?", 2, 2, copy args );

    eq_( args, _env )
}

#[test]
fn test_eqv_() {
    fn eqv__( args:~[Expression] ) -> Expression {
        eqv_( args, @Environment::new_global_environment() )
    }

    assert( Bool(true) == eqv__( ~[ Bool(true), Bool(true) ] ) );
    assert( Bool(true) == eqv__( ~[ Bool(false), Bool(false) ] ) );
    assert( Bool(false) == eqv__( ~[ Bool(true), Bool(false) ] ) );
    assert( Bool(true) == eqv__( ~[ Symbol(~"a"), Symbol(~"a") ] ) );
    assert( Bool(false) == eqv__( ~[ Symbol(~"b"), Symbol(~"a") ] ) );
    assert( Bool(true) == eqv__( ~[ Int(1), Int(1) ] ) );
    assert( Bool(false) == eqv__( ~[ Int(2), Int(1) ] ) );
    assert( Bool(true) == eqv__( ~[ Float(1.0), Float(1.0) ] ) );
    assert( Bool(false) == eqv__( ~[ Float(2.0), Float(1.0) ] ) );
    assert( Bool(true) == eqv__( ~[ List( ~[] ), List( ~[] ) ] ) );
    assert( Bool(false) == eqv__( ~[ List( ~[Int(1)] ), List( ~[] ) ] ) );

    let proc = eval( parse("(lambda (x) (* x x))"), @Environment::new_global_environment() ).first();
    let proc2 = eval( parse("(lambda (x) (* x x))"), @Environment::new_global_environment() ).first();
    assert( Bool(true) == eqv__( ~[ proc, proc ] ) );
    assert( Bool(false) == eqv__( ~[ proc, proc2 ] ) );
}

pub fn builtins() -> ~[(~str,~fn(~[Expression], @Environment) -> Expression)] {
    ~[ (~"+", add), (~"-", sub), (~"*", mul), (~"/", div),
       (~"=", equals), (~"not", not),
       (~"car", car), (~"cdr", cdr),
       (~"cons", cons), (~"append", append),
       (~"list", list), (~"length", length),
       (~"eq?", eq_), (~"eqv?", eqv_),
       (~"equal?", equal_),
       (~"symbol?", symbol_),
       (~"list?", list_),
       (~"null?", null_)
    ]
}
<commit_msg>Add math and list function tests<commit_after>/*
 * Built-in method definitions for scheme
 *
 * Done:
 * +, -, *, / (works on lists of numbers)
 * =, >, <, >=, <= (works on list of numbers)
 * not (works on single argument)
 * list (works on any arguments)
 * list?, null?, symbol? (works on single argument)
 * cons, car, cdr, append
 * equal?
 *
 * Coming:
 * eq?
 *
 *    {'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, 'not':op.not_,
       '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
       'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':lambda x,y:[x]+y,
       'car':lambda x:x[0],'cdr':lambda x:x[1:], 'append':op.add,
       'list':lambda *x:list(x), 'list?': lambda x:isa(x,list),
       'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol)})
 *
 */

macro_rules! math_function {
    ($function:ident $identity:expr) => {
        pub fn $function( args:~[Expression], _:@Environment) -> Expression {
            match args {
                [] => $identity,
                [head] => vec::foldl($identity, ~[head], |x, y| {x.$function(y)}),
                [head, ..tail] => vec::foldl(head, tail, |x, y| {x.$function(y)})
            }
        }
    }
}

math_function!(add Int(0))
math_function!(sub Int(0))
math_function!(mul Int(1))
math_function!(div Int(1))

pub fn equals( args:~[Expression], _:@Environment) -> Expression {
    for args.tail().each() |&expr| {
        if expr != args.head() {
            return Bool(false);
        }
    }
    return Bool(true);
}

pub fn assert_number_of_args( function:~str, min:uint, max:uint, args:~[Expression] ) {
    if args.len() > max || args.len() < min {
        if max == min {
            fail fmt!("Built-in function '%s' takes only %u argument%s. It was called with %u '%s'", function, max, if max==1 {~""} else {~"s"}, args.len(), List(args).to_str());
        } else {
            fail fmt!("Built-in function '%s' takes between %u and %u arguments. It was called with %u '%s'", function, min, max, args.len(), List(args).to_str());
        }
    }
}

pub fn not( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"not", 1, 1, copy args );

    return Bool(!args[0].to_bool());
}

pub fn car( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"car", 1, 1, copy args );

    match copy args[0] {
        List(list) => list.head(),
        _ => fail fmt!("Built-in function 'car' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cdr( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"cdr", 1, 1, copy args );

    match copy args[0] {
        List(list) => List(list.tail()),
        _ => fail fmt!("Built-in function 'cdr' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cons( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"cons", 2, 2, copy args );

    match copy args[1] {
        List(list) => List( ~[args[0]] + list ),
        x => List( ~[args[0]] + ~[x] )
    }
}

pub fn append( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"append", 2, 2, copy args );

    match copy args[0] {
        List(list1) => {
            match copy args[1] {
                List(list) => List( list1 + list ),
                x => List( list1 + ~[x] )
            }
        }
        _ => fail fmt!("Built-in function 'append' requires a list as the first arguments. It was called with %s", List(args).to_str())
    }
}

pub fn length( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"length", 1, 1, copy args );

    match copy args[0] {
        List(list) => Int(list.len() as int),
        _ => fail fmt!("Built-in function 'append' requires a list argument. It was called with %s", List(args).to_str())
    }
}

pub fn equal_( args:~[Expression], _:@Environment ) -> Expression {
    assert_number_of_args( ~"equal?", 2, 2, copy args );

    Bool(args[0] == args[1])
}

pub fn symbol_( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"symbol?", 1, 1, copy args );

    match args[0] {
        Symbol(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn list_( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"list?", 1, 1, copy args );

    match args[0] {
        List(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn null_( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"null?", 1, 1, copy args );

    match copy args[0] {
        List(list) => Bool(list.len() == 0),
        _ => Bool(false)
    }
}

pub fn list( args:~[Expression], _:@Environment) -> Expression {
    List(args)
}

pub fn eq_( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"eq?", 2, 2, copy args );

    Bool( args[0] == args[1] )
}

pub fn eqv_( args:~[Expression], _env:@Environment) -> Expression {
    assert_number_of_args( ~"eq?", 2, 2, copy args );

    eq_( args, _env )
}

#[test]
fn test_eqv_() {
    fn eqv__( args:~[Expression] ) -> Expression {
        eqv_( args, @Environment::new_global_environment() )
    }

    assert( Bool(true) == eqv__( ~[ Bool(true), Bool(true) ] ) );
    assert( Bool(true) == eqv__( ~[ Bool(false), Bool(false) ] ) );
    assert( Bool(false) == eqv__( ~[ Bool(true), Bool(false) ] ) );
    assert( Bool(true) == eqv__( ~[ Symbol(~"a"), Symbol(~"a") ] ) );
    assert( Bool(false) == eqv__( ~[ Symbol(~"b"), Symbol(~"a") ] ) );
    assert( Bool(true) == eqv__( ~[ Int(1), Int(1) ] ) );
    assert( Bool(false) == eqv__( ~[ Int(2), Int(1) ] ) );
    assert( Bool(true) == eqv__( ~[ Float(1.0), Float(1.0) ] ) );
    assert( Bool(false) == eqv__( ~[ Float(2.0), Float(1.0) ] ) );
    assert( Bool(true) == eqv__( ~[ List( ~[] ), List( ~[] ) ] ) );
    assert( Bool(false) == eqv__( ~[ List( ~[Int(1)] ), List( ~[] ) ] ) );

    let proc = eval( parse("(lambda (x) (* x x))"), @Environment::new_global_environment() ).first();
    let proc2 = eval( parse("(lambda (x) (* x x))"), @Environment::new_global_environment() ).first();
    assert( Bool(true) == eqv__( ~[ proc, proc ] ) );
    assert( Bool(false) == eqv__( ~[ proc, proc2 ] ) );
}

#[test]
fn test_math() {
    test_eval( ~"(+ 4 2)", ~"6" );
    test_eval( ~"(- 4 2)", ~"2" );
    test_eval( ~"(/ 4 2)", ~"2" );
    test_eval( ~"(* 4 2)", ~"8" );
    test_eval( ~"(= 4 2)", ~"#f" );
    test_eval( ~"(= 4 4)", ~"#t" );
}

#[test]
fn test_list() {
    test_eval( ~"(list? (quote ()))", ~"#t" );
    test_eval( ~"(car (quote (1 2 3)))", ~"1" );
    test_eval( ~"(cdr (quote (1 2 3)))", ~"(2 3)" );
    test_eval( ~"(cons 1 (quote (2 3)))", ~"(1 2 3)" );
    test_eval( ~"(list 1)", ~"(1)" );
    test_eval( ~"(list)", ~"()" );
    test_eval( ~"(list 1 2 3)", ~"(1 2 3)" );
    test_eval( ~"(length (list))", ~"0" );
    test_eval( ~"(length (list 1))", ~"1" );
    test_eval( ~"(length (list 1 2))", ~"2" );
}

pub fn builtins() -> ~[(~str,~fn(~[Expression], @Environment) -> Expression)] {
    ~[ (~"+", add), (~"-", sub), (~"*", mul), (~"/", div),
       (~"=", equals), (~"not", not),
       (~"car", car), (~"cdr", cdr),
       (~"cons", cons), (~"append", append),
       (~"list", list), (~"length", length),
       (~"eq?", eq_), (~"eqv?", eqv_),
       (~"equal?", equal_),
       (~"symbol?", symbol_),
       (~"list?", list_),
       (~"null?", null_)
    ]
}
<|endoftext|>


<commit_before>//! The main rustup commandline application
//!
//! The rustup binary is a chimera, changing its behavior based on the
//! name of the binary. This is used most prominently to enable
//! rustup's tool 'proxies' - that is, rustup itself and the rustup
//! proxies are the same binary; when the binary is called 'rustup' or
//! 'rustup.exe' rustup behaves like the rustup commandline
//! application; when it is called 'rustc' it behaves as a proxy to
//! 'rustc'.
//!
//! This scheme is further used to distinguish the rustup installer,
//! called 'rustup-init' which is again just the rustup binary under a
//! different name.

#![recursion_limit = "1024"]

#[macro_use]
mod log;
mod common;
mod download_tracker;
mod errors;
mod help;
mod job;
mod markdown;
mod proxy_mode;
mod rustup_mode;
mod self_update;
mod setup_mode;
mod term2;
mod topical_doc;

use crate::errors::*;
use rustup::env_var::RUST_RECURSION_COUNT_MAX;

use std::env;
use std::path::PathBuf;

use rs_tracing::*;

fn main() {
    if let Err(ref e) = run_rustup() {
        common::report_error(e);
        std::process::exit(1);
    }
}

fn run_rustup() -> Result<()> {
    if let Ok(dir) = env::var("RUSTUP_TRACE_DIR") {
        open_trace_file!(dir)?;
    }
    let result = run_rustup_inner();
    if env::var("RUSTUP_TRACE_DIR").is_ok() {
        close_trace_file!();
    }
    result
}

fn run_rustup_inner() -> Result<()> {
    // Guard against infinite proxy recursion. This mostly happens due to
    // bugs in rustup.
    do_recursion_guard()?;

    // The name of arg0 determines how the program is going to behave
    let arg0 = match env::var("RUSTUP_FORCE_ARG0") {
        Ok(v) => Some(v),
        Err(_) => env::args().next(),
    }
    .map(PathBuf::from);
    let name = arg0
        .as_ref()
        .and_then(|a| a.file_stem())
        .and_then(std::ffi::OsStr::to_str);

    match name {
        Some("rustup") => rustup_mode::main(),
        Some(n) if n.starts_with("rustup-setup") || n.starts_with("rustup-init") => {
            // NB: The above check is only for the prefix of the file
            // name. Browsers rename duplicates to
            // e.g. rustup-setup(2), and this allows all variations
            // to work.
            setup_mode::main()
        }
        Some(n) if n.starts_with("rustup-gc-") => {
            // This is the final uninstallation stage on windows where
            // rustup deletes its own exe
            self_update::complete_windows_uninstall()
        }
        Some(_) => proxy_mode::main(),
        None => {
            // Weird case. No arg0, or it's unparsable.
            Err(ErrorKind::NoExeName.into())
        }
    }
}

fn do_recursion_guard() -> Result<()> {
    let recursion_count = env::var("RUST_RECURSION_COUNT")
        .ok()
        .and_then(|s| s.parse().ok())
        .unwrap_or(0);
    if recursion_count > RUST_RECURSION_COUNT_MAX {
        return Err(ErrorKind::InfiniteRecursion.into());
    }

    Ok(())
}
<commit_msg>main: Ensure we check CWD and EXE before we proceed with anything<commit_after>//! The main rustup commandline application
//!
//! The rustup binary is a chimera, changing its behavior based on the
//! name of the binary. This is used most prominently to enable
//! rustup's tool 'proxies' - that is, rustup itself and the rustup
//! proxies are the same binary; when the binary is called 'rustup' or
//! 'rustup.exe' rustup behaves like the rustup commandline
//! application; when it is called 'rustc' it behaves as a proxy to
//! 'rustc'.
//!
//! This scheme is further used to distinguish the rustup installer,
//! called 'rustup-init' which is again just the rustup binary under a
//! different name.

#![recursion_limit = "1024"]

#[macro_use]
mod log;
mod common;
mod download_tracker;
mod errors;
mod help;
mod job;
mod markdown;
mod proxy_mode;
mod rustup_mode;
mod self_update;
mod setup_mode;
mod term2;
mod topical_doc;

use crate::errors::*;
use rustup::env_var::RUST_RECURSION_COUNT_MAX;
use rustup::utils::utils;

use std::env;
use std::path::PathBuf;

use rs_tracing::*;

fn main() {
    if let Err(ref e) = run_rustup() {
        common::report_error(e);
        std::process::exit(1);
    }
}

fn run_rustup() -> Result<()> {
    if let Ok(dir) = env::var("RUSTUP_TRACE_DIR") {
        open_trace_file!(dir)?;
    }
    let result = run_rustup_inner();
    if env::var("RUSTUP_TRACE_DIR").is_ok() {
        close_trace_file!();
    }
    result
}

fn run_rustup_inner() -> Result<()> {
    // Guard against infinite proxy recursion. This mostly happens due to
    // bugs in rustup.
    do_recursion_guard()?;

    // Before we do anything else, ensure we know where we are and who we
    // are because otherwise we cannot proceed usefully.
    utils::current_dir()?;
    utils::current_exe()?;

    // The name of arg0 determines how the program is going to behave
    let arg0 = match env::var("RUSTUP_FORCE_ARG0") {
        Ok(v) => Some(v),
        Err(_) => env::args().next(),
    }
    .map(PathBuf::from);
    let name = arg0
        .as_ref()
        .and_then(|a| a.file_stem())
        .and_then(std::ffi::OsStr::to_str);

    match name {
        Some("rustup") => rustup_mode::main(),
        Some(n) if n.starts_with("rustup-setup") || n.starts_with("rustup-init") => {
            // NB: The above check is only for the prefix of the file
            // name. Browsers rename duplicates to
            // e.g. rustup-setup(2), and this allows all variations
            // to work.
            setup_mode::main()
        }
        Some(n) if n.starts_with("rustup-gc-") => {
            // This is the final uninstallation stage on windows where
            // rustup deletes its own exe
            self_update::complete_windows_uninstall()
        }
        Some(_) => proxy_mode::main(),
        None => {
            // Weird case. No arg0, or it's unparsable.
            Err(ErrorKind::NoExeName.into())
        }
    }
}

fn do_recursion_guard() -> Result<()> {
    let recursion_count = env::var("RUST_RECURSION_COUNT")
        .ok()
        .and_then(|s| s.parse().ok())
        .unwrap_or(0);
    if recursion_count > RUST_RECURSION_COUNT_MAX {
        return Err(ErrorKind::InfiniteRecursion.into());
    }

    Ok(())
}
<|endoftext|>


<commit_before>use clap::Arg;
use clap::App;
use clap::{ArgMatches};
use loader;
use rusqlite::Connection;

pub fn cli_clap(number: &u32) -> ArgMatches{

    let application = App::new("whenenv")
                        .about("Parses an input file to do awesome things")
                        .version("0.0.1")
                        .author("Owen Synge <osynge@googlemail.com>")
                        .arg(Arg::with_name("verbose")
                                    .help("Increase log output.")
                                    .short("v")
                                    .multiple(true)
                                    .long("verbose"))
                        .arg(Arg::with_name("quiet")
                                    .help("Decrease log output.")
                                    .short("q")
                                    .multiple(true)
                                    .long("quiet"))
                        .arg(Arg::with_name("env")
                                    .short("e")
                                    .long("env")
                                    .value_name("ENVIROMENT_VARIABLE")
                                    .help("Which enviroment variables to process")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("dir-jobs")
                                    .long("dir-jobs")
                                    .value_name("DIR_JOB")
                                    .help("directory storing json jobs.")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("dir-sh")
                                    .long("dir-sh")
                                    .value_name("DIR_SHELL")
                                    .help("directory storing jobs shell scripts.")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("dir-py")
                                    .long("dir-py")
                                    .value_name("DIR_PYTHON")
                                    .help("directory storing jobs python scripts.")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("config")
                                    .short("c")
                                    .long("config")
                                    .value_name("FILE")
                                    .help("Sets a custom config file")
                                    .takes_value(true));
    let matches = application.get_matches();

    // We can find out whether or not debugging was turned on
    if matches.is_present("debug") {
        println!("Debugging is turned on");
    }

    // If we wanted to some custom initialization based off some configuration file provided
    // by the user, we could get the file (A string of the file)
    if let Some(ref file) = matches.value_of("config") {
        println!("Using config file: {}", file);
    }
    if let Some(ref env) = matches.value_of("env") {
        println!("Using config file: {}", env);
    }
    // Continued program logic goes here...
    //loader::deligate(conn, matches);
    return matches;
}
<commit_msg>remove demo code<commit_after>use clap::Arg;
use clap::App;
use clap::{ArgMatches};
use loader;
use rusqlite::Connection;

pub fn cli_clap(number: &u32) -> ArgMatches{

    let application = App::new("whenenv")
                        .about("Parses an input file to do awesome things")
                        .version("0.0.1")
                        .author("Owen Synge <osynge@googlemail.com>")
                        .arg(Arg::with_name("verbose")
                                    .help("Increase log output.")
                                    .short("v")
                                    .multiple(true)
                                    .long("verbose"))
                        .arg(Arg::with_name("quiet")
                                    .help("Decrease log output.")
                                    .short("q")
                                    .multiple(true)
                                    .long("quiet"))
                        .arg(Arg::with_name("env")
                                    .short("e")
                                    .long("env")
                                    .value_name("ENVIROMENT_VARIABLE")
                                    .help("Which enviroment variables to process")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("dir-jobs")
                                    .long("dir-jobs")
                                    .value_name("DIR_JOB")
                                    .help("directory storing json jobs.")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("dir-sh")
                                    .long("dir-sh")
                                    .value_name("DIR_SHELL")
                                    .help("directory storing jobs shell scripts.")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("dir-py")
                                    .long("dir-py")
                                    .value_name("DIR_PYTHON")
                                    .help("directory storing jobs python scripts.")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("config")
                                    .short("c")
                                    .long("config")
                                    .value_name("FILE")
                                    .help("Sets a custom config file")
                                    .takes_value(true));
    let matches = application.get_matches();
    return matches;
}
<|endoftext|>


<commit_before>use token::Token;
use token::Token::*;

struct CompileState {
    output: String,
    loopnum: i32,
    ifnum: i32,
    outbuffsize: i32,
}

fn compile_iter(state: &mut CompileState, tokens: Vec<Token>) {
    let mut outbuffpos = 0;
    for token in tokens {
        match token {
            Add(offset, value) => {
                let dest = if offset == 0 {
                    "%r12".to_string()
                } else {
                    format!("{}(%rbx)", (offset * 8))
                };
                if value == 1 && dest == "%r12" {
                    state.output.push_str("    inc %r12\n");
                } else if value >= 1 {
                    state.output.push_str(&format!("    addq ${}, {}\n", value, dest));
                } else if value == -1 && dest == "%r12" {
                    state.output.push_str("    dec %r12\n");
                } else if value <= -1 {
                    state.output.push_str(&format!("    subq ${}, {}\n", -value, dest));
                }
            }
            MulCopy(src_idx, dest_idx, mul) => {
                let mut src = if src_idx == 0 {
                    "%r12".to_string()
                } else {
                    format!("{}(%rbx)", (src_idx * 8))
                };
                let dest = if dest_idx == 0 {
                    "%r12".to_string()
                } else {
                    format!("{}(%rbx)", (dest_idx * 8))
                };

                if mul != -1 && mul != 1 {
                    state.output.push_str(&format!(concat!("    movq {}, %rax\n",
                                                           "    movq ${}, %rdx\n",
                                                           "    mulq %rdx\n"),
                                                   src,
                                                   mul.abs()));
                    src = "%rax".to_string();
                } else if src != "%r12" && dest != "%r12" {
                    // x86 cannot move memory to memory
                    state.output.push_str(&format!("    movq {}, %rax\n", src));
                    src = "%rax".to_string();
                }

                if mul > 0 {
                    state.output.push_str(&format!("    addq {}, {}\n", src, dest));
                } else {
                    state.output.push_str(&format!("    subq {}, {}\n", src, dest));
                }
            }
            Set(offset, value) => {
                if offset == 0 && value == 0 {
                    state.output.push_str("    xor %r12, %r12\n");
                } else if offset == 0 {
                    state.output.push_str(&format!("    movq ${}, %r12\n", value));
                } else {
                    state.output.push_str(&format!("    movq ${}, {}(%rbx)\n", value, offset * 8));
                }
            }
            Move(offset) => {
                if offset != 0 {
                    state.output.push_str("    movq %r12, (%rbx)\n");
                    if offset > 0 {
                        state.output.push_str(&format!("    addq ${}, %rbx\n", offset * 8));
                    } else {
                        state.output.push_str(&format!("    subq ${}, %rbx\n", -offset * 8));
                    }
                    state.output.push_str("    movq (%rbx), %r12\n");
                }
            }
            Loop(content) => {
                state.loopnum += 1;
                let curloop = state.loopnum;
                state.output.push_str(&format!(concat!("    jmp endloop{}\n", "    loop{}:\n"),
                                               curloop,
                                               curloop));

                compile_iter(state, content);

                state.output.push_str(&format!(concat!("    endloop{}:\n",
                                                       "    test %r12, %r12\n",
                                                       "    jnz loop{}\n"),
                                               curloop,
                                               curloop))
            }
            If(offset, content) => {
                state.ifnum += 1;
                let curif = state.ifnum;
                if offset == 0 {
                    state.output.push_str("    test %r12, %r12\n");
                } else {
                    state.output.push_str(&format!("    cmpq $0, {}(%rbx)\n", offset * 8));
                }
                state.output.push_str(&format!("    jz endif{}\n", curif));

                compile_iter(state, content);

                state.output.push_str(&format!("    endif{}:\n", curif))
            }
            Scan(offset) => {
                // Slighly more optimal than normal loop and move
                state.loopnum += 1;
                state.output.push_str(&format!(concat!("    movq %r12, (%rbx)\n",
                                                       "    jmp endloop{}\n",
                                                       "    loop{}:\n"),
                                               state.loopnum,
                                               state.loopnum));
                if offset > 0 {
                    state.output.push_str(&format!("    addq ${}, %rbx\n", offset * 8));
                } else {
                    state.output.push_str(&format!("    subq ${}, %rbx\n", -offset * 8));
                }
                state.output.push_str(&format!(concat!("    endloop{}:\n",
                                                       "    cmp $0, (%rbx)\n",
                                                       "    jnz loop{}\n",
                                                       "    movq (%rbx), %r12\n"),
                                               state.loopnum,
                                               state.loopnum));
            }
            Input => {
                state.output.push_str(concat!("\n    xor %rax, %rax\n",
                                              "    xor %rdi, %rdi\n",
                                              "    movq %rbx, %rsi\n",
                                              "    movq $1, %rdx\n",
                                              "    syscall\n",
                                              "    movq (%rbx), %r12\n\n"))
            }
            LoadOut(offset, add) => {
                let outaddr = format!("(strbuff+{})", outbuffpos);
                if offset == 0 {
                    state.output.push_str(&format!("    movq %r12, {}\n", outaddr));
                } else {
                    state.output.push_str(&format!("    movq {}(%rbx), %rax\n", offset * 8));
                    state.output.push_str(&format!("    movq %rax, {}\n", outaddr));
                }
                if add > 0 {
                    state.output.push_str(&format!("    addb ${}, {}\n", add, outaddr));
                } else if add < 0 {
                    state.output.push_str(&format!("    subb ${}, {}\n", -add, outaddr));
                }
                outbuffpos += 1;
            }
            LoadOutSet(value) => {
                let outaddr = format!("(strbuff+{})", outbuffpos);
                state.output.push_str(&format!("    movq ${}, {}\n", value, outaddr));
                outbuffpos += 1;
            }
            Output => {
                state.output.push_str(&format!(concat!("    movq $1, %rax\n",
                                                       "    movq $1, %rdi\n",
                                                       "    movq $strbuff, %rsi\n",
                                                       "    movq ${}, %rdx\n",
                                                       "    syscall\n\n"),
                                               outbuffpos));

                if state.outbuffsize < outbuffpos + 8 {
                    state.outbuffsize = outbuffpos + 8;
                }
                outbuffpos = 0;
            }
        }
    }
}

pub fn compile(tokens: Vec<Token>, tape_size: i32) -> String {
    let mut state = CompileState {
        output: String::new(),
        loopnum: 0,
        ifnum: 0,
        outbuffsize: 0,
    };

    compile_iter(&mut state, tokens);

    format!(concat!(".section .bss\n",
                    "    .lcomm strbuff, {outbuffsize}\n",
                    "    .lcomm mem, {}\n",
                    "    .set startidx, mem + {}\n",
                    ".section .text\n",
                    ".global _start\n",
                    "_start:\n",
                    "    xor %r12, %r12\n",
                    "    movq $startidx, %rbx\n\n",
                    "{}\n",
                    // Exit syscall
                    "    movq $60, %rax\n",
                    "    movq $0, %rdi\n",
                    "    syscall\n"),
            tape_size,
            tape_size / 2,
            state.output,
            outbuffsize = state.outbuffsize)
}
<commit_msg>Make CompileSatate derive(Default)<commit_after>use token::Token;
use token::Token::*;

#[derive(Default)]
struct CompileState {
    output: String,
    loopnum: i32,
    ifnum: i32,
    outbuffsize: i32,
}

fn compile_iter(state: &mut CompileState, tokens: Vec<Token>) {
    let mut outbuffpos = 0;
    for token in tokens {
        match token {
            Add(offset, value) => {
                let dest = if offset == 0 {
                    "%r12".to_string()
                } else {
                    format!("{}(%rbx)", (offset * 8))
                };
                if value == 1 && dest == "%r12" {
                    state.output.push_str("    inc %r12\n");
                } else if value >= 1 {
                    state.output.push_str(&format!("    addq ${}, {}\n", value, dest));
                } else if value == -1 && dest == "%r12" {
                    state.output.push_str("    dec %r12\n");
                } else if value <= -1 {
                    state.output.push_str(&format!("    subq ${}, {}\n", -value, dest));
                }
            }
            MulCopy(src_idx, dest_idx, mul) => {
                let mut src = if src_idx == 0 {
                    "%r12".to_string()
                } else {
                    format!("{}(%rbx)", (src_idx * 8))
                };
                let dest = if dest_idx == 0 {
                    "%r12".to_string()
                } else {
                    format!("{}(%rbx)", (dest_idx * 8))
                };

                if mul != -1 && mul != 1 {
                    state.output.push_str(&format!(concat!("    movq {}, %rax\n",
                                                           "    movq ${}, %rdx\n",
                                                           "    mulq %rdx\n"),
                                                   src,
                                                   mul.abs()));
                    src = "%rax".to_string();
                } else if src != "%r12" && dest != "%r12" {
                    // x86 cannot move memory to memory
                    state.output.push_str(&format!("    movq {}, %rax\n", src));
                    src = "%rax".to_string();
                }

                if mul > 0 {
                    state.output.push_str(&format!("    addq {}, {}\n", src, dest));
                } else {
                    state.output.push_str(&format!("    subq {}, {}\n", src, dest));
                }
            }
            Set(offset, value) => {
                if offset == 0 && value == 0 {
                    state.output.push_str("    xor %r12, %r12\n");
                } else if offset == 0 {
                    state.output.push_str(&format!("    movq ${}, %r12\n", value));
                } else {
                    state.output.push_str(&format!("    movq ${}, {}(%rbx)\n", value, offset * 8));
                }
            }
            Move(offset) => {
                if offset != 0 {
                    state.output.push_str("    movq %r12, (%rbx)\n");
                    if offset > 0 {
                        state.output.push_str(&format!("    addq ${}, %rbx\n", offset * 8));
                    } else {
                        state.output.push_str(&format!("    subq ${}, %rbx\n", -offset * 8));
                    }
                    state.output.push_str("    movq (%rbx), %r12\n");
                }
            }
            Loop(content) => {
                state.loopnum += 1;
                let curloop = state.loopnum;
                state.output.push_str(&format!(concat!("    jmp endloop{}\n", "    loop{}:\n"),
                                               curloop,
                                               curloop));

                compile_iter(state, content);

                state.output.push_str(&format!(concat!("    endloop{}:\n",
                                                       "    test %r12, %r12\n",
                                                       "    jnz loop{}\n"),
                                               curloop,
                                               curloop))
            }
            If(offset, content) => {
                state.ifnum += 1;
                let curif = state.ifnum;
                if offset == 0 {
                    state.output.push_str("    test %r12, %r12\n");
                } else {
                    state.output.push_str(&format!("    cmpq $0, {}(%rbx)\n", offset * 8));
                }
                state.output.push_str(&format!("    jz endif{}\n", curif));

                compile_iter(state, content);

                state.output.push_str(&format!("    endif{}:\n", curif))
            }
            Scan(offset) => {
                // Slighly more optimal than normal loop and move
                state.loopnum += 1;
                state.output.push_str(&format!(concat!("    movq %r12, (%rbx)\n",
                                                       "    jmp endloop{}\n",
                                                       "    loop{}:\n"),
                                               state.loopnum,
                                               state.loopnum));
                if offset > 0 {
                    state.output.push_str(&format!("    addq ${}, %rbx\n", offset * 8));
                } else {
                    state.output.push_str(&format!("    subq ${}, %rbx\n", -offset * 8));
                }
                state.output.push_str(&format!(concat!("    endloop{}:\n",
                                                       "    cmp $0, (%rbx)\n",
                                                       "    jnz loop{}\n",
                                                       "    movq (%rbx), %r12\n"),
                                               state.loopnum,
                                               state.loopnum));
            }
            Input => {
                state.output.push_str(concat!("\n    xor %rax, %rax\n",
                                              "    xor %rdi, %rdi\n",
                                              "    movq %rbx, %rsi\n",
                                              "    movq $1, %rdx\n",
                                              "    syscall\n",
                                              "    movq (%rbx), %r12\n\n"))
            }
            LoadOut(offset, add) => {
                let outaddr = format!("(strbuff+{})", outbuffpos);
                if offset == 0 {
                    state.output.push_str(&format!("    movq %r12, {}\n", outaddr));
                } else {
                    state.output.push_str(&format!("    movq {}(%rbx), %rax\n", offset * 8));
                    state.output.push_str(&format!("    movq %rax, {}\n", outaddr));
                }
                if add > 0 {
                    state.output.push_str(&format!("    addb ${}, {}\n", add, outaddr));
                } else if add < 0 {
                    state.output.push_str(&format!("    subb ${}, {}\n", -add, outaddr));
                }
                outbuffpos += 1;
            }
            LoadOutSet(value) => {
                let outaddr = format!("(strbuff+{})", outbuffpos);
                state.output.push_str(&format!("    movq ${}, {}\n", value, outaddr));
                outbuffpos += 1;
            }
            Output => {
                state.output.push_str(&format!(concat!("    movq $1, %rax\n",
                                                       "    movq $1, %rdi\n",
                                                       "    movq $strbuff, %rsi\n",
                                                       "    movq ${}, %rdx\n",
                                                       "    syscall\n\n"),
                                               outbuffpos));

                if state.outbuffsize < outbuffpos + 8 {
                    state.outbuffsize = outbuffpos + 8;
                }
                outbuffpos = 0;
            }
        }
    }
}

pub fn compile(tokens: Vec<Token>, tape_size: i32) -> String {
    let mut state = CompileState::default();

    compile_iter(&mut state, tokens);

    format!(concat!(".section .bss\n",
                    "    .lcomm strbuff, {outbuffsize}\n",
                    "    .lcomm mem, {}\n",
                    "    .set startidx, mem + {}\n",
                    ".section .text\n",
                    ".global _start\n",
                    "_start:\n",
                    "    xor %r12, %r12\n",
                    "    movq $startidx, %rbx\n\n",
                    "{}\n",
                    // Exit syscall
                    "    movq $60, %rax\n",
                    "    movq $0, %rdi\n",
                    "    syscall\n"),
            tape_size,
            tape_size / 2,
            state.output,
            outbuffsize = state.outbuffsize)
}
<|endoftext|>


<commit_before>//! Compound data types.

#![allow(non_snake_case)]

use std::mem;

use Result;
use band::{Band, Value};
use primitive::*;

macro_rules! itemize(
    ($code:item) => ($code);
);

macro_rules! compound(
    ($structure:ident { $($field:ident ($($kind:tt)+) $(|$this:ident| $body:block)*,)+ }) => (
        declare!($structure { $($field $($kind)+,)+ });
        implement!($structure { $($field ($($kind)+) $(|$this| $body)*,)+ });
    );
);

macro_rules! declare(
    ($structure:ident { $($field:ident $kind:ty,)+ }) => (
        itemize! {
            #[derive(Debug, Default)]
            pub struct $structure { $(pub $field: $kind,)+ }
        }
    );
);

macro_rules! implement(
    ($structure:ident { $($field:ident ($($kind:tt)+) $(|$this:ident| $body:block)*,)+ }) => (
        impl Value for $structure {
            fn read<T: Band>(band: &mut T) -> Result<Self> {
                let mut value = $structure::default();
                $(value.$field = read!($structure, value, band, $($kind)+ $(|$this| $body)*);)+
                Ok(value)
            }
        }
    );
);

macro_rules! read(
    ($structure:ident, $this:ident, $band:ident, Vec<$kind:ty> |$that:ident| $body:block) => ({
        #[allow(unused_variables)]
        fn count($that: &$structure) -> usize $body
        let _ = count(&$this);
        vec![]
    });
    ($structure:ident, $this:ident, $band:ident, $kind:ty) => ({
        try!(Value::read($band))
    });
);

compound!(OffsetTable {
    version       (Fixed ),
    numTables     (USHORT),
    searchRange   (USHORT),
    entrySelector (USHORT),
    rangeShift    (USHORT),
});

compound!(TableRecord {
    tag      (ULONG),
    checkSum (ULONG),
    offset   (ULONG),
    length   (ULONG),
});

compound!(CharMappingHeader {
    version   (USHORT),
    numTables (USHORT),
});

compound!(EncodingRecord {
    platformID (USHORT),
    encodingID (USHORT),
    offset     (ULONG ),
});

pub enum CharMapping {
    Format4(CharMappingFormat4),
    Format6(CharMappingFormat6),
}

compound!(CharMappingFormat4 {
    format        (USHORT     ),
    length        (USHORT     ),
    language      (USHORT     ),
    segCountX2    (USHORT     ),
    searchRange   (USHORT     ),
    entrySelector (USHORT     ),
    rangeShift    (USHORT     ),
    endCount      (Vec<USHORT>) |this| { 0 },
    reservedPad   (USHORT     ),
    startCount    (Vec<USHORT>) |this| { 0 },
    idDelta       (Vec<SHORT> ) |this| { 0 },
    idRangeOffset (Vec<USHORT>) |this| { 0 },
    glyphIdArray  (Vec<USHORT>) |this| { 0 },
});

compound!(CharMappingFormat6 {
    format       (USHORT     ),
    length       (USHORT     ),
    language     (USHORT     ),
    firstCode    (USHORT     ),
    entryCount   (USHORT     ),
    glyphIdArray (Vec<USHORT>) |this| { 0 },
});

compound!(FontHeader {
    version            (Fixed       ),
    fontRevision       (Fixed       ),
    checkSumAdjustment (ULONG       ),
    magicNumber        (ULONG       ),
    flags              (USHORT      ),
    unitsPerEm         (USHORT      ),
    created            (LONGDATETIME),
    modified           (LONGDATETIME),
    xMin               (SHORT       ),
    yMin               (SHORT       ),
    xMax               (SHORT       ),
    yMax               (SHORT       ),
    macStyle           (USHORT      ),
    lowestRecPPEM      (USHORT      ),
    fontDirectionHint  (SHORT       ),
    indexToLocFormat   (SHORT       ),
    glyphDataFormat    (SHORT       ),
});

pub enum MaxProfile {
    Version05(MaxProfileVersion05),
    Version10(MaxProfileVersion10),
}

compound!(MaxProfileVersion05 {
    version   (Fixed ),
    numGlyphs (USHORT),
});

compound!(MaxProfileVersion10 {
    version               (Fixed ),
    numGlyphs             (USHORT),
    maxPoints             (USHORT),
    maxContours           (USHORT),
    maxCompositePoints    (USHORT),
    maxCompositeContours  (USHORT),
    maxZones              (USHORT),
    maxTwilightPoints     (USHORT),
    maxStorage            (USHORT),
    maxFunctionDefs       (USHORT),
    maxInstructionDefs    (USHORT),
    maxStackElements      (USHORT),
    maxSizeOfInstructions (USHORT),
    maxComponentElements  (USHORT),
    maxComponentDepth     (USHORT),
});

impl TableRecord {
    #[doc(hidden)]
    pub fn check<T, F>(&self, band: &mut T, process: F) -> Result<bool>
        where T: Band, F: Fn(usize, ULONG) -> ULONG
    {
        let length = {
            let size = mem::size_of::<ULONG>();
            ((self.length as usize + size - 1) & !(size - 1)) / size
        };
        band.stay(|band| {
            try!(band.jump(self.offset as u64));
            let mut checksum: u64 = 0;
            for i in 0..length {
                checksum += process(i, try!(ULONG::read(band))) as u64;
            }
            Ok(self.checkSum == checksum as u32)
        })
    }
}

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

    #[test]
    fn char_mapping() {
        use band::Value;
        use compound::{CharMappingHeader, EncodingRecord};
        use std::io::{Seek, SeekFrom};

        let mut file = tests::open("SourceSerifPro-Regular.otf");
        file.seek(SeekFrom::Start(15668)).unwrap();

        let header = CharMappingHeader::read(&mut file).unwrap();
        assert_eq!(header.version, 0);
        assert_eq!(header.numTables, 3);

        let (platforms, encodings) = ([0, 1, 3], [3, 0, 1]);
        for i in 0..3 {
            let record = EncodingRecord::read(&mut file).unwrap();
            assert_eq!(record.platformID, platforms[i]);
            assert_eq!(record.encodingID, encodings[i]);
        }
    }

    #[test]
    fn offset_table() {
        use band::Value;
        use compound::OffsetTable;

        let mut file = tests::open("SourceSerifPro-Regular.otf");
        let table = OffsetTable::read(&mut file).unwrap();

        assert_eq!(table.version.0, 0x4f54544f);
        assert_eq!(table.numTables, 12);
        assert_eq!(table.searchRange, 8 * 16);
        assert_eq!(table.entrySelector, 3);
        assert_eq!(table.rangeShift, table.numTables * 16 - table.searchRange);
    }

    #[test]
    fn table_record() {
        use compound::TableRecord;
        use std::io::Cursor;

        macro_rules! check(
            ($length:expr, $checksum:expr, $data:expr) => ({
                let data: &[u8] = $data;
                let mut reader = Cursor::new(data);
                let table = TableRecord {
                    length: $length,
                    checkSum: $checksum,
                    .. TableRecord::default()
                };
                table.check(&mut reader, |_, chunk| chunk).unwrap()
            })
        );

        assert!(!check!(3 * 4, 1 + 2 + 4, &[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]));
        assert!( check!(3 * 4, 1 + 2 + 3, &[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]));
    }
}
<commit_msg>Dry a bit<commit_after>//! Compound data types.

#![allow(non_snake_case)]

use std::mem;

use Result;
use band::{Band, Value};
use primitive::*;

macro_rules! itemize(
    ($code:item) => ($code);
);

macro_rules! compound(
    ($structure:ident { $($field:ident ($($kind:tt)+) $(|$this:ident| $body:block)*,)+ }) => (
        declare!($structure { $($field $($kind)+,)+ });
        implement!($structure { $($field ($($kind)+) $(|$this| $body)*,)+ });
    );
);

macro_rules! declare(
    ($structure:ident { $($field:ident $kind:ty,)+ }) => (
        itemize! {
            #[derive(Debug, Default)]
            pub struct $structure { $(pub $field: $kind,)+ }
        }
    );
);

macro_rules! implement(
    ($structure:ident { $($field:ident ($($kind:tt)+) $(|$this:ident| $body:block)*,)+ }) => (
        impl Value for $structure {
            fn read<T: Band>(band: &mut T) -> Result<Self> {
                let mut value = $structure::default();
                $(value.$field = read!($structure, value, band, $($kind)+ $(|$this| $body)*);)+
                Ok(value)
            }
        }
    );
);

macro_rules! read(
    ($structure:ident, $this:ident, $band:ident, Vec<$kind:ty> |$that:ident| $body:block) => ({
        #[allow(unused_variables)]
        fn count($that: &$structure) -> usize $body
        let _ = count(&$this);
        vec![]
    });
    ($structure:ident, $this:ident, $band:ident, $kind:ty) => ({
        try!(Value::read($band))
    });
);

compound!(OffsetTable {
    version       (Fixed ),
    numTables     (USHORT),
    searchRange   (USHORT),
    entrySelector (USHORT),
    rangeShift    (USHORT),
});

compound!(TableRecord {
    tag      (ULONG),
    checkSum (ULONG),
    offset   (ULONG),
    length   (ULONG),
});

compound!(CharMappingHeader {
    version   (USHORT),
    numTables (USHORT),
});

compound!(EncodingRecord {
    platformID (USHORT),
    encodingID (USHORT),
    offset     (ULONG ),
});

pub enum CharMapping {
    Format4(CharMappingFormat4),
    Format6(CharMappingFormat6),
}

compound!(CharMappingFormat4 {
    format        (USHORT     ),
    length        (USHORT     ),
    language      (USHORT     ),
    segCountX2    (USHORT     ),
    searchRange   (USHORT     ),
    entrySelector (USHORT     ),
    rangeShift    (USHORT     ),
    endCount      (Vec<USHORT>) |this| { 0 },
    reservedPad   (USHORT     ),
    startCount    (Vec<USHORT>) |this| { 0 },
    idDelta       (Vec<SHORT> ) |this| { 0 },
    idRangeOffset (Vec<USHORT>) |this| { 0 },
    glyphIdArray  (Vec<USHORT>) |this| { 0 },
});

compound!(CharMappingFormat6 {
    format       (USHORT     ),
    length       (USHORT     ),
    language     (USHORT     ),
    firstCode    (USHORT     ),
    entryCount   (USHORT     ),
    glyphIdArray (Vec<USHORT>) |this| { 0 },
});

compound!(FontHeader {
    version            (Fixed       ),
    fontRevision       (Fixed       ),
    checkSumAdjustment (ULONG       ),
    magicNumber        (ULONG       ),
    flags              (USHORT      ),
    unitsPerEm         (USHORT      ),
    created            (LONGDATETIME),
    modified           (LONGDATETIME),
    xMin               (SHORT       ),
    yMin               (SHORT       ),
    xMax               (SHORT       ),
    yMax               (SHORT       ),
    macStyle           (USHORT      ),
    lowestRecPPEM      (USHORT      ),
    fontDirectionHint  (SHORT       ),
    indexToLocFormat   (SHORT       ),
    glyphDataFormat    (SHORT       ),
});

pub enum MaxProfile {
    Version05(MaxProfileVersion05),
    Version10(MaxProfileVersion10),
}

compound!(MaxProfileVersion05 {
    version   (Fixed ),
    numGlyphs (USHORT),
});

compound!(MaxProfileVersion10 {
    version               (Fixed ),
    numGlyphs             (USHORT),
    maxPoints             (USHORT),
    maxContours           (USHORT),
    maxCompositePoints    (USHORT),
    maxCompositeContours  (USHORT),
    maxZones              (USHORT),
    maxTwilightPoints     (USHORT),
    maxStorage            (USHORT),
    maxFunctionDefs       (USHORT),
    maxInstructionDefs    (USHORT),
    maxStackElements      (USHORT),
    maxSizeOfInstructions (USHORT),
    maxComponentElements  (USHORT),
    maxComponentDepth     (USHORT),
});

impl TableRecord {
    #[doc(hidden)]
    pub fn check<T, F>(&self, band: &mut T, process: F) -> Result<bool>
        where T: Band, F: Fn(usize, ULONG) -> ULONG
    {
        let length = {
            let size = mem::size_of::<ULONG>();
            ((self.length as usize + size - 1) & !(size - 1)) / size
        };
        band.stay(|band| {
            try!(band.jump(self.offset as u64));
            let mut checksum: u64 = 0;
            for i in 0..length {
                checksum += process(i, try!(Value::read(band))) as u64;
            }
            Ok(self.checkSum == checksum as u32)
        })
    }
}

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

    #[test]
    fn char_mapping() {
        use band::Value;
        use compound::{CharMappingHeader, EncodingRecord};
        use std::io::{Seek, SeekFrom};

        let mut file = tests::open("SourceSerifPro-Regular.otf");
        file.seek(SeekFrom::Start(15668)).unwrap();

        let header = CharMappingHeader::read(&mut file).unwrap();
        assert_eq!(header.version, 0);
        assert_eq!(header.numTables, 3);

        let (platforms, encodings) = ([0, 1, 3], [3, 0, 1]);
        for i in 0..3 {
            let record = EncodingRecord::read(&mut file).unwrap();
            assert_eq!(record.platformID, platforms[i]);
            assert_eq!(record.encodingID, encodings[i]);
        }
    }

    #[test]
    fn offset_table() {
        use band::Value;
        use compound::OffsetTable;

        let mut file = tests::open("SourceSerifPro-Regular.otf");
        let table = OffsetTable::read(&mut file).unwrap();

        assert_eq!(table.version.0, 0x4f54544f);
        assert_eq!(table.numTables, 12);
        assert_eq!(table.searchRange, 8 * 16);
        assert_eq!(table.entrySelector, 3);
        assert_eq!(table.rangeShift, table.numTables * 16 - table.searchRange);
    }

    #[test]
    fn table_record() {
        use compound::TableRecord;
        use std::io::Cursor;

        macro_rules! check(
            ($length:expr, $checksum:expr, $data:expr) => ({
                let data: &[u8] = $data;
                let mut reader = Cursor::new(data);
                let table = TableRecord {
                    length: $length,
                    checkSum: $checksum,
                    .. TableRecord::default()
                };
                table.check(&mut reader, |_, chunk| chunk).unwrap()
            })
        );

        assert!(!check!(3 * 4, 1 + 2 + 4, &[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]));
        assert!( check!(3 * 4, 1 + 2 + 3, &[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]));
    }
}
<|endoftext|>


<commit_before>use std::{ops, cmp, fmt, str, error};

use super::num::bigint::BigInt;
use super::num::Zero;

/// Represents currency through an optional symbol and amount of coin.
///
/// Every 100 coins results in a banknote. (100 is formatted as 1.00)
/// The currency will be formatted as such: `Currency(Some('$'), 432)` ==> "$4.32"
#[derive(Debug, Clone)]
pub struct Currency {
    symbol: Option<char>,
    coin: BigInt
}

impl Currency {
    /// Creates a blank Currency with no symbol and 0 coin.
    ///
    /// # Examples
    /// ```
    /// extern crate currency;
    /// use currency::Currency;
    ///
    /// let mut c = Currency::new();
    /// ```
    pub fn new() -> Currency {
        Currency {
            symbol: None,
            coin: BigInt::zero()
        }
    }

    // TODO
    // - to_str with comma delimiting
    // - to_str with euro delimiting
}

/// Allows any Currency to be displayed as a String. The format includes no comma delimiting with a
/// two digit precision decimal.
///
/// # Formats
///
/// ## Arguments
///
/// `#` display commas
///
/// ## Examples
///
/// {} => No commas, rounded to nearest dollar.
/// {:#} => Commas, rounded to nearest dollar.
/// {:#.2} => Commas, with decimal point. (values greater than two will route to this fmt as well)
/// {:.1} => No commas, rounded to nearest ten cents.
///
/// # Examples
/// ```
/// use currency::Currency;
///
/// assert!(Currency(Some('$'), 1210).to_string() == "$12.10");
/// assert!(Currency(None, 1210).to_string() == "12.10");
///
/// println!("{:#}", Currency(Some('$'), 100099)); // $1,000
/// println!("{:.2}", Currency(Some('$'), 100099)); //
/// println!("{:.1}", Currency(Some('$'), 100099));
/// println!("{:.0}", Currency(Some('$'), 100099)); //
/// ```
/// The last line prints:
/// ```text
/// "$1000.99"
/// ```
impl fmt::Display for Currency { // TODO TODO TODO TODO
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let one_hundred = BigInt::from(100);
        // TODO cases
        let cents = &self.coin % one_hundred;
        let dollars = &self.coin - &cents;
        match self.symbol {
            Some(c) => write!(f, "{}{}.{}", c, dollars, cents),
            None    => write!(f, "{}.{}", dollars, cents),
        }
    }
}

// impl str::FromStr for Currency {
//     type Err = ParseCurrencyError;
//
//     /// Uses a Regular Expression to parse a string literal (&str) and attempts to turn it into a
//     /// currency. Returns `Some(Currency)` on a successful conversion, otherwise `None`.
//     ///
//     /// If the currency is intended to be a negative amount, ensure the '-' is the first character
//     /// in the string.
//     /// The Regex recognizes European notation (€1,00)
//     ///
//     /// # Examples
//     /// ```
//     /// use currency::Currency;
//     ///
//     /// assert!(Currency::from_string("$4.32")  == Some(Currency(Some('$'), 432)));
//     /// assert!(Currency::from_string("-$4.32") == Some(Currency(Some('$'), -432)));
//     /// assert!(Currency::from_string("424.44") == Some(Currency(None, 42444)));
//     /// assert!(Currency::from_string("£12,00") == Some(Currency(Some('£'), 1200)));
//     /// assert!(Currency::from_string("¥12")    == Some(Currency(Some('¥'), 1200)));
//     /// ```
//     fn from_str(s: &str) -> Result<Currency, ParseCurrencyError> {
//         use regex::Regex;
//
//         // Shadow s with a trimmed version
//         let s = s.trim();
//         let re =
//         Regex::new(r"(?:\b|(-)?)(\p{Sc})?((?:(?:\d{1,3}[\.,])+\d{3})|\d+)(?:[\.,](\d{2}))?\b")
//         .unwrap();
//
//         if !re.is_match(s) {
//             return None;
//         }
//
//         // Used to negate the final result if the regex matches a negative
//         let mut multiplier = 1;
//         let mut sign: Option<char> = None;
//         let mut coin_str: String = "".to_string();
//
//         // If anyone's looking at this and knows how to do this without a loop, fork this.
//         for cap in re.captures_iter(s) {
//             if cap.at(0).unwrap_or("") != s {
//                 return None;
//             }
//
//             if cap.at(1).is_some() {
//                 multiplier = -1;
//             }
//
//             if cap.at(2).is_some() {
//                 if multiplier < 0 {
//                     sign = Some(s.chars().skip(1).next().unwrap());
//                 } else {
//                     sign = Some(s.chars().next().unwrap());
//                 }
//             }
//             coin_str = cap.at(3).unwrap().replace(".", "").replace(",", "")
//             + cap.at(4).unwrap_or("00");
//
//             break;
//         }
//
//         if let Ok(coin) = coin_str.parse::<i64>(){
//             return Some(Currency(sign, multiplier * coin));
//         }
//         None
//     }
// }

#[derive(Debug, Clone, PartialEq)]
pub struct ParseCurrencyError {
    source: String
}

impl fmt::Display for ParseCurrencyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Could not parse {} into a currency.", self.source)
    }
}

impl error::Error for ParseCurrencyError {
    fn description(&self) -> &str {
        "Failed to parse currency"
    }
}

/// Identical to the implementation of Display, but replaces the "." with a ",". Access this
/// formating by using "{:e}".
///
/// # Examples
/// ```
/// use currency::Currency;
///
/// println!("{:e}", Currency(Some('£'), 100099));
/// ```
/// The last line prints the following:
/// ```text
/// "£1000,99"
/// ```
impl fmt::LowerExp for Currency {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", format!("{}", self).replace(".", ","))
    }
}

/// Overloads the '==' operator for Currency objects.
///
/// # Panics
/// Panics if the two comparators are different types of currency, as denoted by the Currency's
/// symbol.
impl PartialEq<Currency> for Currency {
    fn eq(&self, rhs: &Currency) -> bool {
        self.symbol == rhs.symbol && self.coin == rhs.coin
    }

    fn ne(&self, rhs: &Currency) -> bool {
        self.symbol != rhs.symbol || self.coin != rhs.coin
    }
}

/// Overloads the order operators for Currency objects.
///
/// These operators include '<', '<=', '>', and '>='.
///
/// # Panics
/// Panics if the two comparators are different types of currency, as denoted by
/// the Currency's symbol.
impl PartialOrd<Currency> for Currency {
    fn partial_cmp(&self, rhs: &Currency) -> Option<cmp::Ordering> {
        if self.symbol == rhs.symbol {
            self.coin.partial_cmp(&rhs.coin)
        } else {
            None
        }
    }

    fn lt(&self, rhs: &Currency) -> bool {
        if self.symbol == rhs.symbol {
            self.coin.lt(&rhs.coin)
        } else {
            panic!("Cannot compare two different types of currency.");
        }
    }

    fn le(&self, rhs: &Currency) -> bool {
        if self.symbol == rhs.symbol {
            self.coin.le(&rhs.coin)
        } else {
            panic!("Cannot compare two different types of currency.");
        }
    }

    fn gt(&self, rhs: &Currency) -> bool {
        if self.symbol == rhs.symbol {
            self.coin.gt(&rhs.coin)
        } else {
            panic!("Cannot compare two different types of currency.");
        }
    }

    fn ge(&self, rhs: &Currency) -> bool {
        if self.symbol == rhs.symbol {
            self.coin.ge(&rhs.coin)
        } else {
            panic!("Cannot compare two different types of currency.");
        }
    }
}

/// Overloads the '+' operator for Currency objects.
///
/// # Panics
/// Panics if the two addends are different types of currency, as denoted by the Currency's symbol.
impl ops::Add for Currency {
    type Output = Currency;

    fn add(self, rhs: Currency) -> Currency {
        if self.symbol == rhs.symbol {
            Currency {
                symbol: self.symbol,
                coin: self.coin.add(rhs.coin)
            }
        } else {
            panic!("Cannot add two different types of currency.");
        }
    }
}

/// Overloads the '-' operator for Currency objects.
///
/// # Panics
/// Panics if the minuend and subtrahend are two different types of currency, as denoted by the
/// Currency's symbol.
impl ops::Sub for Currency {
    type Output = Currency;

    fn sub(self, rhs: Currency) -> Currency {
        if self.symbol == rhs.symbol {
            Currency {
                symbol: self.symbol,
                coin: self.coin.sub(rhs.coin)
            }
        } else {
            panic!("Cannot subtract two different types of currency.");
        }
    }
}

/// Overloads the '*' operator for Currency objects.
///
/// Allows a Currency to be multiplied by an i64.
impl ops::Mul<i64> for Currency {
    type Output = Currency;

    fn mul(self, rhs: i64) -> Currency {
        Currency {
            symbol: self.symbol,
            coin: self.coin.mul(BigInt::from(rhs))
        }
    }
}
// TODO mul for each num type, both ways

/// Overloads the '*' operator for Currency objects.
///
/// Allows a Currency to be multiplied by an i64.
impl ops::Mul<Currency> for Currency {
    type Output = Currency;

    fn mul(self, rhs: Currency) -> Currency {
        if self.symbol == rhs.symbol {
            Currency {
                symbol: self.symbol,
                coin: self.coin.mul(rhs.coin)
            }
        } else {
            panic!("Cannot multiply two different types of currency.");
        }
    }
}

// TODO
// - neg
// - rem
// - hash
<commit_msg>updated doc for currency struct<commit_after>use std::{ops, cmp, fmt, str, error};

use super::num::bigint::BigInt;
use super::num::Zero;

/// Represents currency through an optional symbol and amount of coin.
///
/// Every 100 coins represents a banknote. (coin: 100 => 1.00)
/// A currency is formatted by default as such:
/// `Currency { symbol: Some('$'), coin: 432 }` => "$4.32"
#[derive(Debug, Clone)]
pub struct Currency {
    symbol: Option<char>,
    coin: BigInt
}

impl Currency {
    /// Creates a blank Currency with no symbol and 0 coin.
    ///
    /// # Examples
    /// ```
    /// extern crate currency;
    /// use currency::Currency;
    ///
    /// let mut c = Currency::new();
    /// ```
    pub fn new() -> Currency {
        Currency {
            symbol: None,
            coin: BigInt::zero()
        }
    }

    // TODO
    // - to_str with comma delimiting
    // - to_str with euro delimiting
}

/// Allows any Currency to be displayed as a String. The format includes no comma delimiting with a
/// two digit precision decimal.
///
/// # Formats
///
/// ## Arguments
///
/// `#` display commas
///
/// ## Examples
///
/// {} => No commas, rounded to nearest dollar.
/// {:#} => Commas, rounded to nearest dollar.
/// {:#.2} => Commas, with decimal point. (values greater than two will route to this fmt as well)
/// {:.1} => No commas, rounded to nearest ten cents.
///
/// # Examples
/// ```
/// use currency::Currency;
///
/// assert!(Currency(Some('$'), 1210).to_string() == "$12.10");
/// assert!(Currency(None, 1210).to_string() == "12.10");
///
/// println!("{:#}", Currency(Some('$'), 100099)); // $1,000
/// println!("{:.2}", Currency(Some('$'), 100099)); //
/// println!("{:.1}", Currency(Some('$'), 100099));
/// println!("{:.0}", Currency(Some('$'), 100099)); //
/// ```
/// The last line prints:
/// ```text
/// "$1000.99"
/// ```
impl fmt::Display for Currency { // TODO TODO TODO TODO
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let one_hundred = BigInt::from(100);
        // TODO cases
        let cents = &self.coin % one_hundred;
        let dollars = &self.coin - &cents;
        match self.symbol {
            Some(c) => write!(f, "{}{}.{}", c, dollars, cents),
            None    => write!(f, "{}.{}", dollars, cents),
        }
    }
}

// impl str::FromStr for Currency {
//     type Err = ParseCurrencyError;
//
//     /// Uses a Regular Expression to parse a string literal (&str) and attempts to turn it into a
//     /// currency. Returns `Some(Currency)` on a successful conversion, otherwise `None`.
//     ///
//     /// If the currency is intended to be a negative amount, ensure the '-' is the first character
//     /// in the string.
//     /// The Regex recognizes European notation (€1,00)
//     ///
//     /// # Examples
//     /// ```
//     /// use currency::Currency;
//     ///
//     /// assert!(Currency::from_string("$4.32")  == Some(Currency(Some('$'), 432)));
//     /// assert!(Currency::from_string("-$4.32") == Some(Currency(Some('$'), -432)));
//     /// assert!(Currency::from_string("424.44") == Some(Currency(None, 42444)));
//     /// assert!(Currency::from_string("£12,00") == Some(Currency(Some('£'), 1200)));
//     /// assert!(Currency::from_string("¥12")    == Some(Currency(Some('¥'), 1200)));
//     /// ```
//     fn from_str(s: &str) -> Result<Currency, ParseCurrencyError> {
//         use regex::Regex;
//
//         // Shadow s with a trimmed version
//         let s = s.trim();
//         let re =
//         Regex::new(r"(?:\b|(-)?)(\p{Sc})?((?:(?:\d{1,3}[\.,])+\d{3})|\d+)(?:[\.,](\d{2}))?\b")
//         .unwrap();
//
//         if !re.is_match(s) {
//             return None;
//         }
//
//         // Used to negate the final result if the regex matches a negative
//         let mut multiplier = 1;
//         let mut sign: Option<char> = None;
//         let mut coin_str: String = "".to_string();
//
//         // If anyone's looking at this and knows how to do this without a loop, fork this.
//         for cap in re.captures_iter(s) {
//             if cap.at(0).unwrap_or("") != s {
//                 return None;
//             }
//
//             if cap.at(1).is_some() {
//                 multiplier = -1;
//             }
//
//             if cap.at(2).is_some() {
//                 if multiplier < 0 {
//                     sign = Some(s.chars().skip(1).next().unwrap());
//                 } else {
//                     sign = Some(s.chars().next().unwrap());
//                 }
//             }
//             coin_str = cap.at(3).unwrap().replace(".", "").replace(",", "")
//             + cap.at(4).unwrap_or("00");
//
//             break;
//         }
//
//         if let Ok(coin) = coin_str.parse::<i64>(){
//             return Some(Currency(sign, multiplier * coin));
//         }
//         None
//     }
// }

#[derive(Debug, Clone, PartialEq)]
pub struct ParseCurrencyError {
    source: String
}

impl fmt::Display for ParseCurrencyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Could not parse {} into a currency.", self.source)
    }
}

impl error::Error for ParseCurrencyError {
    fn description(&self) -> &str {
        "Failed to parse currency"
    }
}

/// Identical to the implementation of Display, but replaces the "." with a ",". Access this
/// formating by using "{:e}".
///
/// # Examples
/// ```
/// use currency::Currency;
///
/// println!("{:e}", Currency(Some('£'), 100099));
/// ```
/// The last line prints the following:
/// ```text
/// "£1000,99"
/// ```
impl fmt::LowerExp for Currency {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", format!("{}", self).replace(".", ","))
    }
}

/// Overloads the '==' operator for Currency objects.
///
/// # Panics
/// Panics if the two comparators are different types of currency, as denoted by the Currency's
/// symbol.
impl PartialEq<Currency> for Currency {
    fn eq(&self, rhs: &Currency) -> bool {
        self.symbol == rhs.symbol && self.coin == rhs.coin
    }

    fn ne(&self, rhs: &Currency) -> bool {
        self.symbol != rhs.symbol || self.coin != rhs.coin
    }
}

/// Overloads the order operators for Currency objects.
///
/// These operators include '<', '<=', '>', and '>='.
///
/// # Panics
/// Panics if the two comparators are different types of currency, as denoted by
/// the Currency's symbol.
impl PartialOrd<Currency> for Currency {
    fn partial_cmp(&self, rhs: &Currency) -> Option<cmp::Ordering> {
        if self.symbol == rhs.symbol {
            self.coin.partial_cmp(&rhs.coin)
        } else {
            None
        }
    }

    fn lt(&self, rhs: &Currency) -> bool {
        if self.symbol == rhs.symbol {
            self.coin.lt(&rhs.coin)
        } else {
            panic!("Cannot compare two different types of currency.");
        }
    }

    fn le(&self, rhs: &Currency) -> bool {
        if self.symbol == rhs.symbol {
            self.coin.le(&rhs.coin)
        } else {
            panic!("Cannot compare two different types of currency.");
        }
    }

    fn gt(&self, rhs: &Currency) -> bool {
        if self.symbol == rhs.symbol {
            self.coin.gt(&rhs.coin)
        } else {
            panic!("Cannot compare two different types of currency.");
        }
    }

    fn ge(&self, rhs: &Currency) -> bool {
        if self.symbol == rhs.symbol {
            self.coin.ge(&rhs.coin)
        } else {
            panic!("Cannot compare two different types of currency.");
        }
    }
}

/// Overloads the '+' operator for Currency objects.
///
/// # Panics
/// Panics if the two addends are different types of currency, as denoted by the Currency's symbol.
impl ops::Add for Currency {
    type Output = Currency;

    fn add(self, rhs: Currency) -> Currency {
        if self.symbol == rhs.symbol {
            Currency {
                symbol: self.symbol,
                coin: self.coin.add(rhs.coin)
            }
        } else {
            panic!("Cannot add two different types of currency.");
        }
    }
}

/// Overloads the '-' operator for Currency objects.
///
/// # Panics
/// Panics if the minuend and subtrahend are two different types of currency, as denoted by the
/// Currency's symbol.
impl ops::Sub for Currency {
    type Output = Currency;

    fn sub(self, rhs: Currency) -> Currency {
        if self.symbol == rhs.symbol {
            Currency {
                symbol: self.symbol,
                coin: self.coin.sub(rhs.coin)
            }
        } else {
            panic!("Cannot subtract two different types of currency.");
        }
    }
}

/// Overloads the '*' operator for Currency objects.
///
/// Allows a Currency to be multiplied by an i64.
impl ops::Mul<i64> for Currency {
    type Output = Currency;

    fn mul(self, rhs: i64) -> Currency {
        Currency {
            symbol: self.symbol,
            coin: self.coin.mul(BigInt::from(rhs))
        }
    }
}
// TODO mul for each num type, both ways

/// Overloads the '*' operator for Currency objects.
///
/// Allows a Currency to be multiplied by an i64.
impl ops::Mul<Currency> for Currency {
    type Output = Currency;

    fn mul(self, rhs: Currency) -> Currency {
        if self.symbol == rhs.symbol {
            Currency {
                symbol: self.symbol,
                coin: self.coin.mul(rhs.coin)
            }
        } else {
            panic!("Cannot multiply two different types of currency.");
        }
    }
}

// TODO
// - neg
// - rem
// - hash
<|endoftext|>


<commit_before>use {Bytes, Chunk, SChunks};
use client::GetResponse;
use hyper::client::Client;
use hyper::error::Error;
use hyper::header::{ByteRangeSpec, Headers, Range};
use pbr::{MultiBar, Pipe, ProgressBar, Units};
use response::CheckResponseStatus;
use std::cmp::min;
use std::io::Read;
use std::thread;
use std::time::{Instant, Duration};

/// Represents a range between two Bytes types
#[derive(Debug, PartialEq)]
struct RangeBytes(Bytes, Bytes);

/// Function to get the current chunk length, based on the chunk index.
fn get_chunk_length(chunk_index: u64,
                    content_length: Bytes,
                    global_chunk_length: Bytes)
                    -> Option<RangeBytes> {

    if content_length == 0 || global_chunk_length == 0 {
        return None;
    }

    let b_range: Bytes = chunk_index * global_chunk_length;

    if b_range >= (content_length - 1) {
        return None;
    }

    let e_range: Bytes = min(content_length - 1,
                             ((chunk_index + 1) * global_chunk_length) - 1);

    Some(RangeBytes(b_range, e_range))

}

/// Function to get the HTTP header to send to the file server, for a chunk (specified by its index)
fn get_header_from_index(chunk_index: u64,
                         content_length: Bytes,
                         global_chunk_length: Bytes)
                         -> Option<(Headers, Bytes)> {

    match get_chunk_length(chunk_index, content_length, global_chunk_length) {
        Some(range) => {
            let mut header = Headers::new();
            header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(range.0, range.1)]));
            Some((header, range.1 - range.0))
        }
        None => None,
    }

}

/// Function to get from the server the content of a chunk.
/// This function returns a Result type - Bytes if the content of the header is accessible, an Error type otherwise.
fn download_a_chunk(http_client: &Client,
                    http_header: Headers,
                    chunk_vector: &mut Chunk,
                    url: &str,
                    mpb: &mut ProgressBar<Pipe>)
                    -> Result<Bytes, Error> {

    let mut body = http_client.get_http_response_using_headers(url, http_header).unwrap();
    if !body.check_partialcontent_status() {
        return Err(Error::Status);
    }
    let mut bytes_buffer = [0; 2048];
    let mut sum_bytes = 0;

    let progress_update_interval = Duration::from_millis(500);
    let mut last_progress_bytes = 0;
    let mut last_progress_time = Instant::now() - progress_update_interval;

    while let Ok(n) = body.read(&mut bytes_buffer) {
        if n == 0 {
            return Ok(sum_bytes);
        }

        chunk_vector.extend_from_slice(&bytes_buffer[..n]);
        sum_bytes += n as u64;

        if Instant::now().duration_since(last_progress_time) > progress_update_interval {
            last_progress_time = Instant::now();
            let progress_bytes_delta = sum_bytes-last_progress_bytes;
            last_progress_bytes = sum_bytes;
            mpb.add(progress_bytes_delta);
        }
    }
    mpb.add(sum_bytes-last_progress_bytes);
    return Ok(0u64);
}

/// Function to download each chunk of a remote content (given by its URL).
/// This function takes as parameters:
/// * the remote content length,
/// * a mutable reference to share between threads, which contains each chunk,
/// * the number of chunks that contains the remote content,
/// * the URL of the remote content server.
pub fn download_chunks(content_length: u64,
                       downloaded_chunks: &SChunks,
                       nb_chunks: u64,
                       url: &str) {

    // let mut downloaded_chunks: Arc<Mutex<Chunks>> =
    //     Arc::new(Mutex::new(Chunks::with_capacity(nb_chunks as usize)));
    let global_chunk_length: u64 = (content_length / nb_chunks) + 1;
    let mut jobs = vec![];

    let mut mpb = MultiBar::new();
    mpb.println(&format!("Downloading {} chunks: ", nb_chunks));

    for chunk_index in 0..nb_chunks {

        let (http_header, chunk_length) =
            get_header_from_index(chunk_index, content_length, global_chunk_length).unwrap();
        let mut chunk_content = Chunk::with_capacity(chunk_length as usize);
        let hyper_client = Client::new();
        let url_clone = String::from(url);
        let clone_chunks = downloaded_chunks.clone();

        // Progress bar customization
        let mut mp = mpb.create_bar(chunk_length);
        mp.tick_format("▏▎▍▌▋▊▉██▉▊▋▌▍▎▏");
        mp.format("|#--|");
        mp.show_tick = true;
        mp.show_speed = true;
        mp.show_percent = true;
        mp.show_counter = false;
        mp.show_time_left = true;
        mp.set_units(Units::Bytes);
        mp.message(&format!("Chunk {} ", chunk_index));

        jobs.push(thread::spawn(move || match download_a_chunk(&hyper_client,
                                                                    http_header,
                                                                    &mut chunk_content,
                                                                    &url_clone,
                                                                    &mut mp) {
            Ok(bytes_written) => {
                if bytes_written > 0 {
                    let mut shared_clone_chunks = clone_chunks.lock().unwrap();
                    shared_clone_chunks.insert(chunk_index as usize, chunk_content);
                    mp.finish();
                } else {
                    panic!("The downloaded chunk {} is empty", chunk_index);
                }
            }
            Err(error) => {
                panic!("Cannot download the chunk {}, due to error {}",
                       chunk_index,
                       error);
            }
        }));
    }

    mpb.listen();

    for child in jobs {
        let _ = child.join();
    }

}

#[cfg(test)]
mod test_chunk_length {

    use super::get_chunk_length;
    use super::RangeBytes;

    #[test]
    fn wrong_content_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 15, 0));
    }

    #[test]
    fn wrong_global_chunk_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 15));
    }

    #[test]
    fn wrong_length_parameters_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 0));
    }

    #[test]
    fn get_the_first_range_in_chunk() {
        assert_eq!(Some(RangeBytes(0, 249)), get_chunk_length(0, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_chunk() {
        assert_eq!(Some(RangeBytes(750, 999)), get_chunk_length(3, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_shorten_chunk() {
        assert_eq!(Some(RangeBytes(750, 997)), get_chunk_length(3, 998, 250));
    }

    #[test]
    fn wrong_index_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(4, 1000, 250));
    }

}

#[cfg(test)]
mod test_header {

    use super::get_header_from_index;
    use hyper::header::{ByteRangeSpec, Headers, Range};

    #[test]
    fn wrong_chunk_length_should_return_none() {
        assert_eq!(None, get_header_from_index(0, 0, 0));
    }

    #[test]
    fn good_chunk_length_should_return_a_good_header() {
        let mut test_header = Headers::new();
        test_header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(750, 997)]));
        assert_eq!(Some((test_header, 247)), get_header_from_index(3, 998, 250));
    }

}
<commit_msg>Use larger download buffer<commit_after>use {Bytes, Chunk, SChunks};
use client::GetResponse;
use hyper::client::Client;
use hyper::error::Error;
use hyper::header::{ByteRangeSpec, Headers, Range};
use pbr::{MultiBar, Pipe, ProgressBar, Units};
use response::CheckResponseStatus;
use std::cmp::min;
use std::io::Read;
use std::thread;
use std::time::{Instant, Duration};

const DOWNLOAD_BUFFER_BYTES: usize = 1024*64;

/// Represents a range between two Bytes types
#[derive(Debug, PartialEq)]
struct RangeBytes(Bytes, Bytes);

/// Function to get the current chunk length, based on the chunk index.
fn get_chunk_length(chunk_index: u64,
                    content_length: Bytes,
                    global_chunk_length: Bytes)
                    -> Option<RangeBytes> {

    if content_length == 0 || global_chunk_length == 0 {
        return None;
    }

    let b_range: Bytes = chunk_index * global_chunk_length;

    if b_range >= (content_length - 1) {
        return None;
    }

    let e_range: Bytes = min(content_length - 1,
                             ((chunk_index + 1) * global_chunk_length) - 1);

    Some(RangeBytes(b_range, e_range))

}

/// Function to get the HTTP header to send to the file server, for a chunk (specified by its index)
fn get_header_from_index(chunk_index: u64,
                         content_length: Bytes,
                         global_chunk_length: Bytes)
                         -> Option<(Headers, Bytes)> {

    match get_chunk_length(chunk_index, content_length, global_chunk_length) {
        Some(range) => {
            let mut header = Headers::new();
            header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(range.0, range.1)]));
            Some((header, range.1 - range.0))
        }
        None => None,
    }

}

/// Function to get from the server the content of a chunk.
/// This function returns a Result type - Bytes if the content of the header is accessible, an Error type otherwise.
fn download_a_chunk(http_client: &Client,
                    http_header: Headers,
                    chunk_vector: &mut Chunk,
                    url: &str,
                    mpb: &mut ProgressBar<Pipe>)
                    -> Result<Bytes, Error> {

    let mut body = http_client.get_http_response_using_headers(url, http_header).unwrap();
    if !body.check_partialcontent_status() {
        return Err(Error::Status);
    }
    let mut bytes_buffer = [0; DOWNLOAD_BUFFER_BYTES];
    let mut sum_bytes = 0;

    let progress_update_interval = Duration::from_millis(500);
    let mut last_progress_bytes = 0;
    let mut last_progress_time = Instant::now() - progress_update_interval;

    while let Ok(n) = body.read(&mut bytes_buffer) {
        if n == 0 {
            return Ok(sum_bytes);
        }

        chunk_vector.extend_from_slice(&bytes_buffer[..n]);
        sum_bytes += n as u64;

        if Instant::now().duration_since(last_progress_time) > progress_update_interval {
            last_progress_time = Instant::now();
            let progress_bytes_delta = sum_bytes-last_progress_bytes;
            last_progress_bytes = sum_bytes;
            mpb.add(progress_bytes_delta);
        }
    }
    mpb.add(sum_bytes-last_progress_bytes);
    return Ok(0u64);
}

/// Function to download each chunk of a remote content (given by its URL).
/// This function takes as parameters:
/// * the remote content length,
/// * a mutable reference to share between threads, which contains each chunk,
/// * the number of chunks that contains the remote content,
/// * the URL of the remote content server.
pub fn download_chunks(content_length: u64,
                       downloaded_chunks: &SChunks,
                       nb_chunks: u64,
                       url: &str) {

    // let mut downloaded_chunks: Arc<Mutex<Chunks>> =
    //     Arc::new(Mutex::new(Chunks::with_capacity(nb_chunks as usize)));
    let global_chunk_length: u64 = (content_length / nb_chunks) + 1;
    let mut jobs = vec![];

    let mut mpb = MultiBar::new();
    mpb.println(&format!("Downloading {} chunks: ", nb_chunks));

    for chunk_index in 0..nb_chunks {

        let (http_header, chunk_length) =
            get_header_from_index(chunk_index, content_length, global_chunk_length).unwrap();
        let mut chunk_content = Chunk::with_capacity(chunk_length as usize);
        let hyper_client = Client::new();
        let url_clone = String::from(url);
        let clone_chunks = downloaded_chunks.clone();

        // Progress bar customization
        let mut mp = mpb.create_bar(chunk_length);
        mp.tick_format("▏▎▍▌▋▊▉██▉▊▋▌▍▎▏");
        mp.format("|#--|");
        mp.show_tick = true;
        mp.show_speed = true;
        mp.show_percent = true;
        mp.show_counter = false;
        mp.show_time_left = true;
        mp.set_units(Units::Bytes);
        mp.message(&format!("Chunk {} ", chunk_index));

        jobs.push(thread::spawn(move || match download_a_chunk(&hyper_client,
                                                                    http_header,
                                                                    &mut chunk_content,
                                                                    &url_clone,
                                                                    &mut mp) {
            Ok(bytes_written) => {
                if bytes_written > 0 {
                    let mut shared_clone_chunks = clone_chunks.lock().unwrap();
                    shared_clone_chunks.insert(chunk_index as usize, chunk_content);
                    mp.finish();
                } else {
                    panic!("The downloaded chunk {} is empty", chunk_index);
                }
            }
            Err(error) => {
                panic!("Cannot download the chunk {}, due to error {}",
                       chunk_index,
                       error);
            }
        }));
    }

    mpb.listen();

    for child in jobs {
        let _ = child.join();
    }

}

#[cfg(test)]
mod test_chunk_length {

    use super::get_chunk_length;
    use super::RangeBytes;

    #[test]
    fn wrong_content_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 15, 0));
    }

    #[test]
    fn wrong_global_chunk_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 15));
    }

    #[test]
    fn wrong_length_parameters_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 0));
    }

    #[test]
    fn get_the_first_range_in_chunk() {
        assert_eq!(Some(RangeBytes(0, 249)), get_chunk_length(0, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_chunk() {
        assert_eq!(Some(RangeBytes(750, 999)), get_chunk_length(3, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_shorten_chunk() {
        assert_eq!(Some(RangeBytes(750, 997)), get_chunk_length(3, 998, 250));
    }

    #[test]
    fn wrong_index_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(4, 1000, 250));
    }

}

#[cfg(test)]
mod test_header {

    use super::get_header_from_index;
    use hyper::header::{ByteRangeSpec, Headers, Range};

    #[test]
    fn wrong_chunk_length_should_return_none() {
        assert_eq!(None, get_header_from_index(0, 0, 0));
    }

    #[test]
    fn good_chunk_length_should_return_a_good_header() {
        let mut test_header = Headers::new();
        test_header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(750, 997)]));
        assert_eq!(Some((test_header, 247)), get_header_from_index(3, 998, 250));
    }

}
<|endoftext|>


<commit_before>const MAX: usize = 10_000_000;

fn fill(array: &mut Vec<u8>, index: usize) -> u8 {
    let next = index.to_string()
                    .chars()
                    .map(|c| {
                        match c {
                            '0' => 0,
                            '1' => 1,
                            '2' => 4,
                            '3' => 9,
                            '4' => 16,
                            '5' => 25,
                            '6' => 36,
                            '7' => 49,
                            '8' => 64,
                            '9' => 81,
                            _ => panic!(),
                        }
                    })
                    .fold(0, |acc, n| acc + n);
    if array[next] == 0 {
        array[next] = fill(array, next);
    }
    return array[next];
}

pub fn main() {
    let mut numbers = vec![0; MAX];
    numbers[1] = 1;
    numbers[89] = 89;
    for i in 2..MAX {
        if numbers[i] != 0 {
            continue;
        }
        numbers[i] = fill(&mut numbers, i);
    }
    println!("{}", numbers.iter().filter(|&n| *n == 89).count());
}
<commit_msg>use alternative syntax to avoid the derefence operator<commit_after>const MAX: usize = 10_000_000;

fn fill(array: &mut Vec<u8>, index: usize) -> u8 {
    let next = index.to_string()
                    .chars()
                    .map(|c| {
                        match c {
                            '0' => 0,
                            '1' => 1,
                            '2' => 4,
                            '3' => 9,
                            '4' => 16,
                            '5' => 25,
                            '6' => 36,
                            '7' => 49,
                            '8' => 64,
                            '9' => 81,
                            _ => panic!(),
                        }
                    })
                    .fold(0, |acc, n| acc + n);
    if array[next] == 0 {
        array[next] = fill(array, next);
    }
    return array[next];
}

pub fn main() {
    let mut numbers = vec![0; MAX];
    numbers[1] = 1;
    numbers[89] = 89;
    for i in 2..MAX {
        if numbers[i] != 0 {
            continue;
        }
        numbers[i] = fill(&mut numbers, i);
    }
    println!("{}", numbers.iter().filter(|&&n| n == 89).count());
}
<|endoftext|>