<commit_before>#[macro_use] extern crate error_chain;
#[macro_use] extern crate prettytable;
#[macro_use] extern crate stderr;
extern crate chan;
extern crate clap;
extern crate filetime;
extern crate globset;
extern crate pretty_bytes;
extern crate separator;

#[macro_use] mod errors;
mod compression;
mod lists;
mod structs;

use clap::{App, Arg};
use errors::*;
use globset::{GlobBuilder, GlobSet, GlobSetBuilder};
use lists::*;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::sync::mpsc;
use structs::*;

const DEBUG_FILTERS: bool = cfg!(debug_assertions);

quick_main!(run);

fn run() -> Result<()> {
    let matches = App::new("static-compress")
        .version("0.1")
        .about("Create statically-compresed copies of matching files")
        .author("NeoSmart Technologies")
        .arg(Arg::with_name("compressor")
            .short("c")
            .long("compressor")
            .value_name("[brotli|gzip|zopfli]")
            .help("The compressor to use (default: gzip)")
            .takes_value(true))
        .arg(Arg::with_name("threads")
            .short("j")
            .long("threads")
            .value_name("COUNT")
            .help("The number of simultaneous compressions (default: 1)")
            .takes_value(true))
        .arg(Arg::with_name("filters")
            .value_name("FILTER")
            .multiple(true)
            .required(true))
        .arg(Arg::with_name("ext")
            .short("e")
            .value_name("EXT")
            .long("extension")
            .help("The extension to use for compressed files (default: gz or br)"))
        /*.arg(Arg::with_name("excludes")
            .short("x")
            .value_name("FILTER")
            .long("exclude")
            .multiple(true)
            .help("Exclude files matching this glob expression"))*/
        .get_matches();

    fn get_parameter<'a, T>(matches: &clap::ArgMatches, name: &str, default_value: T) -> Result<T>
        where T: std::str::FromStr
    {
        match matches.value_of(name) {
            Some(v) => {
                Ok(v.parse().map_err(|_| ErrorKind::InvalidParameterValue(name.to_owned()))?)
            }
            None => Ok(default_value),
        }
    }

    let case_sensitive = !matches.is_present("nocase");
    let compressor = get_parameter(&matches, "compressor", CompressionAlgorithm::GZip)?;
    let temp = Parameters {
        extension: matches.value_of("ext")
            .unwrap_or(compressor.extension())
            .trim_matches(|c: char| c.is_whitespace() || c.is_control() || c == '.')
            .to_owned(),
        compressor: compressor,
        threads: get_parameter(&matches, "threads", 1)?,
    };

    /*let exclude_filters = match matches.values_of("exclude") {
        Some(values)=> values.map(|s| s.to_owned()).collect(),
        None => Vec::<String>::new(),
    };*/

    let parameters = Arc::<Parameters>::new(temp);
    let (send_queue, stats_rx, wait_group) = start_workers(&parameters);

    let include_filters: Vec<String> = match matches.values_of("filters") {
        Some(values) => Ok(values.map(|s| s.to_owned()).collect()),
        None => Err(ErrorKind::InvalidUsage),
    }?;

    let mut builder = GlobSetBuilder::new();
    for filter in include_filters.iter() {
        let glob = GlobBuilder::new(filter)
            .case_insensitive(!case_sensitive)
            .literal_separator(true)
            .build().map_err(|_| ErrorKind::InvalidIncludeFilter)?;
        builder.add(glob);
    }
    let globset = builder.build().map_err(|_| ErrorKind::InvalidIncludeFilter)?;

    //convert filters to paths and deal out conversion jobs

    dispatch_jobs(send_queue, include_filters, globset/*, exclude_filters*/)?;

    //wait for all jobs to finish
    wait_group.wait();

    //merge statistics from all threads
    let mut stats = Statistics::new();
    while let Ok(thread_stats) = stats_rx.recv() {
        stats.merge(&thread_stats);
    }

    println!("{}", stats);

    Ok(())
}

type ThreadParam = std::path::PathBuf;

fn start_workers<'a>(params: &Arc<Parameters>) -> (chan::Sender<ThreadParam>, mpsc::Receiver<Statistics>, chan::WaitGroup) {
    let (tx, rx) = chan::sync::<ThreadParam>(params.threads);
    let (stats_tx, stats_rx) = std::sync::mpsc::channel::<Statistics>();
    let wg = chan::WaitGroup::new();

    for _ in 0..params.threads {
        let local_params = params.clone();
        let local_rx = rx.clone();
        let local_stats_tx = stats_tx.clone();
        let local_wg = wg.clone();
        wg.add(1);
        std::thread::spawn(move || {
            worker_thread(local_params, local_stats_tx, local_rx);
            local_wg.done();
        });
    }

    (tx, stats_rx, wg)
}

fn yield_file<F>(path: PathBuf, globset: &GlobSet, callback: &F) -> Result<()>
    where F: Fn(PathBuf) -> Result<()>
{
    if is_hidden(&path)? {
        //we are ignoring .files and .directories
        //we may add a command-line switch to control this behavior in the future
        return Ok(());
    }

    if path.is_dir() {
        for child in path.read_dir()? {
            let child_path = child?.path();
            yield_file(child_path, globset, callback)?;
        }
    }
    else {
        //I'm presuming the binary search in is_blacklisted is faster
        //than globset.is_match, but we should benchmark it at some point
        if !is_blacklisted(&path)? && globset.is_match(&path) {
            callback(path)?;
        }
    }

    Ok(())
}

fn dispatch_jobs(send_queue: chan::Sender<ThreadParam>, filters: Vec<String>, globset: GlobSet/*, exclude_filters: Vec<String>*/) -> Result<()> {
    let paths = extract_paths(&filters)?;
    for path in paths {
        yield_file(path, &globset, &|path: PathBuf| {
            send_queue.send(path);
            Ok(())
        })?
    }

    Ok(())
}

fn worker_thread(params: Arc<Parameters>, stats_tx: mpsc::Sender<Statistics>, rx: chan::Receiver<ThreadParam>) {
    let mut local_stats = Statistics::new();

    loop {
        let src = match rx.recv() {
            Some(task) => task,
            None => break, //no more tasks
        };

        //in a nested function so we can handle errors centrally
        fn compress_single(src: &ThreadParam, params: &Parameters, mut local_stats: &mut Statistics) -> Result<()> {
            let dst_path = format!("{}.{}",
                                   src.to_str().ok_or(ErrorKind::InvalidCharactersInPath)?,
                                   params.extension);
            let dst = Path::new(&dst_path);

            //again, in a scope for error handling
            |local_stats: &mut Statistics| -> Result<()> {
                    println!("{}", src.to_string_lossy());
                    let src_metadata = std::fs::metadata(src)?;

                    //don't compress files that are already compressed that haven't changed
                    if let Ok(dst_metadata) = std::fs::metadata(dst) {
                        //the destination already exists
                        let src_seconds = src_metadata.modified()?.duration_since(std::time::UNIX_EPOCH)?.as_secs();
                        let dst_seconds = dst_metadata.modified()?.duration_since(std::time::UNIX_EPOCH)?.as_secs();
                        match src_seconds == dst_seconds {
                            true => {
                                local_stats.update(src_metadata.len(), dst_metadata.len(), false);
                                return Ok(());//no need to recompress
                            },
                            false => {
                                std::fs::remove_file(dst)?; //throw if we can't
                            }
                        };
                    }
                    params.compressor.compress(src.as_path(), dst)?;
                    let dst_metadata = std::fs::metadata(dst)?;
                    local_stats.update(src_metadata.len(), dst_metadata.len(), true);
                    let src_modified = filetime::FileTime::from_last_modification_time(&src_metadata);
                    filetime::set_file_times(dst, filetime::FileTime::zero(), src_modified).unwrap_or_default();

                    Ok(())
                }(&mut local_stats)
                .map_err(|e| {
                    //try deleting the invalid destination file, but don't care if we can't
                    std::fs::remove_file(dst).unwrap_or_default();
                    e //return the same error
                })
        }

        if let Err(e) = compress_single(&src, &params, &mut local_stats) {
            errstln!("Error compressing {}: {}", src.to_string_lossy(), e);
        }
    }

    if !stats_tx.send(local_stats).is_ok() {
        errstln!("Error compiling statistics!");
    }
}

fn str_search(sorted: &[&str], search_term: &str, case_sensitive: bool) -> std::result::Result<usize, usize> {
    let term = match case_sensitive {
        true => search_term.to_owned(),
        false => search_term.to_lowercase(),
    };

    sorted.binary_search_by(|probe| probe.cmp(&&*term))
}

fn is_hidden(path: &Path) -> Result<bool> {
    let hidden = match path.file_name() {
        Some(x) => x.to_str().ok_or(ErrorKind::InvalidCharactersInPath)?
            .starts_with("."),
        None => false
    };
    Ok(hidden)
}

fn is_blacklisted(path: &Path) -> Result<bool> {

    let r = match path.extension() {
        Some(x) => {
            let ext = x.to_str().ok_or(ErrorKind::InvalidCharactersInPath)?;
            str_search(COMP_EXTS, &ext, false).is_ok()
        },
        None => false,
    };

    return Ok(r);
}

//Given a list of filters, extracts the directories that should be searched
//To-Do: Also provide info about to what depth they should be recursed
use std::collections::HashSet;
fn extract_paths(filters: &Vec<String>) -> Result<HashSet<PathBuf>> {
    use std::iter::FromIterator;

    let mut dirs = std::collections::HashSet::<PathBuf>::new();

    {
        let insert_path = &mut |filter: &String, dir: PathBuf| {
            if DEBUG_FILTERS {
                println!("filter {} mapped to ./", filter);
            }
            dirs.insert(dir);
        };

        for filter in filters {
            //take everything until the first expression
            let mut last_char = None::<char>;
            let dir;
            {
                let partial = filter.chars().take_while(|c| match c {
                    &'?' | &'*' | &'{' | &'[' => false,
                    c => { last_char = Some(c.clone()); true }
                });
                dir = String::from_iter(partial);
            }

            let dir = match dir.chars().next() {
                Some(c) => match c {
                    '.' | '/' => PathBuf::from(dir),
                    _ => {
                        let mut pb = PathBuf::from("./");
                        pb.push(dir);
                        pb
                    }
                },
                None => {
                    insert_path(filter, PathBuf::from("./"));
                    continue;
                }
            };

            if dir.to_str().ok_or(ErrorKind::InvalidCharactersInPath)?.ends_with(filter) {
                //the "dir" is actually a full path to a single file
                //return it as-is
                insert_path(filter, dir);
                continue;
            }

            if last_char == Some('/') {
                //dir is a already a directory, return it as-is
                insert_path(filter, dir);
                continue;
            }

            //we need to extract the directory from the path we have
            let dir = match PathBuf::from(dir).parent() {
                Some(parent) => parent.to_path_buf(),
                None => PathBuf::from("./"),
            };

            insert_path(filter, dir);
        }
    }

    if DEBUG_FILTERS {
        println!("final dirs: {:?}", dirs);
    }

    Ok(dirs)
}
<commit_msg>Fixed matching against un-prefixed paths<commit_after>#[macro_use] extern crate error_chain;
#[macro_use] extern crate prettytable;
#[macro_use] extern crate stderr;
extern crate chan;
extern crate clap;
extern crate filetime;
extern crate globset;
extern crate pretty_bytes;
extern crate separator;

#[macro_use] mod errors;
mod compression;
mod lists;
mod structs;

use clap::{App, Arg};
use errors::*;
use globset::{GlobBuilder, GlobSet, GlobSetBuilder};
use lists::*;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::sync::mpsc;
use structs::*;

const DEBUG_FILTERS: bool = cfg!(debug_assertions);
fn debug(message: &str) {
    if DEBUG_FILTERS {
        errstln!("{}", message);
    }
}

quick_main!(run);

fn run() -> Result<()> {
    let matches = App::new("static-compress")
        .version("0.1")
        .about("Create statically-compresed copies of matching files")
        .author("NeoSmart Technologies")
        .arg(Arg::with_name("compressor")
            .short("c")
            .long("compressor")
            .value_name("[brotli|gzip|zopfli]")
            .help("The compressor to use (default: gzip)")
            .takes_value(true))
        .arg(Arg::with_name("threads")
            .short("j")
            .long("threads")
            .value_name("COUNT")
            .help("The number of simultaneous compressions (default: 1)")
            .takes_value(true))
        .arg(Arg::with_name("filters")
            .value_name("FILTER")
            .multiple(true)
            .required(true))
        .arg(Arg::with_name("ext")
            .short("e")
            .value_name("EXT")
            .long("extension")
            .help("The extension to use for compressed files (default: gz or br)"))
        /*.arg(Arg::with_name("excludes")
            .short("x")
            .value_name("FILTER")
            .long("exclude")
            .multiple(true)
            .help("Exclude files matching this glob expression"))*/
        .get_matches();

    fn get_parameter<'a, T>(matches: &clap::ArgMatches, name: &str, default_value: T) -> Result<T>
        where T: std::str::FromStr
    {
        match matches.value_of(name) {
            Some(v) => {
                Ok(v.parse().map_err(|_| ErrorKind::InvalidParameterValue(name.to_owned()))?)
            }
            None => Ok(default_value),
        }
    }

    let case_sensitive = !matches.is_present("nocase");
    let compressor = get_parameter(&matches, "compressor", CompressionAlgorithm::GZip)?;
    let temp = Parameters {
        extension: matches.value_of("ext")
            .unwrap_or(compressor.extension())
            .trim_matches(|c: char| c.is_whitespace() || c.is_control() || c == '.')
            .to_owned(),
        compressor: compressor,
        threads: get_parameter(&matches, "threads", 1)?,
    };

    /*let exclude_filters = match matches.values_of("exclude") {
        Some(values)=> values.map(|s| s.to_owned()).collect(),
        None => Vec::<String>::new(),
    };*/

    let parameters = Arc::<Parameters>::new(temp);
    let (send_queue, stats_rx, wait_group) = start_workers(&parameters);

    let mut include_filters: Vec<String> = match matches.values_of("filters") {
        Some(values) => Ok(values.map(|s| s.to_owned()).collect()),
        None => Err(ErrorKind::InvalidUsage),
    }?;

    let mut builder = GlobSetBuilder::new();
    fix_filters(&mut include_filters);
    for filter in include_filters.iter() {
        let glob = GlobBuilder::new(filter)
            .case_insensitive(!case_sensitive)
            .literal_separator(true)
            .build().map_err(|_| ErrorKind::InvalidIncludeFilter)?;
        builder.add(glob);
    }
    let globset = builder.build().map_err(|_| ErrorKind::InvalidIncludeFilter)?;

    //convert filters to paths and deal out conversion jobs

    dispatch_jobs(send_queue, include_filters, globset/*, exclude_filters*/)?;

    //wait for all jobs to finish
    wait_group.wait();

    //merge statistics from all threads
    let mut stats = Statistics::new();
    while let Ok(thread_stats) = stats_rx.recv() {
        stats.merge(&thread_stats);
    }

    println!("{}", stats);

    Ok(())
}

type ThreadParam = std::path::PathBuf;

fn start_workers<'a>(params: &Arc<Parameters>) -> (chan::Sender<ThreadParam>, mpsc::Receiver<Statistics>, chan::WaitGroup) {
    let (tx, rx) = chan::sync::<ThreadParam>(params.threads);
    let (stats_tx, stats_rx) = std::sync::mpsc::channel::<Statistics>();
    let wg = chan::WaitGroup::new();

    for _ in 0..params.threads {
        let local_params = params.clone();
        let local_rx = rx.clone();
        let local_stats_tx = stats_tx.clone();
        let local_wg = wg.clone();
        wg.add(1);
        std::thread::spawn(move || {
            worker_thread(local_params, local_stats_tx, local_rx);
            local_wg.done();
        });
    }

    (tx, stats_rx, wg)
}

fn yield_file<F>(path: PathBuf, globset: &GlobSet, callback: &F) -> Result<()>
    where F: Fn(PathBuf) -> Result<()>
{
    if is_hidden(&path)? {
        //we are ignoring .files and .directories
        //we may add a command-line switch to control this behavior in the future
        return Ok(());
    }

    if path.is_dir() {
        for child in path.read_dir()? {
            let child_path = child?.path();
            yield_file(child_path, globset, callback)?;
        }
    }
    else {
        //I'm presuming the binary search in is_blacklisted is faster
        //than globset.is_match, but we should benchmark it at some point
        if !is_blacklisted(&path)? && globset.is_match(&path) {
            callback(path)?;
        }
    }

    Ok(())
}

fn dispatch_jobs(send_queue: chan::Sender<ThreadParam>, filters: Vec<String>, globset: GlobSet/*, exclude_filters: Vec<String>*/) -> Result<()> {
    let paths = extract_paths(&filters)?;
    for path in paths {
        yield_file(path, &globset, &|path: PathBuf| {
            send_queue.send(path);
            Ok(())
        })?
    }

    Ok(())
}

fn worker_thread(params: Arc<Parameters>, stats_tx: mpsc::Sender<Statistics>, rx: chan::Receiver<ThreadParam>) {
    let mut local_stats = Statistics::new();

    loop {
        let src = match rx.recv() {
            Some(task) => task,
            None => break, //no more tasks
        };

        //in a nested function so we can handle errors centrally
        fn compress_single(src: &ThreadParam, params: &Parameters, mut local_stats: &mut Statistics) -> Result<()> {
            let dst_path = format!("{}.{}",
                                   src.to_str().ok_or(ErrorKind::InvalidCharactersInPath)?,
                                   params.extension);
            let dst = Path::new(&dst_path);

            //again, in a scope for error handling
            |local_stats: &mut Statistics| -> Result<()> {
                    println!("{}", src.to_string_lossy());
                    let src_metadata = std::fs::metadata(src)?;

                    //don't compress files that are already compressed that haven't changed
                    if let Ok(dst_metadata) = std::fs::metadata(dst) {
                        //the destination already exists
                        let src_seconds = src_metadata.modified()?.duration_since(std::time::UNIX_EPOCH)?.as_secs();
                        let dst_seconds = dst_metadata.modified()?.duration_since(std::time::UNIX_EPOCH)?.as_secs();
                        match src_seconds == dst_seconds {
                            true => {
                                local_stats.update(src_metadata.len(), dst_metadata.len(), false);
                                return Ok(());//no need to recompress
                            },
                            false => {
                                std::fs::remove_file(dst)?; //throw if we can't
                            }
                        };
                    }
                    params.compressor.compress(src.as_path(), dst)?;
                    let dst_metadata = std::fs::metadata(dst)?;
                    local_stats.update(src_metadata.len(), dst_metadata.len(), true);
                    let src_modified = filetime::FileTime::from_last_modification_time(&src_metadata);
                    filetime::set_file_times(dst, filetime::FileTime::zero(), src_modified).unwrap_or_default();

                    Ok(())
                }(&mut local_stats)
                .map_err(|e| {
                    //try deleting the invalid destination file, but don't care if we can't
                    std::fs::remove_file(dst).unwrap_or_default();
                    e //return the same error
                })
        }

        if let Err(e) = compress_single(&src, &params, &mut local_stats) {
            errstln!("Error compressing {}: {}", src.to_string_lossy(), e);
        }
    }

    if !stats_tx.send(local_stats).is_ok() {
        errstln!("Error compiling statistics!");
    }
}

fn str_search(sorted: &[&str], search_term: &str, case_sensitive: bool) -> std::result::Result<usize, usize> {
    let term = match case_sensitive {
        true => search_term.to_owned(),
        false => search_term.to_lowercase(),
    };

    sorted.binary_search_by(|probe| probe.cmp(&&*term))
}

fn is_hidden(path: &Path) -> Result<bool> {
    let hidden = match path.file_name() {
        Some(x) => x.to_str().ok_or(ErrorKind::InvalidCharactersInPath)?
            .starts_with("."),
        None => false
    };
    Ok(hidden)
}

fn is_blacklisted(path: &Path) -> Result<bool> {

    let r = match path.extension() {
        Some(x) => {
            let ext = x.to_str().ok_or(ErrorKind::InvalidCharactersInPath)?;
            str_search(COMP_EXTS, &ext, false).is_ok()
        },
        None => false,
    };

    return Ok(r);
}

//pre-pends ./ to relative paths
fn fix_filters(mut filters: &mut Vec<String>) {
    for i in 0..filters.len() {
        let new_path;
        {
            let ref path = filters[i];
            match path.chars().next().expect("Received blank filter!") {
                '.' | '/' => continue,
                _ => new_path = format!("./{}", path) //un-prefixed path
            }
        }
        filters[i] = new_path;
    }
}

//Given a list of filters, extracts the directories that should be searched
//To-Do: Also provide info about to what depth they should be recursed
use std::collections::HashSet;
fn extract_paths(filters: &Vec<String>) -> Result<HashSet<PathBuf>> {
    use std::iter::FromIterator;

    let mut dirs = std::collections::HashSet::<PathBuf>::new();

    {
        let insert_path = &mut |filter: &String, dir: PathBuf| {
            debug(&format!("filter {} mapped to search {}", filter, dir.display()));
            dirs.insert(dir);
        };

        for filter in filters {
            //take everything until the first expression
            let mut last_char = None::<char>;
            let dir;
            {
                let partial = filter.chars().take_while(|c| match c {
                    &'?' | &'*' | &'{' | &'[' => false,
                    c => { last_char = Some(c.clone()); true }
                });
                dir = String::from_iter(partial);
            }

            let dir = match dir.chars().next() {
                Some(c) => match c {
                    '.' | '/' => PathBuf::from(dir),
                    _ => {
                        let mut pb = PathBuf::from("./");
                        pb.push(dir);
                        pb
                    }
                },
                None => {
                    insert_path(filter, PathBuf::from("./"));
                    continue;
                }
            };

            if dir.to_str().ok_or(ErrorKind::InvalidCharactersInPath)?.ends_with(filter) {
                //the "dir" is actually a full path to a single file
                //return it as-is
                insert_path(filter, dir);
                continue;
            }

            if last_char == Some('/') {
                //dir is a already a directory, return it as-is
                insert_path(filter, dir);
                continue;
            }

            //we need to extract the directory from the path we have
            let dir = match PathBuf::from(dir).parent() {
                Some(parent) => parent.to_path_buf(),
                None => PathBuf::from("./"),
            };

            insert_path(filter, dir);
        }
    }

    debug(&format!("final search paths: {:?}", dirs));

    Ok(dirs)
}
<|endoftext|>


<commit_before>//! A simple evolutionary algorithm written in Rust.

extern crate rand;

use rand::Rng;
use std::collections::HashMap;

fn main() {
    let target = "METHINKS IT IS LIKE A WEASEL".to_string();
    println!("{}", target);

    let mut parent = String::new();
    generate_first_sentence(&mut parent);

    println!("{}", parent);

    let nb_copy = 400;
    let mutation_rate = 0.05;
    let mut counter = 0;

    while fitness(&target, &parent) != 0 {
        counter += 1;

        let mut sentences = HashMap::new();
        let mut f_min = 30;

        for _ in 0..nb_copy {
            let sentence = mutate(&mut parent, mutation_rate);
            let f = fitness(&target, &sentence);

            sentences.insert(f, sentence);

            if f < f_min {
                f_min = f
            }
        }

        if fitness(&target, &parent) > f_min {
            match sentences.get(&f_min) {
                Some(s) => {
                    parent = s.clone();
                    println!("{} : {}", parent, counter);
                }
                None => println!("Error, fitness minimum but no sentence."),
            }
        }
    }
}

fn fitness(target: &String, sentence: &String) -> u32 {
    let mut fitness = 0;

    for (c1, c2) in target.chars().zip(sentence.chars()) {
        if c1 != c2 {
            fitness += 1
        };
    }

    fitness
}

fn mutate(sentence: &mut String, mutation_rate: f64) -> String {
    let mut rng = rand::thread_rng();
    let mut mutation = String::new();

    for c in sentence.chars() {
        match mutation_rate > rng.gen_range(0f64, 1f64) {
            false => mutation.push(c),               // no mutation
            true => mutation.push(random_char()),   // mutation
        }
    }
    mutation
}

fn generate_first_sentence(parent: &mut String) {
    for _ in 0..28 {
        parent.push(random_char());
    }
}

fn random_char() -> char {
    match rand::thread_rng().gen_range('A' as u8, '\\' as u8) as char {
        '[' => ' ',
        c => c,
    }
}
<commit_msg>remove another unneeded type annotation<commit_after>//! A simple evolutionary algorithm written in Rust.

extern crate rand;

use rand::Rng;
use std::collections::HashMap;

fn main() {
    let target = "METHINKS IT IS LIKE A WEASEL".to_string();
    println!("{}", target);

    let mut parent = String::new();
    generate_first_sentence(&mut parent);

    println!("{}", parent);

    let nb_copy = 400;
    let mutation_rate = 0.05;
    let mut counter = 0;

    while fitness(&target, &parent) != 0 {
        counter += 1;

        let mut sentences = HashMap::new();
        let mut f_min = 30;

        for _ in 0..nb_copy {
            let sentence = mutate(&mut parent, mutation_rate);
            let f = fitness(&target, &sentence);

            sentences.insert(f, sentence);

            if f < f_min {
                f_min = f
            }
        }

        if fitness(&target, &parent) > f_min {
            match sentences.get(&f_min) {
                Some(s) => {
                    parent = s.clone();
                    println!("{} : {}", parent, counter);
                }
                None => println!("Error, fitness minimum but no sentence."),
            }
        }
    }
}

fn fitness(target: &String, sentence: &String) -> u32 {
    let mut fitness = 0;

    for (c1, c2) in target.chars().zip(sentence.chars()) {
        if c1 != c2 {
            fitness += 1
        };
    }

    fitness
}

fn mutate(sentence: &mut String, mutation_rate: f64) -> String {
    let mut rng = rand::thread_rng();
    let mut mutation = String::new();

    for c in sentence.chars() {
        match mutation_rate > rng.gen_range(0.0, 1.0) {
            false => mutation.push(c),               // no mutation
            true => mutation.push(random_char()),   // mutation
        }
    }
    mutation
}

fn generate_first_sentence(parent: &mut String) {
    for _ in 0..28 {
        parent.push(random_char());
    }
}

fn random_char() -> char {
    match rand::thread_rng().gen_range('A' as u8, '\\' as u8) as char {
        '[' => ' ',
        c => c,
    }
}
<|endoftext|>


<commit_before>#![feature(core, io)]
use std::fs;
use std::io;
use std::io::{Read, Write};
use std::path::Path;

const MEMSIZE: usize = 4096;

enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

#[derive(Debug)]
enum Op {
    Add(u8),
    Mov(usize),
    In,
    Out,
    Loop(OpStream)
}

use Op::*;

#[derive(Debug)]
struct OpStream {
    ops: Vec<Op>
}

impl OpStream {
    fn add(&mut self, op: Op) {
        self.ops.push(op);
    }

    fn optimize(&mut self) {
        let mut i = 0;
        while i < self.ops.len() {
            match &self.ops[i..] {
                [Add(a), Add(b), ..] => {
                    self.ops[i] = Add(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Mov(a), Mov(b), ..] => {
                    self.ops[i] = Mov(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Add(0), ..] | [Mov(0), ..] => {
                    self.ops.remove(i);
                }
                _ => i += 1
            }
        }
        for op in &mut self.ops[..] {
            if let &mut Loop(ref mut stream) = op {
                stream.optimize();
            }
        }
    }

    fn get(&self) -> &[Op] {
        &self.ops[..]
    }

    fn new() -> OpStream {
        OpStream { ops: Vec::new() }
    }
}

struct State {
    index: usize,
    memory: [u8; MEMSIZE]
}

impl State {
    fn new() -> State {
        State { index: 0, memory: [0; MEMSIZE] }
    }

    fn peek(&self) -> u8 {
        self.memory[self.index % MEMSIZE]
    }

    fn poke(&mut self, value: u8) {
        self.memory[self.index % MEMSIZE] = value;
    }

    fn step(&mut self, op: &Op) {
        match op {
            &Add(i) => {
                // XXX: Ugly expression due to lexical scoping of borrow,
                //      cf. https://github.com/rust-lang/rust/issues/6393
                let x = self.peek();
                self.poke(x.wrapping_add(i));
            }
            &Mov(n) => {
                self.index = self.index.wrapping_add(n);
            }
            &In => {
                let mut c = vec![0u8];
                io::stdin().read(&mut c).unwrap();
                self.poke(c[0]);
            }
            &Out => {
                io::stdout().write(&vec![self.peek()]).unwrap();
            }
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    self.run(ops.get());
                }
            }
        }
    }

    fn run(&mut self, ops: &[Op]) {
        for op in ops {
            self.step(op);
        }
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in &filenames[1..] {
        match reader(&Path::new(filename)) {
            Ok(reader) => {
                let mut chars = reader.chars().peekable();

                let mut opstream = OpStream::new();
                loop {
                    match parse(&mut chars) {
                        Something(op) => opstream.add(op),
                        EOF => break,
                        _ => {}
                    }
                }

                opstream.optimize();

                State::new().run(opstream.get());
            }
            Err(e) => {
                writeln!(&mut io::stderr(), "Error while processing {}: {}", filename, e).unwrap();
            }
        }
    }
}

fn parse<T: io::Read>(mut chars: &mut std::iter::Peekable<io::Chars<T>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(1)),
            '-' => Something(Add(-1)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut childstream = OpStream::new();
                while chars.peek() != Some(&Ok(']')) {
                    match parse(&mut chars) {
                        Something(op) => childstream.add(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(childstream))
            },
            _ => Nothing  // other characters
        },
        _ => EOF  // XXX: really?
    }
}

fn reader(path: &Path) -> Result<io::BufReader<fs::File>, io::Error> {
    Ok(io::BufReader::new(try!(fs::File::open(path))))
}

#[cfg(test)]
mod tests {
    use super::{State, OpStream};
    use super::Op::*;

    #[test]
    fn state_peek() {
        let mut state = State::new();
        state.memory[state.index] = 23;
        assert_eq!(23, state.peek());
        state.index = 5;
        state.memory[state.index] = 42;
        assert_eq!(42, state.peek());
    }

    #[test]
    fn state_poke() {
        let mut state = State::new();
        state.poke(23);
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state.poke(42);
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn state_step_add() {
        let mut state = State::new();
        state.step(&Add(23));
        assert_eq!(23, state.peek());
        state.step(&Add(42));
        assert_eq!(65, state.peek());
        state.step(&Add(-66));
        assert_eq!(-1, state.peek());
    }

    #[test]
    fn state_step_mov() {
        let mut state = State::new();
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn state_step_loop() {
        let mut state = State::new();
        state.poke(23);
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state.peek());
    }
}
<commit_msg>fix: handle EOF from stdin<commit_after>#![feature(core, io)]
use std::fs;
use std::io;
use std::io::{Read, Write};
use std::path::Path;

const MEMSIZE: usize = 4096;

enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

#[derive(Debug)]
enum Op {
    Add(u8),
    Mov(usize),
    In,
    Out,
    Loop(OpStream)
}

use Op::*;

#[derive(Debug)]
struct OpStream {
    ops: Vec<Op>
}

impl OpStream {
    fn add(&mut self, op: Op) {
        self.ops.push(op);
    }

    fn optimize(&mut self) {
        let mut i = 0;
        while i < self.ops.len() {
            match &self.ops[i..] {
                [Add(a), Add(b), ..] => {
                    self.ops[i] = Add(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Mov(a), Mov(b), ..] => {
                    self.ops[i] = Mov(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Add(0), ..] | [Mov(0), ..] => {
                    self.ops.remove(i);
                }
                _ => i += 1
            }
        }
        for op in &mut self.ops[..] {
            if let &mut Loop(ref mut stream) = op {
                stream.optimize();
            }
        }
    }

    fn get(&self) -> &[Op] {
        &self.ops[..]
    }

    fn new() -> OpStream {
        OpStream { ops: Vec::new() }
    }
}

struct State {
    index: usize,
    memory: [u8; MEMSIZE]
}

impl State {
    fn new() -> State {
        State { index: 0, memory: [0; MEMSIZE] }
    }

    fn peek(&self) -> u8 {
        self.memory[self.index % MEMSIZE]
    }

    fn poke(&mut self, value: u8) {
        self.memory[self.index % MEMSIZE] = value;
    }

    fn step(&mut self, op: &Op) -> bool {
        match op {
            &Add(i) => {
                // XXX: Ugly expression due to lexical scoping of borrow,
                //      cf. https://github.com/rust-lang/rust/issues/6393
                let x = self.peek();
                self.poke(x.wrapping_add(i));
            }
            &Mov(n) => {
                self.index = self.index.wrapping_add(n);
            }
            &In => {
                let mut c = vec![0u8];
                if io::stdin().read(&mut c).unwrap() == 0 {
                    return false;
                }
                self.poke(c[0]);
            }
            &Out => {
                io::stdout().write(&vec![self.peek()]).unwrap();
            }
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    if !self.run(ops.get()) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    fn run(&mut self, ops: &[Op]) -> bool {
        for op in ops {
            if !self.step(op) {
                return false;
            }
        }
        return true;
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in &filenames[1..] {
        match reader(&Path::new(filename)) {
            Ok(reader) => {
                let mut chars = reader.chars().peekable();

                let mut opstream = OpStream::new();
                loop {
                    match parse(&mut chars) {
                        Something(op) => opstream.add(op),
                        EOF => break,
                        _ => {}
                    }
                }

                opstream.optimize();

                State::new().run(opstream.get());
            }
            Err(e) => {
                writeln!(&mut io::stderr(), "Error while processing {}: {}", filename, e).unwrap();
            }
        }
    }
}

fn parse<T: io::Read>(mut chars: &mut std::iter::Peekable<io::Chars<T>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(1)),
            '-' => Something(Add(-1)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut childstream = OpStream::new();
                while chars.peek() != Some(&Ok(']')) {
                    match parse(&mut chars) {
                        Something(op) => childstream.add(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(childstream))
            },
            _ => Nothing  // other characters
        },
        _ => EOF  // XXX: really?
    }
}

fn reader(path: &Path) -> Result<io::BufReader<fs::File>, io::Error> {
    Ok(io::BufReader::new(try!(fs::File::open(path))))
}

#[cfg(test)]
mod tests {
    use super::{State, OpStream};
    use super::Op::*;

    #[test]
    fn state_peek() {
        let mut state = State::new();
        state.memory[state.index] = 23;
        assert_eq!(23, state.peek());
        state.index = 5;
        state.memory[state.index] = 42;
        assert_eq!(42, state.peek());
    }

    #[test]
    fn state_poke() {
        let mut state = State::new();
        state.poke(23);
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state.poke(42);
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn state_step_add() {
        let mut state = State::new();
        state.step(&Add(23));
        assert_eq!(23, state.peek());
        state.step(&Add(42));
        assert_eq!(65, state.peek());
        state.step(&Add(-66));
        assert_eq!(-1, state.peek());
    }

    #[test]
    fn state_step_mov() {
        let mut state = State::new();
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn state_step_loop() {
        let mut state = State::new();
        state.poke(23);
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state.peek());
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(regex_macros)]

extern crate rustc_serialize;
extern crate websocket;
extern crate hyper;
extern crate image;
extern crate qrcode;
extern crate regex;

pub mod blockchain_info;
pub mod payment_detection;
pub mod server;
pub mod qr;

use std::env;
use std::process;

use hyper::server::Server;

use server::{routes};

fn main() {
	if env::args().count() != 2 {
		println!("Usage: cr-payment-bitcoin <ip-address> <port>");
		process::exit(1);
	}

	let mut ip = env::args().nth(1).unwrap();
	ip.push_str(":");
	ip.push_str(&*env::args().nth(2).unwrap());

	let server = Server::http(&*ip).unwrap();
	let _guard = server.handle(routes);

	println!("Listening on http://{}", ip);
}
<commit_msg>minor refactoring<commit_after>#![feature(plugin)]
#![plugin(regex_macros)]

extern crate rustc_serialize;
extern crate websocket;
extern crate hyper;
extern crate image;
extern crate qrcode;
extern crate regex;

pub mod blockchain_info;
pub mod payment_detection;
pub mod server;
pub mod qr;

use std::env;
use std::process;

use hyper::server::Server;

use server::routes;

fn main() {
	if env::args().count() != 2 {
		println!("Usage: cr-payment-bitcoin <ip-address> <port>");
		process::exit(1);
	}

	let mut sock_addr = env::args().nth(1).unwrap();
	sock_addr.push_str(":");
	sock_addr.push_str(&*env::args().nth(2).unwrap());

	let server = Server::http(&*sock_addr).unwrap();
	let _guard = server.handle(routes);

	println!("Listening on http://{}", sock_addr);
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate docopt;

extern crate hyper;

use docopt::Docopt;
use rustc_serialize::{Decodable, Decoder};

use std::env;
use std::path::PathBuf;
use std::error::Error;
use std::io;
use std::io::prelude::*;
use std::fs::File;
use rustc_serialize::json;

use hyper::Client;
use hyper::header::{Authorization, Bearer};

// TODO: This is only temporary...
const TOKEN: &'static str = "";

const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");
const USAGE: &'static str = "
Banking for the command line.

Usage:
    teller list accounts
    teller show balance <account>
    teller -h | --help
    teller -V | --version

Commands:
    list accounts   List accounts.
    show balance    Show the balance of an account.

Options:
    -h --help       Show this screen.
    -V --version    Show version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_list: bool,
    cmd_accounts: bool,
    cmd_show: bool,
    cmd_balance: bool,
    arg_account: AccountType,
    flag_help: bool,
    flag_version: bool,
}

#[derive(Debug)]
enum AccountType { Current, Savings, Business, Unknown(String), None }

impl Decodable for AccountType {
    fn decode<D: Decoder>(d: &mut D) -> Result<AccountType, D::Error> {
        let s = try!(d.read_str());
        Ok(match &*s {
            "" => AccountType::None,
            "current" => AccountType::Current,
            "savings" => AccountType::Savings,
            "business" => AccountType::Business,
            s => AccountType::Unknown(s.to_string()),
        })
    }
}

#[derive(RustcEncodable, RustcDecodable)]
struct Config {
    auth_token: String,
}

impl Config {
    pub fn new(auth_token: String) -> Config {
        Config {
            auth_token: auth_token,
        }
    }
}

#[derive(Debug, RustcDecodable)]
struct AccountResponse {
    data: Account,
}

#[derive(Debug, RustcDecodable)]
struct AccountsResponse {
    data: Vec<Account>,
}

#[derive(Debug, RustcDecodable)]
struct Account {
    updated_at: String,
    institution: String,
    id: String,
    currency: String,
    balance: String,
    account_number_last_4: String,
}
// TODO: Maybe will need to deserialize with this:
// http://valve.github.io/blog/2014/08/26/json-serialization-in-rust-part-2/

// TODO: Work out when to use matching
//       and when to use try! and when to
//       use something else.

#[derive(Debug)]
enum ConfigError {
    IoError(io::Error),
    JsonParseError(rustc_serialize::json::DecoderError),
    JsonStringifyError(rustc_serialize::json::EncoderError),
}

impl std::fmt::Display for ConfigError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.description().fmt(f)
    }
}

impl From<io::Error> for ConfigError {
    fn from(e: io::Error) -> ConfigError {
        ConfigError::IoError(e)
    }
}

impl From<rustc_serialize::json::DecoderError> for ConfigError {
    fn from(e: rustc_serialize::json::DecoderError) -> ConfigError {
        ConfigError::JsonParseError(e)
    }
}

impl From<rustc_serialize::json::EncoderError> for ConfigError {
    fn from(e: rustc_serialize::json::EncoderError) -> ConfigError {
        ConfigError::JsonStringifyError(e)
    }
}

impl std::error::Error for ConfigError {
    fn description(&self) -> &str {
        match *self {
            ConfigError::IoError(_) => "I/O Error",
            ConfigError::JsonParseError(_) => "JSON parsing error",
            ConfigError::JsonStringifyError(_) => "JSON stringify error",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            ConfigError::IoError(ref err) => Some(err as &std::error::Error),
            ConfigError::JsonParseError(ref err) => Some(err as &std::error::Error),
            ConfigError::JsonStringifyError(ref err) => Some(err as &std::error::Error),
        }
    }
}

fn get_config_path() -> PathBuf {
    let fallback_config_path = PathBuf::from("./.tellerrc");
    let append_config_file = |mut p: PathBuf| {
        p.push(".tellerrc");
        p
    };
    env::home_dir().map_or(fallback_config_path, append_config_file)
}

fn get_config_file() -> Result<File, io::Error> {
    let config_path = get_config_path();
    File::open(&config_path)
}

fn get_config_file_to_write() -> Result<File, io::Error> {
    let config_path = get_config_path();
    File::create(&config_path)
}

fn read_config() -> Result<Config, ConfigError> {
    let mut config_file = try!(get_config_file());

    let mut content_str = String::new();
    try!(config_file.read_to_string(&mut content_str));

    let config: Config = try!(json::decode(&content_str));

    Ok(config)
}

fn write_config(config: &Config) -> Result<(), ConfigError> {
    let mut config_file = try!(get_config_file_to_write());

    let content_str = try!(json::encode(&config));

    try!(config_file.write_all(content_str.as_bytes()));

    Ok(())
}

// TODO: Turns out you've been polluting the namespace really really badly
//       and you're gonna need to fix that!
#[derive(Debug)]
enum ApiServiceError {
    HttpClientError(hyper::error::Error),
    IoError(io::Error),
    JsonParseError(rustc_serialize::json::DecoderError),
}

impl std::fmt::Display for ApiServiceError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.description().fmt(f)
    }
}

impl From<hyper::error::Error> for ApiServiceError {
    fn from(e: hyper::error::Error) -> ApiServiceError {
        ApiServiceError::HttpClientError(e)
    }
}

impl From<io::Error> for ApiServiceError {
    fn from(e: io::Error) -> ApiServiceError {
        ApiServiceError::IoError(e)
    }
}

impl From<rustc_serialize::json::DecoderError> for ApiServiceError {
    fn from(e: rustc_serialize::json::DecoderError) -> ApiServiceError {
        ApiServiceError::JsonParseError(e)
    }
}

impl std::error::Error for ApiServiceError {
    fn description(&self) -> &str {
        match *self {
            ApiServiceError::HttpClientError(_) => "Api Error",
            ApiServiceError::IoError(_) => "I/O Error",
            ApiServiceError::JsonParseError(_) => "JSON parsing error",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            ApiServiceError::HttpClientError(ref err) => Some(err as &std::error::Error),
            ApiServiceError::IoError(ref err) => Some(err as &std::error::Error),
            ApiServiceError::JsonParseError(ref err) => Some(err as &std::error::Error),
        }
    }
}

type ApiServiceResult<T> = Result<T, ApiServiceError>;

fn get_accounts() -> ApiServiceResult<AccountsResponse> {
    let client = Client::new();

    let auth_header = Authorization(
        Bearer {
            token: TOKEN.to_owned()
        }
    );

    let mut res = try!(client.get("https://api.teller.io/accounts")
                             .header(auth_header)
                             .send()
                             .and_then(|r| {
                                 if r.status.is_client_error() {
                                     Err(hyper::error::Error::Status)
                                 } else {
                                     Ok(r)
                                 }
                             }));

    let mut body = String::new();
    try!(res.read_to_string(&mut body));

    println!("Response: {}", body);
    let accounts_response = try!(json::decode(&body));

    Ok(accounts_response)
}

#[allow(dead_code)]
fn get_account() -> ApiServiceResult<AccountResponse> {
    let client = Client::new();

    let auth_header = Authorization(
        Bearer {
            token: TOKEN.to_owned()
        }
    );

    let mut res = try!(client.get("https://api.teller.io/accounts/4803f712-cc3e-4560-9f80-3be8116d7723")
                             .header(auth_header)
                             .send()
                             .and_then(|r| {
                                if r.status.is_client_error() {
                                    Err(hyper::error::Error::Status)
                                } else {
                                    Ok(r)
                                }
                            }));

    let mut body = String::new();
    try!(res.read_to_string(&mut body));

    println!("Response: {}", body);
    let account_response = try!(json::decode(&body));

    Ok(account_response)
}

#[allow(dead_code)]
fn get_account_balance() -> ApiServiceResult<String> {
    get_account().map(|r| r.data.balance)
}

fn main() {
    // TODO: Currently this gets data but it will panic! if no JSON comes back, for example if we
    //       get a 500 server error. (There is no `error` property bizarrely.)
    match get_accounts() {
        Ok(_) => println!("dont print value "),
        Err(why) => println!("error: {}", std::error::Error::description(&why)),
    }

    // get_account_balance();

    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| {
                                d.version(VERSION.map(|v| v.to_string()))
                                 .decode()
                            })
                            .unwrap_or_else(|e| e.exit());
    println!("{:?}", args);

    // TODO: If there is a config file then read it,
    //       otherwise ask a question and write to it.
    let config = match read_config() {
        Ok(config) => config,
        Err(why) => panic!("config could not be read"),
    };
    println!("{}", config.auth_token);

    println!("What's the auth token?");
    let mut input = String::new();
    match io::stdin().read_line(&mut input) {
        Ok(_) => println!("{}", input),
        Err(error) => println!("error: {}", error),
    };

    let auth_token = String::new();
    let new_config = Config::new(auth_token);

    println!("fake token: {}", new_config.auth_token);

    let _ = write_config(&new_config);

    ()
}
<commit_msg>refactor(error): cause/description call underlying cause/description; AuthenticationError exists<commit_after>extern crate rustc_serialize;
extern crate docopt;

extern crate hyper;

// TODO: Turns out you've been polluting the namespace really really badly
//       and you're gonna need to fix that!

use docopt::Docopt;
use rustc_serialize::{Decodable, Decoder};

use std::env;
use std::path::PathBuf;
use std::error::Error;
use std::io;
use std::io::prelude::*;
use std::fs::File;
use rustc_serialize::json;

use hyper::Client;
use hyper::header::{Authorization, Bearer};

// TODO: This is only temporary...
const TOKEN: &'static str = "";

const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");
const USAGE: &'static str = "
Banking for the command line.

Usage:
    teller list accounts
    teller show balance <account>
    teller -h | --help
    teller -V | --version

Commands:
    list accounts   List accounts.
    show balance    Show the balance of an account.

Options:
    -h --help       Show this screen.
    -V --version    Show version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_list: bool,
    cmd_accounts: bool,
    cmd_show: bool,
    cmd_balance: bool,
    arg_account: AccountType,
    flag_help: bool,
    flag_version: bool,
}

#[derive(Debug)]
enum AccountType { Current, Savings, Business, Unknown(String), None }

impl Decodable for AccountType {
    fn decode<D: Decoder>(d: &mut D) -> Result<AccountType, D::Error> {
        let s = try!(d.read_str());
        Ok(match &*s {
            "" => AccountType::None,
            "current" => AccountType::Current,
            "savings" => AccountType::Savings,
            "business" => AccountType::Business,
            s => AccountType::Unknown(s.to_string()),
        })
    }
}

#[derive(RustcEncodable, RustcDecodable)]
struct Config {
    auth_token: String,
}

impl Config {
    pub fn new(auth_token: String) -> Config {
        Config {
            auth_token: auth_token,
        }
    }
}

#[derive(Debug, RustcDecodable)]
struct AccountResponse {
    data: Account,
}

#[derive(Debug, RustcDecodable)]
struct AccountsResponse {
    data: Vec<Account>,
}

#[derive(Debug, RustcDecodable)]
struct Account {
    updated_at: String,
    institution: String,
    id: String,
    currency: String,
    balance: String,
    account_number_last_4: String,
}

#[derive(Debug)]
enum ConfigError {
    IoError(io::Error),
    JsonParseError(rustc_serialize::json::DecoderError),
    JsonStringifyError(rustc_serialize::json::EncoderError),
}

impl std::fmt::Display for ConfigError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.description().fmt(f)
    }
}

impl From<io::Error> for ConfigError {
    fn from(e: io::Error) -> ConfigError {
        ConfigError::IoError(e)
    }
}

impl From<rustc_serialize::json::DecoderError> for ConfigError {
    fn from(e: rustc_serialize::json::DecoderError) -> ConfigError {
        ConfigError::JsonParseError(e)
    }
}

impl From<rustc_serialize::json::EncoderError> for ConfigError {
    fn from(e: rustc_serialize::json::EncoderError) -> ConfigError {
        ConfigError::JsonStringifyError(e)
    }
}

impl std::error::Error for ConfigError {
    fn description(&self) -> &str {
        match *self {
            ConfigError::IoError(ref err) => err.description(),
            ConfigError::JsonParseError(ref err) => err.description(),
            ConfigError::JsonStringifyError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            ConfigError::IoError(ref err) => err.cause(),
            ConfigError::JsonParseError(ref err) => err.cause(),
            ConfigError::JsonStringifyError(ref err) => err.cause(),
        }
    }
}

// TODO: Technically this should probably be passed into the
//       functions that require it.
fn get_config_path() -> PathBuf {
    let fallback_config_path = PathBuf::from("./.tellerrc");
    let append_config_file = |mut p: PathBuf| {
        p.push(".tellerrc");
        p
    };
    env::home_dir().map_or(fallback_config_path, append_config_file)
}

fn get_config_file() -> Result<File, io::Error> {
    let config_path = get_config_path();
    File::open(&config_path)
}

fn get_config_file_to_write() -> Result<File, io::Error> {
    let config_path = get_config_path();
    File::create(&config_path)
}

fn read_config() -> Result<Config, ConfigError> {
    let mut config_file = try!(get_config_file());

    let mut content_str = String::new();
    try!(config_file.read_to_string(&mut content_str));

    let config: Config = try!(json::decode(&content_str));

    Ok(config)
}

fn write_config(config: &Config) -> Result<(), ConfigError> {
    let mut config_file = try!(get_config_file_to_write());

    let content_str = try!(json::encode(&config));

    try!(config_file.write_all(content_str.as_bytes()));

    Ok(())
}

#[derive(Debug)]
enum ApiServiceError {
    AuthenticationError,
    HttpClientError(hyper::error::Error),
    IoError(io::Error),
    JsonParseError(rustc_serialize::json::DecoderError),
}

impl std::fmt::Display for ApiServiceError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.description().fmt(f)
    }
}

impl From<hyper::error::Error> for ApiServiceError {
    fn from(e: hyper::error::Error) -> ApiServiceError {
        ApiServiceError::HttpClientError(e)
    }
}

impl From<io::Error> for ApiServiceError {
    fn from(e: io::Error) -> ApiServiceError {
        ApiServiceError::IoError(e)
    }
}

impl From<rustc_serialize::json::DecoderError> for ApiServiceError {
    fn from(e: rustc_serialize::json::DecoderError) -> ApiServiceError {
        ApiServiceError::JsonParseError(e)
    }
}

impl std::error::Error for ApiServiceError {
    fn description(&self) -> &str {
        match *self {
            ApiServiceError::AuthenticationError => "Could not authenticate",
            ApiServiceError::HttpClientError(ref err) => err.description(),
            ApiServiceError::IoError(ref err) => err.description(),
            ApiServiceError::JsonParseError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            ApiServiceError::HttpClientError(ref err) => err.cause(),
            ApiServiceError::IoError(ref err) => err.cause(),
            ApiServiceError::JsonParseError(ref err) => err.cause(),
            _ => None,
        }
    }
}

type ApiServiceResult<T> = Result<T, ApiServiceError>;

fn get_accounts() -> ApiServiceResult<AccountsResponse> {
    let client = Client::new();

    let auth_header = Authorization(
        Bearer {
            token: TOKEN.to_owned()
        }
    );

    let mut res = try!(
        client.get("https://api.teller.io/accounts")
              .header(auth_header)
              .send()
    );
    if res.status.is_client_error() {
        return Err(ApiServiceError::AuthenticationError);
    }

    let mut body = String::new();
    try!(res.read_to_string(&mut body));

    println!("Response: {}", body);
    let accounts_response = try!(json::decode(&body));

    Ok(accounts_response)
}

#[allow(dead_code)]
fn get_account() -> ApiServiceResult<AccountResponse> {
    let client = Client::new();

    let auth_header = Authorization(
        Bearer {
            token: TOKEN.to_owned()
        }
    );

    let mut res = try!(
        client.get("https://api.teller.io/accounts/4803f712-cc3e-4560-9f80-3be8116d7723")
              .header(auth_header)
              .send()
    );
    if res.status.is_client_error() {
        return Err(ApiServiceError::AuthenticationError);
    }

    let mut body = String::new();
    try!(res.read_to_string(&mut body));

    println!("Response: {}", body);
    let account_response = try!(json::decode(&body));

    Ok(account_response)
}

#[allow(dead_code)]
fn get_account_balance() -> ApiServiceResult<String> {
    get_account().map(|r| r.data.balance)
}

fn main() {
    // TODO: Currently this gets data but it will panic! if no JSON comes back, for example if we
    //       get a 500 server error. (There is no `error` property bizarrely.)
    match get_accounts() {
        Ok(_) => println!("dont print value "),
        Err(why) => println!("error: {}", why),
    }

    // get_account_balance();

    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| {
                                d.version(VERSION.map(|v| v.to_string()))
                                 .decode()
                            })
                            .unwrap_or_else(|e| e.exit());
    println!("{:?}", args);

    // TODO: If there is a config file then read it,
    //       otherwise ask a question and write to it.
    let config = match read_config() {
        Ok(config) => config,
        Err(why) => panic!(why),
    };
    println!("{}", config.auth_token);

    println!("What's the auth token?");
    let mut input = String::new();
    match io::stdin().read_line(&mut input) {
        Ok(_) => println!("{}", input),
        Err(error) => println!("error: {}", error),
    };

    let auth_token = String::new();
    let new_config = Config::new(auth_token);

    println!("fake token: {}", new_config.auth_token);

    let _ = write_config(&new_config);

    ()
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

extern crate curl;
extern crate git;
extern crate serialize;
extern crate time;

use git::Result as GitResult;
use std::default::Default;
use std::io::IoResult;
use std::os::args;

use description::Description;

mod description;

fn main() {
    macro_rules! ok(
        ($result:expr) => (
            if let Err(e) = $result {
                error(e);
                std::os::set_exit_status(1);
                return;
            }
        );
    )

    let args = args();

    if args.len() != 3 {
        usage();
        return;
    }

    let (command, path) = (args[1].clone(), Path::new(args[2].clone()));

    match command.as_slice() {
        "status" => ok!(status(&mut std::io::stdio::stdout(), &path)),
        "push" => ok!(push(&path)),
        _ => usage(),
    }
}

fn error<T: std::fmt::Show>(e: T) {
    println!("{}", e);
}

fn usage() {
    println!("Usage: {} (status|push) <path>", args()[0]);
}

fn status<T: Writer>(writer: &mut T, path: &Path) -> IoResult<()> {
    use std::io::MemWriter;
    use std::io::{IoError, OtherIoError};

    macro_rules! display(
        ($writer:expr, $title:expr, $paths:expr) => {
            if !$paths.is_empty() {
                try!(display($writer, $title, &$paths));
            }
        };
    )

    let (new, updated, removed) = match summarize(path) {
        Ok(result) => result,
        Err(error) => return Err(IoError {
            kind: OtherIoError,
            desc: "cannot check the status of the repository",
            detail: Some(error.to_string()),
        }),
    };

    let mut buffer = MemWriter::new();

    display!(&mut buffer, "New", new);
    display!(&mut buffer, "Updated", updated);
    display!(&mut buffer, "Deleted", removed);

    let data = buffer.into_inner();

    if data.len() > 0 {
        try!(writeln!(writer, "### {}", timestamp()));
        try!(writeln!(writer, ""));
        try!(writer.write(data.as_slice()));
    }

    Ok(())
}

fn push(path: &Path) -> GitResult<()> {
    let mut git = try!(git::open(path));

    if try!(git.status()).len() > 0 {
        try!(git.add_all());
        try!(git.commit("Synchronized with the official repository"));
    }

    try!(git.push());

    Ok(())
}

fn summarize(dir: &Path) -> GitResult<(Vec<Path>, Vec<Path>, Vec<Path>)> {
    use git::status::{Flag, Flags};

    macro_rules! equal(
        ($one:expr, $two:expr) => ($one.dir_path() == $two.dir_path());
    )

    macro_rules! find(
        ($vector:expr, $element:expr) => (
            $vector.iter().find(|p| equal!(p, $element))
        );
    )

    const NEW: Flags = Flags(Flag::IndexNew as u32 | Flag::WorkDirNew as u32);
    const UPDATED: Flags = Flags(Flag::IndexModified as u32 | Flag::WorkDirModified as u32);
    const REMOVED: Flags = Flags(Flag::IndexDeleted as u32 | Flag::WorkDirDeleted as u32);

    let repo = try!(git::Repository::open(dir));
    let list = try!(repo.status(&Default::default()));

    let mut new = vec![];
    let mut updated = vec![];
    let mut removed = vec![];

    fn push(vector: &mut Vec<Path>, path: &Path) {
        if find!(vector, path).is_none() {
            vector.push(path.clone());
        }
    }

    for entry in list.iter() {
        let status = entry.status();
        let path = dir.join(entry.new_path());

        if status.has_any(NEW) {
            push(&mut new, &path);
        } else if status.has_any(UPDATED) {
            push(&mut updated, &path);
        } else if status.has_any(REMOVED) {
            push(&mut removed, &path);
        }
    }

    let new = new.into_iter().filter(|path| {
        if find!(removed, path).is_some() {
            push(&mut updated, path);
            false
        } else {
            true
        }
    }).collect::<Vec<_>>();

    let removed = removed.into_iter().filter(|path| {
        (find!(updated, path).is_none())
    }).collect::<Vec<_>>();

    Ok((new, updated, removed))
}

fn display<T: Writer>(writer: &mut T, title: &str, paths: &Vec<Path>) -> IoResult<()> {
    let lines = paths.iter().by_ref()
                     .map(|path| format(path))
                     .filter(|line| line.is_some())
                     .map(|line| line.unwrap())
                     .collect::<Vec<_>>();

    let len = lines.len();
    if len == 0 {
        return Ok(());
    }

    try!(writeln!(writer, "{}:", title));
    try!(writeln!(writer, ""));
    for (i, line) in lines.iter().enumerate() {
        if i + 1 == len {
            try!(writeln!(writer, "* {}.", line));
        } else if i + 2 == len {
            if len == 2 {
                try!(writeln!(writer, "* {} and", line));
            } else {
                try!(writeln!(writer, "* {}, and", line));
            }
        } else {
            try!(writeln!(writer, " * {},", line));
        }
    }
    try!(writeln!(writer, ""));

    Ok(())
}

fn format(path: &Path) -> Option<String> {
    let mut line = String::new();

    let desc = Description::load(path);

    match desc.name {
        Some(ref name) => line.push_str(name.as_slice()),
        None => return None,
    }

    match desc.url {
        Some(ref url) => {
            line.insert(0, '[');
            line.push_str("](");
            line.push_str(url.as_slice());
            line.push_str(")");
        },
        None => {},
    }

    match desc.designer {
        Some(ref designer) => {
            line.push_str(" by ");
            line.push_str(designer.as_slice());
        },
        None => {},
    }

    Some(line)
}

fn timestamp() -> String {
    let time = time::now();

    const MONTHS: [&'static str, ..12] = ["January", "February", "March", "April",
                                          "May", "June", "July", "August", "September",
                                          "October", "November", "December"];

    format!("{} {}, {}", MONTHS[time.tm_mon as uint], time.tm_mday, 1900 + time.tm_year)
}
<commit_msg>Fixed a typo<commit_after>#![feature(macro_rules)]

extern crate curl;
extern crate git;
extern crate serialize;
extern crate time;

use git::Result as GitResult;
use std::default::Default;
use std::io::IoResult;
use std::os::args;

use description::Description;

mod description;

fn main() {
    macro_rules! ok(
        ($result:expr) => (
            if let Err(e) = $result {
                error(e);
                std::os::set_exit_status(1);
                return;
            }
        );
    )

    let args = args();

    if args.len() != 3 {
        usage();
        return;
    }

    let (command, path) = (args[1].clone(), Path::new(args[2].clone()));

    match command.as_slice() {
        "status" => ok!(status(&mut std::io::stdio::stdout(), &path)),
        "push" => ok!(push(&path)),
        _ => usage(),
    }
}

fn error<T: std::fmt::Show>(e: T) {
    println!("{}", e);
}

fn usage() {
    println!("Usage: {} (status|push) <path>", args()[0]);
}

fn status<T: Writer>(writer: &mut T, path: &Path) -> IoResult<()> {
    use std::io::MemWriter;
    use std::io::{IoError, OtherIoError};

    macro_rules! display(
        ($writer:expr, $title:expr, $paths:expr) => {
            if !$paths.is_empty() {
                try!(display($writer, $title, &$paths));
            }
        };
    )

    let (new, updated, removed) = match summarize(path) {
        Ok(result) => result,
        Err(error) => return Err(IoError {
            kind: OtherIoError,
            desc: "cannot check the status of the repository",
            detail: Some(error.to_string()),
        }),
    };

    let mut buffer = MemWriter::new();

    display!(&mut buffer, "New", new);
    display!(&mut buffer, "Updated", updated);
    display!(&mut buffer, "Deleted", removed);

    let data = buffer.into_inner();

    if data.len() > 0 {
        try!(writeln!(writer, "### {}", timestamp()));
        try!(writeln!(writer, ""));
        try!(writer.write(data.as_slice()));
    }

    Ok(())
}

fn push(path: &Path) -> GitResult<()> {
    let mut git = try!(git::open(path));

    if try!(git.status()).len() > 0 {
        try!(git.add_all());
        try!(git.commit("Synchronized with the official repository"));
    }

    try!(git.push());

    Ok(())
}

fn summarize(dir: &Path) -> GitResult<(Vec<Path>, Vec<Path>, Vec<Path>)> {
    use git::status::{Flag, Flags};

    macro_rules! equal(
        ($one:expr, $two:expr) => ($one.dir_path() == $two.dir_path());
    )

    macro_rules! find(
        ($vector:expr, $element:expr) => (
            $vector.iter().find(|p| equal!(p, $element))
        );
    )

    const NEW: Flags = Flags(Flag::IndexNew as u32 | Flag::WorkDirNew as u32);
    const UPDATED: Flags = Flags(Flag::IndexModified as u32 | Flag::WorkDirModified as u32);
    const REMOVED: Flags = Flags(Flag::IndexDeleted as u32 | Flag::WorkDirDeleted as u32);

    let repo = try!(git::Repository::open(dir));
    let list = try!(repo.status(&Default::default()));

    let mut new = vec![];
    let mut updated = vec![];
    let mut removed = vec![];

    fn push(vector: &mut Vec<Path>, path: &Path) {
        if find!(vector, path).is_none() {
            vector.push(path.clone());
        }
    }

    for entry in list.iter() {
        let status = entry.status();
        let path = dir.join(entry.new_path());

        if status.has_any(NEW) {
            push(&mut new, &path);
        } else if status.has_any(UPDATED) {
            push(&mut updated, &path);
        } else if status.has_any(REMOVED) {
            push(&mut removed, &path);
        }
    }

    let new = new.into_iter().filter(|path| {
        if find!(removed, path).is_some() {
            push(&mut updated, path);
            false
        } else {
            true
        }
    }).collect::<Vec<_>>();

    let removed = removed.into_iter().filter(|path| {
        (find!(updated, path).is_none())
    }).collect::<Vec<_>>();

    Ok((new, updated, removed))
}

fn display<T: Writer>(writer: &mut T, title: &str, paths: &Vec<Path>) -> IoResult<()> {
    let lines = paths.iter().by_ref()
                     .map(|path| format(path))
                     .filter(|line| line.is_some())
                     .map(|line| line.unwrap())
                     .collect::<Vec<_>>();

    let len = lines.len();
    if len == 0 {
        return Ok(());
    }

    try!(writeln!(writer, "{}:", title));
    try!(writeln!(writer, ""));
    for (i, line) in lines.iter().enumerate() {
        if i + 1 == len {
            try!(writeln!(writer, "* {}.", line));
        } else if i + 2 == len {
            if len == 2 {
                try!(writeln!(writer, "* {} and", line));
            } else {
                try!(writeln!(writer, "* {}, and", line));
            }
        } else {
            try!(writeln!(writer, "* {},", line));
        }
    }
    try!(writeln!(writer, ""));

    Ok(())
}

fn format(path: &Path) -> Option<String> {
    let mut line = String::new();

    let desc = Description::load(path);

    match desc.name {
        Some(ref name) => line.push_str(name.as_slice()),
        None => return None,
    }

    match desc.url {
        Some(ref url) => {
            line.insert(0, '[');
            line.push_str("](");
            line.push_str(url.as_slice());
            line.push_str(")");
        },
        None => {},
    }

    match desc.designer {
        Some(ref designer) => {
            line.push_str(" by ");
            line.push_str(designer.as_slice());
        },
        None => {},
    }

    Some(line)
}

fn timestamp() -> String {
    let time = time::now();

    const MONTHS: [&'static str, ..12] = ["January", "February", "March", "April",
                                          "May", "June", "July", "August", "September",
                                          "October", "November", "December"];

    format!("{} {}, {}", MONTHS[time.tm_mon as uint], time.tm_mday, 1900 + time.tm_year)
}
<|endoftext|>


<commit_before>#![feature(macro_rules, phase)]

#![allow(non_snake_case)]
#![allow(dead_code)]

extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate serialize;

extern crate csv;
extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

use std::io;
use std::os;

macro_rules! ctry(
    ($e:expr) => (
        match $e {
            Ok(e) => e,
            Err(e) => return Err(::types::CliError::from_str(e)),
        }
    )
)

macro_rules! csv_reader(
    ($args:expr) => ({
        let d = ::csv::Decoder::from_reader($args.arg_input)
                               .separator($args.flag_delimiter.to_byte());
        if $args.flag_no_headers { d.no_headers() } else { d }
    })
)

macro_rules! csv_write_headers(
    ($args:expr, $rdr:expr, $wtr:expr) => (
        if !$args.flag_no_headers {
            ctry!($wtr.record_bytes(ctry!($rdr.headers_bytes()).move_iter()));
        }
    )
)

docopt!(Args, "
Usage:
    xcsv <command> [<args>...]
    xcsv [options]

Options:
    -h, --help    Display this message
    --version     Print version info and exit

Commands:
    count    Count records
    fmt      Format CSV output (change field delimiter)
    select   Select columns from CSV
", arg_command: Command)

fn main() {
    let mut conf = util::arg_config();
    conf.options_first = true;
    let args: Args = docopt::FlagParser::parse_conf(conf)
                                        .unwrap_or_else(|e| e.exit());
    let result = match args.arg_command {
        Count => count::main(),
        Fmt => fmt::main(),
        Select => select::main(),
    };
    match result {
        Ok(()) => os::set_exit_status(0),
        Err(types::ErrOther(msg)) => {
            os::set_exit_status(1);
            let _ = write!(io::stderr(), "{}\n", msg);
        }
        Err(types::ErrFlag(err)) => err.exit(),
    }
}

#[deriving(Decodable, Show)]
enum Command {
    Count,
    Fmt,
    Select,
}

mod types;
mod util;

mod count;
mod fmt;
mod select;
<commit_msg>simplify main<commit_after>#![feature(macro_rules, phase)]

#![allow(non_snake_case)]
#![allow(dead_code)]

extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate serialize;

extern crate csv;
extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

use std::io;
use std::os;

macro_rules! ctry(
    ($e:expr) => (
        match $e {
            Ok(e) => e,
            Err(e) => return Err(::types::CliError::from_str(e)),
        }
    )
)

macro_rules! csv_reader(
    ($args:expr) => ({
        let d = ::csv::Decoder::from_reader($args.arg_input)
                               .separator($args.flag_delimiter.to_byte());
        if $args.flag_no_headers { d.no_headers() } else { d }
    })
)

macro_rules! csv_write_headers(
    ($args:expr, $rdr:expr, $wtr:expr) => (
        if !$args.flag_no_headers {
            ctry!($wtr.record_bytes(ctry!($rdr.headers_bytes()).move_iter()));
        }
    )
)

docopt!(Args, "
Usage:
    xcsv <command> [<args>...]
    xcsv [options]

Options:
    -h, --help    Display this message
    --version     Print version info and exit

Commands:
    count    Count records
    fmt      Format CSV output (change field delimiter)
    select   Select columns from CSV
", arg_command: Command)

fn main() {
    let mut conf = util::arg_config();
    conf.options_first = true;
    let args: Args = docopt::FlagParser::parse_conf(conf)
                                        .unwrap_or_else(|e| e.exit());
    match args.arg_command.run() {
        Ok(()) => os::set_exit_status(0),
        Err(types::ErrOther(msg)) => {
            os::set_exit_status(1);
            let _ = write!(io::stderr(), "{}\n", msg);
        }
        Err(types::ErrFlag(err)) => err.exit(),
    }
}

#[deriving(Decodable, Show)]
enum Command {
    Count,
    Fmt,
    Select,
}

impl Command {
    fn run(self) -> Result<(), types::CliError> {
        match self {
            Count => count::main(),
            Fmt => fmt::main(),
            Select => select::main(),
        }
    }
}

mod types;
mod util;

mod count;
mod fmt;
mod select;
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017  Sebastian Wiesner <swiesner@lunaryorn.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#![deny(warnings)]

#[macro_use]
extern crate clap;
extern crate atty;
extern crate rand;
extern crate ansi_term;

use ansi_term::Colour;
use ansi_term::Style;
use clap::{AppSettings, Arg};

static EFF_WORDLIST: &'static str = include_str!(concat!(env!("OUT_DIR"), "/eff_wordlist.txt"));
static LICENSE: &'static str = {
    "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law."
};

fn builtin_words() -> Vec<&'static str> {
    EFF_WORDLIST.lines().collect()
}

arg_enum! {
    enum YesNoAuto {
        Yes,
        No,
        Auto
    }
}

fn alternating_styles(colour_setting: YesNoAuto) -> (Style, Style) {
    let enable_colours = match colour_setting {
        YesNoAuto::Auto => atty::is(atty::Stream::Stdout),
        YesNoAuto::Yes => true,
        YesNoAuto::No => false,
    };
    if enable_colours {
        (Style::new().fg(Colour::Cyan), Style::new().fg(Colour::Purple))
    } else {
        (Style::new(), Style::new())
    }
}

fn main() {
    let parse_result = app_from_crate!()
        .after_help(format!("Copyright (C) 2017 Sebastian Wiesner <swiesner@lunaryorn.com>\n\n{}",
                            LICENSE)
                            .as_str())
        .version_message("Print version information")
        .help_message("Print this message")
        .arg(Arg::with_name("colour")
                 .alias("color")
                 .long("colour")
                 .possible_values(&["yes", "no", "auto"])
                 .default_value("auto")
                 .help("Whether to enable or disable coloured output."))
        .arg(Arg::with_name("number")
                 .short("n")
                 .long("number")
                 .default_value("5")
                 .help("The number of passwords to generate at once"))
        .arg(Arg::with_name("length")
                 .short("l")
                 .long("length")
                 .default_value("4")
                 .help("The number of words in each password"))
        .arg(Arg::with_name("words").long("words").help("Print the internal wordlist and exit"))
        .settings(&[AppSettings::ColoredHelp,
                    AppSettings::DontCollapseArgsInUsage,
                    // Don't put flags and options in separate --help groups
                    AppSettings::UnifiedHelpMessage])
        .get_matches_safe();

    match parse_result {
        Ok(matches) => {
            if matches.is_present("words") {
                for word in builtin_words() {
                    println!("{}", word);
                }
            } else {
                let words = builtin_words();
                let password_length = value_t_or_exit!(matches.value_of("length"), usize);
                let number_of_passwords = value_t_or_exit!(matches.value_of("number"), usize);
                let (even, odd) =
                    alternating_styles(value_t_or_exit!(matches, "colour", YesNoAuto));
                for lineno in 0..number_of_passwords {
                    let style = if lineno % 2 == 0 { even } else { odd };
                    let words = rand::sample(&mut rand::thread_rng(),
                                             words.iter().map(|s| *s),
                                             password_length);
                    println!("{}", style.paint(words.join(" ")));
                }
            }
        }
        Err(error @ clap::Error { kind: clap::ErrorKind::VersionDisplayed, .. }) => {
            let mut words = builtin_words();
            words.sort_by_key(|w| w.chars().count());
            print!("\n
EFF long wordlist July 2017: {} words (min length {}, max length {})

{}",
                   words.len(),
                   words[0].chars().count(),
                   words.last()
                       .unwrap()
                       .chars()
                       .count(),
                   LICENSE);
            error.exit();
        }
        Err(error) => error.exit(),
    }
}
<commit_msg>Extract app into function<commit_after>/*
 * Copyright (C) 2017  Sebastian Wiesner <swiesner@lunaryorn.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#![deny(warnings)]

#[macro_use]
extern crate clap;
extern crate atty;
extern crate rand;
extern crate ansi_term;

use ansi_term::Colour;
use ansi_term::Style;
use clap::{App, AppSettings, Arg};

static EFF_WORDLIST: &'static str = include_str!(concat!(env!("OUT_DIR"), "/eff_wordlist.txt"));

macro_rules! license {
    () => {
    "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law."
    }
}

fn builtin_words() -> Vec<&'static str> {
    EFF_WORDLIST.lines().collect()
}

arg_enum! {
    enum YesNoAuto {
        Yes,
        No,
        Auto
    }
}

fn alternating_styles(colour_setting: YesNoAuto) -> (Style, Style) {
    let enable_colours = match colour_setting {
        YesNoAuto::Auto => atty::is(atty::Stream::Stdout),
        YesNoAuto::Yes => true,
        YesNoAuto::No => false,
    };
    if enable_colours {
        (Style::new().fg(Colour::Cyan), Style::new().fg(Colour::Purple))
    } else {
        (Style::new(), Style::new())
    }
}

fn app() -> App<'static, 'static> {
    app_from_crate!()
        .after_help(concat!("Copyright (C) 2017 Sebastian Wiesner <swiesner@lunaryorn.com>\n\n",
                            license!()))
        .version_message("Print version information")
        .help_message("Print this message")
        .arg(Arg::with_name("colour")
                 .alias("color")
                 .long("colour")
                 .possible_values(&["yes", "no", "auto"])
                 .default_value("auto")
                 .help("Whether to enable or disable coloured output."))
        .arg(Arg::with_name("number")
                 .short("n")
                 .long("number")
                 .default_value("5")
                 .help("The number of passwords to generate at once"))
        .arg(Arg::with_name("length")
                 .short("l")
                 .long("length")
                 .default_value("4")
                 .help("The number of words in each password"))
        .arg(Arg::with_name("words").long("words").help("Print the internal wordlist and exit"))
        .settings(&[AppSettings::ColoredHelp,
                    AppSettings::DontCollapseArgsInUsage,
                    // Don't put flags and options in separate --help groups
                    AppSettings::UnifiedHelpMessage])
}

fn main() {
    let parse_result = app().get_matches_safe();

    match parse_result {
        Ok(matches) => {
            if matches.is_present("words") {
                for word in builtin_words() {
                    println!("{}", word);
                }
            } else {
                let words = builtin_words();
                let password_length = value_t_or_exit!(matches.value_of("length"), usize);
                let number_of_passwords = value_t_or_exit!(matches.value_of("number"), usize);
                let (even, odd) =
                    alternating_styles(value_t_or_exit!(matches, "colour", YesNoAuto));
                for lineno in 0..number_of_passwords {
                    let style = if lineno % 2 == 0 { even } else { odd };
                    let words = rand::sample(&mut rand::thread_rng(),
                                             words.iter().map(|s| *s),
                                             password_length);
                    println!("{}", style.paint(words.join(" ")));
                }
            }
        }
        Err(error @ clap::Error { kind: clap::ErrorKind::VersionDisplayed, .. }) => {
            let mut words = builtin_words();
            words.sort_by_key(|w| w.chars().count());
            print!("\n
EFF long wordlist July 2017: {} words (min length {}, max length {})

{}",
                   words.len(),
                   words[0].chars().count(),
                   words.last()
                       .unwrap()
                       .chars()
                       .count(),
                   license!());
            error.exit();
        }
        Err(error) => error.exit(),
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate ladaemon;

#[macro_use(router)]
extern crate router;

use iron::Iron;
use std::env;
use std::io::{self, Write};

/// The `main()` method. Will loop forever to serve HTTP requests.
fn main() {

    // Make sure we get a file name where we can find configuration.
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        io::stderr().write(b"no configuration file specified\n").unwrap();
        return;
    }

    // Read the configuration from the provided file.
    let app = ladaemon::AppConfig::from_json_file(&args[1]);

    // Register all handlers with a router object. TODO: cloning the
    // configuration object is kind of ugly, but is apparently needed with
    // the way the Iron `Handler` trait is defined. Also, it would be cleaner
    // if the handlers could just be a function, instead of single-method
    // impls.
    let router = router!{
        get "/" => ladaemon::WelcomeHandler { app: app.clone() },
        get "/.well-known/openid-configuration" =>
               ladaemon::OIDConfigHandler { app: app.clone() },
        get "/keys.json" => ladaemon::KeysHandler { app: app.clone() },
        post "/auth" => ladaemon::AuthHandler { app: app.clone() },
        get "/confirm" => ladaemon::ConfirmHandler { app: app.clone() },
        get "/callback" => ladaemon::CallbackHandler { app: app.clone() },
    };

    // Iron will take care of stuff from here. It should spin up a number of
    // threads according to the number of cores available. TODO: make the
    // interface on which we listen configurable.
    Iron::new(router).http("0.0.0.0:3333").unwrap();

}
<commit_msg>Order and divide different kinds of endpoints<commit_after>extern crate iron;
extern crate ladaemon;

#[macro_use(router)]
extern crate router;

use iron::Iron;
use std::env;
use std::io::{self, Write};

/// The `main()` method. Will loop forever to serve HTTP requests.
fn main() {

    // Make sure we get a file name where we can find configuration.
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        io::stderr().write(b"no configuration file specified\n").unwrap();
        return;
    }

    // Read the configuration from the provided file.
    let app = ladaemon::AppConfig::from_json_file(&args[1]);

    // Register all handlers with a router object. TODO: cloning the
    // configuration object is kind of ugly, but is apparently needed with
    // the way the Iron `Handler` trait is defined. Also, it would be cleaner
    // if the handlers could just be a function, instead of single-method
    // impls.
    let router = router!{

        // Human-targeted endpoints
        get "/" => ladaemon::WelcomeHandler { app: app.clone() },
        get "/confirm" => ladaemon::ConfirmHandler { app: app.clone() },

        // OpenID Connect provider endpoints
        get "/.well-known/openid-configuration" =>
               ladaemon::OIDConfigHandler { app: app.clone() },
        get "/keys.json" => ladaemon::KeysHandler { app: app.clone() },
        post "/auth" => ladaemon::AuthHandler { app: app.clone() },

        // OpenID Connect relying party endpoints
        get "/callback" => ladaemon::CallbackHandler { app: app.clone() },

    };

    // Iron will take care of stuff from here. It should spin up a number of
    // threads according to the number of cores available. TODO: make the
    // interface on which we listen configurable.
    Iron::new(router).http("0.0.0.0:3333").unwrap();

}
<|endoftext|>


<commit_before>
extern crate unicode_normalization;

mod syntax;
mod scanner;

fn main() {

}

<commit_msg>test scanner on examples<commit_after>
extern crate unicode_normalization;

use std::path::Path;
use std::fs::OpenOptions;
use std::io::BufReader;
use std::io::prelude::*;

mod syntax;
mod scanner;

fn print_tokens(path: &str) {
    let path = Path::new(path);
    let mut file = OpenOptions::new()
        .read(true)
        .open(path)
        .unwrap();

    let mut source = String::new();
    file.read_to_string(&mut source).unwrap();

    let tokens = scanner::scan(&source);

    let sep = std::iter::repeat("=")
        .take(80)
        .collect::<String>();
    println!("{}", sep);
    println!("{}:", path.display());
    println!("{}", sep);
    println!("{:?}", tokens);

}

fn main() {
    print_tokens("examples/gfarr.mch");
    print_tokens("examples/gfarr_i.imp");
}

<|endoftext|>


<commit_before>extern crate sdl2;
extern crate sdl2_image;

mod raytrace;
use sdl2::event::{Event};
use sdl2::keyboard::{Keycode};
use sdl2::rect::{Rect};
use sdl2::surface::{Surface};
use sdl2::rwops::{RWops};
use sdl2_image::{ImageRWops, LoadTexture, INIT_PNG, INIT_JPG};
use std::path::{Path};

fn main() {
    // start sdl2

    let ctx = sdl2::init().unwrap();
    let video_ctx = ctx.video().unwrap();
    let _image_context = sdl2_image::init(INIT_PNG | INIT_JPG).unwrap();
    let mut timer = ctx.timer().unwrap();

    // Create a window

    let mut window = match video_ctx.window("Gaytracer", 400, 400).position_centered()
                                    .opengl().build() {
        Ok(window) => window,
        Err(err)   => panic!("failed to create window: {}", err)
    };

    // Create a rendering context
    let mut renderer = match window.renderer().build() {
        Ok(renderer) => renderer,
        Err(err) => panic!("failed to create renderer: {}", err)
    };

    // Set the drawing color to a light blue.
    let _ = renderer.set_draw_color(sdl2::pixels::Color::RGB(101, 208, 246));

    // Clear the buffer, using the light blue color set above.
    let _ = renderer.clear();

    // Set the drawing color to a darker blue.
    let _ = renderer.set_draw_color(sdl2::pixels::Color::RGB(0, 153, 204));

    // Create centered Rect, draw the outline of the Rect in our dark blue color.
    let border_rect = Rect::new(320-64, 240-64, 128, 128).unwrap().unwrap();
    let _ = renderer.draw_rect(border_rect);

    // Create a smaller centered Rect, filling it in the same dark blue.
    let inner_rect = Rect::new(320-60, 240-60, 120, 120).unwrap().unwrap();
    let _ = renderer.fill_rect(inner_rect);

    // Load image via sdl2-image
    let my_rwops = RWops::from_file(&Path::new("data/circle.png"), "r").unwrap();
    let my_surface = my_rwops.load_png().unwrap();
    let my_texture = renderer.create_texture_from_surface(my_surface).unwrap();

    // Copy texture onto renderer buffer
    let _ = renderer.copy(&my_texture, None, None);

    // Swap our buffer for the present buffer, displaying it.
    let _ = renderer.present();

    {
        // timer.sleep(3000);

        let my_rwops = RWops::from_file(&Path::new("data/circle.png"), "r").unwrap();
        let mut my_surface = my_rwops.load_png().unwrap();
        let width = my_surface.width();
        let height = my_surface.height();
        let circle = [0; 0];
        let circle_blur = [0; 0];
        let mut state = raytrace::RaytraceState::new((width, height), &circle[..], &circle_blur[..]);
        my_surface.with_lock_mut(|data: &mut [u8]| {
            for i in 1..50 {
                state.raytrace(data, i);
            }
        });
        let my_texture = renderer.create_texture_from_surface(my_surface).unwrap();

        // Copy texture onto renderer buffer
        let _ = renderer.copy(&my_texture, None, None);

        // Swap our buffer for the present buffer, displaying it.
        let _ = renderer.present();
    }

    let mut events = ctx.event_pump().unwrap();

    // loop until we receive a QuitEvent or escape key pressed
    'event : loop {
        // poll_event returns the most recent event or NoEvent if nothing has happened
        for event in events.poll_iter() {
            match event {
                Event::Quit{..} => break 'event,
                Event::KeyDown{keycode: Option::Some(Keycode::Escape), ..} =>
                    break 'event,
                _ => continue
            }
        }
    }
}
<commit_msg>load pixel buffers to raytracer function<commit_after>extern crate sdl2;
extern crate sdl2_image;

mod raytrace;
use sdl2::event::{Event};
use sdl2::keyboard::{Keycode};
use sdl2::rect::{Rect};
use sdl2::surface::{Surface};
use sdl2::rwops::{RWops};
use sdl2::pixels::{PixelFormatEnum};
use sdl2_image::{ImageRWops, INIT_PNG, INIT_JPG};
use std::path::{Path};
use sdl2::{SdlResult};

fn png_data(path: &str) -> SdlResult<Vec<u8>> {
    let image_path = Path::new(path);
    let image_rwops = try!(RWops::from_file(&image_path, "r"));
    let mut image_surface = try!(image_rwops.load_png());
    let image_data = image_surface.without_lock_mut().unwrap();
    Ok(image_data.to_vec())
}

fn main() {

    // start sdl2
    let ctx = sdl2::init().unwrap();
    let video_ctx = ctx.video().unwrap();
    let _image_context = sdl2_image::init(INIT_PNG | INIT_JPG).unwrap();
    let mut timer = ctx.timer().unwrap();

    // Create a window
    let mut window = match video_ctx.window("Gaytracer", 400, 400).position_centered()
                                    .opengl().build() {
        Ok(window) => window,
        Err(err)   => panic!("failed to create window: {}", err)
    };

    // Create a rendering context
    let mut renderer = match window.renderer().build() {
        Ok(renderer) => renderer,
        Err(err) => panic!("failed to create renderer: {}", err)
    };

    let image_edge_path = "data/circle.png";
    let image_blur_path = "data/circle_blur.png";

    {
        let my_rwops = RWops::from_file(&Path::new("data/circle.png"), "r").unwrap();
        let mut my_surface = my_rwops.load_png().unwrap();
        let width = my_surface.width();
        let height = my_surface.height();
        let circle = png_data(image_edge_path).unwrap();
        let circle_blur = png_data(image_blur_path).unwrap();
        let mut state = raytrace::RaytraceState::new((width, height), &circle[..], &circle_blur[..]);
        my_surface.with_lock_mut(|data: &mut [u8]| {
            for i in 1..50 {
                state.raytrace(data, i);
            }
        });
        let my_texture = renderer.create_texture_from_surface(my_surface).unwrap();

        // Copy texture onto renderer buffer
        let _ = renderer.copy(&my_texture, None, None);

        // Swap our buffer for the present buffer, displaying it.
        let _ = renderer.present();
    }

    let mut events = ctx.event_pump().unwrap();

    // loop until we receive a QuitEvent or escape key pressed
    'event : loop {
        // poll_event returns the most recent event or NoEvent if nothing has happened
        for event in events.poll_iter() {
            match event {
                Event::Quit{..} => break 'event,
                Event::KeyDown{keycode: Option::Some(Keycode::Escape), ..} =>
                    break 'event,
                _ => continue
            }
        }
    }
}
<|endoftext|>