<commit_before>#![crate_name = "uu_sort"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Yin <mikeyin@mikeyin.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![allow(dead_code)]

extern crate getopts;
extern crate libc;
extern crate semver;

#[macro_use]
extern crate uucore;
#[macro_use]
extern crate itertools;

use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Lines, Read, stdin, stdout, Write};
use std::mem::replace;
use std::path::Path;
use uucore::fs::is_stdin_interactive;
use semver::Version;
use itertools::Itertools; // for Iterator::dedup()

static NAME: &'static str = "sort";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

static DECIMAL_PT: char = '.';
static THOUSANDS_SEP: char = ',';

enum SortMode {
    Numeric,
    HumanNumeric,
    Month,
    Version,
    Default,
}

struct Settings {
    mode: SortMode,
    merge: bool,
    reverse: bool,
    outfile: Option<String>,
    stable: bool,
    unique: bool,
    check: bool,
    compare_fns: Vec<fn(&String, &String) -> Ordering>,
}

impl Default for Settings {
    fn default() -> Settings {
        Settings {
            mode: SortMode::Default,
            merge: false,
            reverse: false,
            outfile: None,
            stable: false,
            unique: false,
            check: false,
            compare_fns: Vec::new(),
        }
    }
}

struct MergeableFile<'a> {
    lines: Lines<BufReader<Box<Read>>>,
    current_line: String,
    settings: &'a Settings,
}

// BinaryHeap depends on `Ord`. Note that we want to pop smallest items
// from the heap first, and BinaryHeap.pop() returns the largest, so we
// trick it into the right order by calling reverse() here.
impl<'a> Ord for MergeableFile<'a> {
    fn cmp(&self, other: &MergeableFile) -> Ordering {
        compare_by(&self.current_line, &other.current_line, &self.settings).reverse()
    }
}

impl<'a> PartialOrd for MergeableFile<'a> {
    fn partial_cmp(&self, other: &MergeableFile) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<'a> PartialEq for MergeableFile<'a> {
    fn eq(&self, other: &MergeableFile) -> bool {
        Ordering::Equal == compare_by(&self.current_line, &other.current_line, &self.settings)
    }
}

impl<'a> Eq for MergeableFile<'a> {}

struct FileMerger<'a> {
    heap: BinaryHeap<MergeableFile<'a>>,
    settings: &'a Settings,
}

impl<'a> FileMerger<'a> {
    fn new(settings: &'a Settings) -> FileMerger<'a> {
        FileMerger {
            heap: BinaryHeap::new(),
            settings: settings,
        }
    }
    fn push_file(&mut self, mut lines: Lines<BufReader<Box<Read>>>){
        match lines.next() {
            Some(Ok(next_line)) => {
                let mergeable_file = MergeableFile {
                    lines: lines,
                    current_line: next_line,
                    settings: &self.settings,
                };
                self.heap.push(mergeable_file);
            }
            _ => {}
        }
    }
}

impl<'a> Iterator for FileMerger<'a> {
    type Item = String;
    fn next(&mut self) -> Option<String> {
        match self.heap.pop() {
            Some(mut current) => {
                match current.lines.next() {
                    Some(Ok(next_line)) => {
                        let ret = replace(&mut current.current_line, next_line);
                        self.heap.push(current);
                        Some(ret)
                    },
                    _ => {
                        // Don't put it back in the heap (it's empty/erroring)
                        // but its first line is still valid.
                        Some(current.current_line)
                    },
                }
            },
            None => None,
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut settings: Settings = Default::default();
    let mut opts = getopts::Options::new();

    opts.optflag("n", "numeric-sort", "compare according to string numerical value");
    opts.optflag("h", "human-numeric-sort", "compare according to human readable sizes, eg 1M > 100k");
    opts.optflag("M", "month-sort", "compare according to month name abbreviation");
    opts.optflag("r", "reverse", "reverse the output");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("", "version", "output version information and exit");
    opts.optflag("m", "merge", "merge already sorted files; do not sort");
    opts.optopt("o", "output", "write output to FILENAME instead of stdout", "FILENAME");
    opts.optflag("s", "stable", "stabilize sort by disabling last-resort comparison");
    opts.optflag("u", "unique", "output only the first of an equal run");
    opts.optflag("V", "version-sort", "Sort by SemVer version number, eg 1.12.2 > 1.1.2");
    opts.optflag("c", "check", "check for sorted input; do not sort");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f)
    };
    if matches.opt_present("help") {
        let msg = format!("{0} {1}

Usage:
 {0} [OPTION]... [FILE]...

Write the sorted concatenation of all FILE(s) to standard output.

Mandatory arguments for long options are mandatory for short options too.

With no FILE, or when FILE is -, read standard input.", NAME, VERSION);
        print!("{}", opts.usage(&msg));
        return 0;
    }

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    settings.mode = if matches.opt_present("numeric-sort") {
        SortMode::Numeric
    } else if matches.opt_present("human-numeric-sort") {
        SortMode::HumanNumeric
    } else if matches.opt_present("month-sort") {
        SortMode::Month
    } else if matches.opt_present("version-sort") {
        SortMode::Version
    } else {
        SortMode::Default
    };

    settings.merge = matches.opt_present("merge");
    settings.reverse = matches.opt_present("reverse");
    settings.outfile = matches.opt_str("output");
    settings.stable = matches.opt_present("stable");
    settings.unique = matches.opt_present("unique");
    settings.check = matches.opt_present("check");

    let mut files = matches.free;
    if files.is_empty() {
        /* if no file, default to stdin */
        files.push("-".to_owned());
    }

    settings.compare_fns.push(match settings.mode {
        SortMode::Numeric => numeric_compare,
        SortMode::HumanNumeric => human_numeric_size_compare,
        SortMode::Month => month_compare,
        SortMode::Version => version_compare,
        SortMode::Default => String::cmp
    });

    if !settings.stable {
        match settings.mode {
            SortMode::Default => {}
            _ => settings.compare_fns.push(String::cmp)
        }
    }

    exec(files, &settings)
}

fn exec(files: Vec<String>, settings: &Settings) -> i32 {
    let mut lines = Vec::new();
    let mut file_merger = FileMerger::new(&settings);

    for path in &files {
        let (reader, _) = match open(path) {
            Some(x) => x,
            None => continue,
        };

        let buf_reader = BufReader::new(reader);

        if settings.merge {
            file_merger.push_file(buf_reader.lines());
        }
        else {
            for line in buf_reader.lines() {
                if let Ok(n) = line {
                        lines.push(n);
                }
                else {
                    break;
                }
            }
        }
    }

    let original_lines = lines.to_vec();

    sort_by(&mut lines, &settings);

    if settings.check {
        for (i, line) in lines.iter().enumerate() {
            if line != &original_lines[i] {
                println!("sort: disorder in line {}", i);
                return 1;
            }
        }
    }
    else if settings.merge {
        if settings.unique {
            print_sorted(file_merger.dedup(), &settings.outfile)
        }
        else {
            print_sorted(file_merger, &settings.outfile)
        }
    }
    else {
        if settings.unique {
            print_sorted(lines.iter().dedup(), &settings.outfile)
        }
        else {
            print_sorted(lines.iter(), &settings.outfile)
        }
    }

    0

}

fn sort_by(lines: &mut Vec<String>, settings: &Settings) {
    lines.sort_by(|a, b| {
        compare_by(a, b, &settings)
    })
}

fn compare_by(a: &String, b: &String, settings: &Settings) -> Ordering {
    for compare_fn in &settings.compare_fns {
        let cmp = compare_fn(a, b);
        if cmp != Ordering::Equal {
            if settings.reverse {
                return cmp.reverse();
            }
            else {
                return cmp;
            }
        }
    }
    return Ordering::Equal;
}

/// Parse the beginning string into an f64, returning -inf instead of NaN on errors.
fn permissive_f64_parse(a: &str) -> f64 {
    // Maybe should be split on non-digit, but then 10e100 won't parse properly.
    // On the flip side, this will give NEG_INFINITY for "1,234", which might be OK
    // because there's no way to handle both CSV and thousands separators without a new flag.
    // GNU sort treats "1,234" as "1" in numeric, so maybe it's fine.
    let sa: &str = a.split_whitespace().next().unwrap();
    match sa.parse::<f64>() {
        Ok(a) => a,
        Err(_) => std::f64::NEG_INFINITY
    }
}

/// Compares two floating point numbers, with errors being assumed to be -inf.
/// Stops coercing at the first whitespace char, so 1e2 will parse as 100 but
/// 1,000 will parse as -inf.
fn numeric_compare(a: &String, b: &String) -> Ordering {
    let fa = permissive_f64_parse(a);
    let fb = permissive_f64_parse(b);
    // f64::cmp isn't implemented because NaN messes with it
    // but we sidestep that with permissive_f64_parse so just fake it
    if fa > fb {
        Ordering::Greater
    }
    else if fa < fb {
        Ordering::Less
    }
    else {
        Ordering::Equal
    }
}

fn human_numeric_convert(a: &String) -> f64 {
    let int_iter = a.chars();
    let suffix_iter = a.chars();
    let int_str: String = int_iter.take_while(|c| c.is_numeric()).collect();
    let suffix = suffix_iter.skip_while(|c| c.is_numeric()).next();
    let int_part = match int_str.parse::<f64>() {
        Ok(i) => i,
        Err(_) => -1f64
    } as f64;
    let suffix: f64 = match suffix.unwrap_or('\0') {
        'K' => 1000f64,
        'M' => 1E6,
        'G' => 1E9,
        'T' => 1E12,
        'P' => 1E15,
        _ => 1f64
    };
    int_part * suffix
}

/// Compare two strings as if they are human readable sizes.
/// AKA 1M > 100k
fn human_numeric_size_compare(a: &String, b: &String) -> Ordering {
    let fa = human_numeric_convert(a);
    let fb = human_numeric_convert(b);
    if fa > fb {
        Ordering::Greater
    }
    else if fa < fb {
        Ordering::Less
    }
    else {
        Ordering::Equal
    }
}

#[derive(Eq, Ord, PartialEq, PartialOrd)]
enum Month {
    Unknown,
    January,
    February,
    March,
    April,
    May,
    June,
    July,
    August,
    September,
    October,
    November,
    December,
}

/// Parse the beginning string into a Month, returning Month::Unknown on errors.
fn month_parse(line: &String) -> Month {
    match line.split_whitespace().next().unwrap().to_uppercase().as_ref() {
        "JAN" => Month::January,
        "FEB" => Month::February,
        "MAR" => Month::March,
        "APR" => Month::April,
        "MAY" => Month::May,
        "JUN" => Month::June,
        "JUL" => Month::July,
        "AUG" => Month::August,
        "SEP" => Month::September,
        "OCT" => Month::October,
        "NOV" => Month::November,
        "DEC" => Month::December,
        _     => Month::Unknown,
    }
}

fn month_compare(a: &String, b: &String) -> Ordering {
    month_parse(a).cmp(&month_parse(b))
}

fn version_compare(a: &String, b: &String) -> Ordering {
    let ver_a = Version::parse(a);
    let ver_b = Version::parse(b);
    if ver_a > ver_b {
        Ordering::Greater
    }
    else if ver_a < ver_b {
        Ordering::Less
    }
    else {
        Ordering::Equal
    }
}

fn print_sorted<S, T: Iterator<Item=S>>(iter: T, outfile: &Option<String>) where S: std::fmt::Display {
    let mut file: Box<Write> = match *outfile {
        Some(ref filename) => {
            match File::create(Path::new(&filename)) {
                Ok(f) => Box::new(BufWriter::new(f)) as Box<Write>,
                Err(e) => {
                    show_error!("sort: {0}: {1}", filename, e.to_string());
                    panic!("Could not open output file");
                },
            }
        },
        None => Box::new(stdout()) as Box<Write>,
    };

    for line in iter {
        let str = format!("{}\n", line);
        match file.write_all(str.as_bytes()) {
            Err(e) => {
                show_error!("sort: {0}", e.to_string());
                panic!("Write failed");
            },
            Ok(_) => (),
        }
    }
}

// from cat.rs
fn open(path: &str) -> Option<(Box<Read>, bool)> {
    if path == "-" {
        let stdin = stdin();
        return Some((Box::new(stdin) as Box<Read>, is_stdin_interactive()));
    }

    match File::open(Path::new(path)) {
        Ok(f) => Some((Box::new(f) as Box<Read>, false)),
        Err(e) => {
            show_error!("sort: {0}: {1}", path, e.to_string());
            None
        },
    }
}
<commit_msg>sort --check refactor to use iterator<commit_after>#![crate_name = "uu_sort"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Yin <mikeyin@mikeyin.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![allow(dead_code)]

extern crate getopts;
extern crate libc;
extern crate semver;

#[macro_use]
extern crate uucore;
#[macro_use]
extern crate itertools;

use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Lines, Read, stdin, stdout, Write};
use std::mem::replace;
use std::path::Path;
use uucore::fs::is_stdin_interactive;
use semver::Version;
use itertools::Itertools; // for Iterator::dedup()

static NAME: &'static str = "sort";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

static DECIMAL_PT: char = '.';
static THOUSANDS_SEP: char = ',';

enum SortMode {
    Numeric,
    HumanNumeric,
    Month,
    Version,
    Default,
}

struct Settings {
    mode: SortMode,
    merge: bool,
    reverse: bool,
    outfile: Option<String>,
    stable: bool,
    unique: bool,
    check: bool,
    compare_fns: Vec<fn(&String, &String) -> Ordering>,
}

impl Default for Settings {
    fn default() -> Settings {
        Settings {
            mode: SortMode::Default,
            merge: false,
            reverse: false,
            outfile: None,
            stable: false,
            unique: false,
            check: false,
            compare_fns: Vec::new(),
        }
    }
}

struct MergeableFile<'a> {
    lines: Lines<BufReader<Box<Read>>>,
    current_line: String,
    settings: &'a Settings,
}

// BinaryHeap depends on `Ord`. Note that we want to pop smallest items
// from the heap first, and BinaryHeap.pop() returns the largest, so we
// trick it into the right order by calling reverse() here.
impl<'a> Ord for MergeableFile<'a> {
    fn cmp(&self, other: &MergeableFile) -> Ordering {
        compare_by(&self.current_line, &other.current_line, &self.settings).reverse()
    }
}

impl<'a> PartialOrd for MergeableFile<'a> {
    fn partial_cmp(&self, other: &MergeableFile) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<'a> PartialEq for MergeableFile<'a> {
    fn eq(&self, other: &MergeableFile) -> bool {
        Ordering::Equal == compare_by(&self.current_line, &other.current_line, &self.settings)
    }
}

impl<'a> Eq for MergeableFile<'a> {}

struct FileMerger<'a> {
    heap: BinaryHeap<MergeableFile<'a>>,
    settings: &'a Settings,
}

impl<'a> FileMerger<'a> {
    fn new(settings: &'a Settings) -> FileMerger<'a> {
        FileMerger {
            heap: BinaryHeap::new(),
            settings: settings,
        }
    }
    fn push_file(&mut self, mut lines: Lines<BufReader<Box<Read>>>){
        match lines.next() {
            Some(Ok(next_line)) => {
                let mergeable_file = MergeableFile {
                    lines: lines,
                    current_line: next_line,
                    settings: &self.settings,
                };
                self.heap.push(mergeable_file);
            }
            _ => {}
        }
    }
}

impl<'a> Iterator for FileMerger<'a> {
    type Item = String;
    fn next(&mut self) -> Option<String> {
        match self.heap.pop() {
            Some(mut current) => {
                match current.lines.next() {
                    Some(Ok(next_line)) => {
                        let ret = replace(&mut current.current_line, next_line);
                        self.heap.push(current);
                        Some(ret)
                    },
                    _ => {
                        // Don't put it back in the heap (it's empty/erroring)
                        // but its first line is still valid.
                        Some(current.current_line)
                    },
                }
            },
            None => None,
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut settings: Settings = Default::default();
    let mut opts = getopts::Options::new();

    opts.optflag("n", "numeric-sort", "compare according to string numerical value");
    opts.optflag("h", "human-numeric-sort", "compare according to human readable sizes, eg 1M > 100k");
    opts.optflag("M", "month-sort", "compare according to month name abbreviation");
    opts.optflag("r", "reverse", "reverse the output");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("", "version", "output version information and exit");
    opts.optflag("m", "merge", "merge already sorted files; do not sort");
    opts.optopt("o", "output", "write output to FILENAME instead of stdout", "FILENAME");
    opts.optflag("s", "stable", "stabilize sort by disabling last-resort comparison");
    opts.optflag("u", "unique", "output only the first of an equal run");
    opts.optflag("V", "version-sort", "Sort by SemVer version number, eg 1.12.2 > 1.1.2");
    opts.optflag("c", "check", "check for sorted input; do not sort");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f)
    };
    if matches.opt_present("help") {
        let msg = format!("{0} {1}

Usage:
 {0} [OPTION]... [FILE]...

Write the sorted concatenation of all FILE(s) to standard output.

Mandatory arguments for long options are mandatory for short options too.

With no FILE, or when FILE is -, read standard input.", NAME, VERSION);
        print!("{}", opts.usage(&msg));
        return 0;
    }

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    settings.mode = if matches.opt_present("numeric-sort") {
        SortMode::Numeric
    } else if matches.opt_present("human-numeric-sort") {
        SortMode::HumanNumeric
    } else if matches.opt_present("month-sort") {
        SortMode::Month
    } else if matches.opt_present("version-sort") {
        SortMode::Version
    } else {
        SortMode::Default
    };

    settings.merge = matches.opt_present("merge");
    settings.reverse = matches.opt_present("reverse");
    settings.outfile = matches.opt_str("output");
    settings.stable = matches.opt_present("stable");
    settings.unique = matches.opt_present("unique");
    settings.check = matches.opt_present("check");

    let mut files = matches.free;
    if files.is_empty() {
        /* if no file, default to stdin */
        files.push("-".to_owned());
    }
    else if settings.check && files.len() != 1 {
        crash!(1, "sort: extra operand `{}' not allowed with -c", files[1])

    }

    settings.compare_fns.push(match settings.mode {
        SortMode::Numeric => numeric_compare,
        SortMode::HumanNumeric => human_numeric_size_compare,
        SortMode::Month => month_compare,
        SortMode::Version => version_compare,
        SortMode::Default => String::cmp
    });

    if !settings.stable {
        match settings.mode {
            SortMode::Default => {}
            _ => settings.compare_fns.push(String::cmp)
        }
    }

    exec(files, &settings)
}

fn exec(files: Vec<String>, settings: &Settings) -> i32 {
    let mut lines = Vec::new();
    let mut file_merger = FileMerger::new(&settings);

    for path in &files {
        let (reader, _) = match open(path) {
            Some(x) => x,
            None => continue,
        };

        let buf_reader = BufReader::new(reader);

        if settings.merge {
            file_merger.push_file(buf_reader.lines());
        }
        else if settings.check {
            return exec_check_file(buf_reader.lines(), &settings)
        }
        else {
            for line in buf_reader.lines() {
                if let Ok(n) = line {
                        lines.push(n);
                }
                else {
                    break;
                }
            }
        }
    }

    sort_by(&mut lines, &settings);

    if settings.merge {
        if settings.unique {
            print_sorted(file_merger.dedup(), &settings.outfile)
        }
        else {
            print_sorted(file_merger, &settings.outfile)
        }
    }
    else {
        if settings.unique {
            print_sorted(lines.iter().dedup(), &settings.outfile)
        }
        else {
            print_sorted(lines.iter(), &settings.outfile)
        }
    }

    0

}

fn exec_check_file(lines: Lines<BufReader<Box<Read>>>, settings: &Settings) -> i32 {
    // errors yields the line before each disorder,
    // plus the last line (quirk of .coalesce())
    let unwrapped_lines = lines.filter_map(|maybe_line| {
        if let Ok(line) = maybe_line {
            Some(line)
        }
        else {
            None
        }
    });
    let mut errors = unwrapped_lines.enumerate().coalesce(
        |(last_i, last_line), (i, line)| {
            if compare_by(&last_line, &line, &settings) == Ordering::Greater {
                Err(((last_i, last_line), (i, line)))
            }
            else {
                Ok((i, line))
            }
    });
    if let Some((first_error_index, _line)) = errors.next() {
        // Check for a second "error", as .coalesce() always returns the last
        // line, no matter what our merging function does.
        if let Some(_last_line_or_next_error) = errors.next() {
            println!("sort: disorder in line {}", first_error_index);
            return 1;
        }
        else {
            // first "error" was actually the last line.
            return 0;
        }
    }
    else {
        // unwrapped_lines was empty. Empty files are defined to be sorted.
        return 0;
    }
}

fn sort_by(lines: &mut Vec<String>, settings: &Settings) {
    lines.sort_by(|a, b| {
        compare_by(a, b, &settings)
    })
}

fn compare_by(a: &String, b: &String, settings: &Settings) -> Ordering {
    for compare_fn in &settings.compare_fns {
        let cmp = compare_fn(a, b);
        if cmp != Ordering::Equal {
            if settings.reverse {
                return cmp.reverse();
            }
            else {
                return cmp;
            }
        }
    }
    return Ordering::Equal;
}

/// Parse the beginning string into an f64, returning -inf instead of NaN on errors.
fn permissive_f64_parse(a: &str) -> f64 {
    // Maybe should be split on non-digit, but then 10e100 won't parse properly.
    // On the flip side, this will give NEG_INFINITY for "1,234", which might be OK
    // because there's no way to handle both CSV and thousands separators without a new flag.
    // GNU sort treats "1,234" as "1" in numeric, so maybe it's fine.
    let sa: &str = a.split_whitespace().next().unwrap();
    match sa.parse::<f64>() {
        Ok(a) => a,
        Err(_) => std::f64::NEG_INFINITY
    }
}

/// Compares two floating point numbers, with errors being assumed to be -inf.
/// Stops coercing at the first whitespace char, so 1e2 will parse as 100 but
/// 1,000 will parse as -inf.
fn numeric_compare(a: &String, b: &String) -> Ordering {
    let fa = permissive_f64_parse(a);
    let fb = permissive_f64_parse(b);
    // f64::cmp isn't implemented because NaN messes with it
    // but we sidestep that with permissive_f64_parse so just fake it
    if fa > fb {
        Ordering::Greater
    }
    else if fa < fb {
        Ordering::Less
    }
    else {
        Ordering::Equal
    }
}

fn human_numeric_convert(a: &String) -> f64 {
    let int_iter = a.chars();
    let suffix_iter = a.chars();
    let int_str: String = int_iter.take_while(|c| c.is_numeric()).collect();
    let suffix = suffix_iter.skip_while(|c| c.is_numeric()).next();
    let int_part = match int_str.parse::<f64>() {
        Ok(i) => i,
        Err(_) => -1f64
    } as f64;
    let suffix: f64 = match suffix.unwrap_or('\0') {
        'K' => 1000f64,
        'M' => 1E6,
        'G' => 1E9,
        'T' => 1E12,
        'P' => 1E15,
        _ => 1f64
    };
    int_part * suffix
}

/// Compare two strings as if they are human readable sizes.
/// AKA 1M > 100k
fn human_numeric_size_compare(a: &String, b: &String) -> Ordering {
    let fa = human_numeric_convert(a);
    let fb = human_numeric_convert(b);
    if fa > fb {
        Ordering::Greater
    }
    else if fa < fb {
        Ordering::Less
    }
    else {
        Ordering::Equal
    }
}

#[derive(Eq, Ord, PartialEq, PartialOrd)]
enum Month {
    Unknown,
    January,
    February,
    March,
    April,
    May,
    June,
    July,
    August,
    September,
    October,
    November,
    December,
}

/// Parse the beginning string into a Month, returning Month::Unknown on errors.
fn month_parse(line: &String) -> Month {
    match line.split_whitespace().next().unwrap().to_uppercase().as_ref() {
        "JAN" => Month::January,
        "FEB" => Month::February,
        "MAR" => Month::March,
        "APR" => Month::April,
        "MAY" => Month::May,
        "JUN" => Month::June,
        "JUL" => Month::July,
        "AUG" => Month::August,
        "SEP" => Month::September,
        "OCT" => Month::October,
        "NOV" => Month::November,
        "DEC" => Month::December,
        _     => Month::Unknown,
    }
}

fn month_compare(a: &String, b: &String) -> Ordering {
    month_parse(a).cmp(&month_parse(b))
}

fn version_compare(a: &String, b: &String) -> Ordering {
    let ver_a = Version::parse(a);
    let ver_b = Version::parse(b);
    if ver_a > ver_b {
        Ordering::Greater
    }
    else if ver_a < ver_b {
        Ordering::Less
    }
    else {
        Ordering::Equal
    }
}

fn print_sorted<S, T: Iterator<Item=S>>(iter: T, outfile: &Option<String>) where S: std::fmt::Display {
    let mut file: Box<Write> = match *outfile {
        Some(ref filename) => {
            match File::create(Path::new(&filename)) {
                Ok(f) => Box::new(BufWriter::new(f)) as Box<Write>,
                Err(e) => {
                    show_error!("sort: {0}: {1}", filename, e.to_string());
                    panic!("Could not open output file");
                },
            }
        },
        None => Box::new(stdout()) as Box<Write>,
    };

    for line in iter {
        let str = format!("{}\n", line);
        match file.write_all(str.as_bytes()) {
            Err(e) => {
                show_error!("sort: {0}", e.to_string());
                panic!("Write failed");
            },
            Ok(_) => (),
        }
    }
}

// from cat.rs
fn open(path: &str) -> Option<(Box<Read>, bool)> {
    if path == "-" {
        let stdin = stdin();
        return Some((Box::new(stdin) as Box<Read>, is_stdin_interactive()));
    }

    match File::open(Path::new(path)) {
        Ok(f) => Some((Box::new(f) as Box<Read>, false)),
        Err(e) => {
            show_error!("sort: {0}: {1}", path, e.to_string());
            None
        },
    }
}
<|endoftext|>


<commit_before>extern crate curl;
extern crate docopt;

use curl::http::handle::Method;
use curl::http;
use docopt::Docopt;
use super::request::SpagRequest;
use super::file;

docopt!(Args derive Debug, "
Usage: spag request [show] <file> [(-H <header>)...]
       spag (get|post|put|patch|delete) <resource> [(-H <header>)...]
       spag env set (<key> <val>)...
       spag env show [<environment>]
       spag history
       spag history show <index>

Options:
    -h, --help      Show this message
    -H, --header    Supply a header

Arguments:
    <resource>      The path of an api resource, like /v2/things
    <header>        An http header, like 'Content-type: application/json'
    <environment>   The name of an environment, like 'default'
    <index>         An index, starting at zero
");

pub fn main() {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
    println!("{:?}", args);

    if args.cmd_request {
        spag_request(&args);
    } else if args.cmd_history {
        spag_history(&args);
    } else if args.cmd_env {
        spag_env(&args);
    } else if args.cmd_get || args.cmd_post || args.cmd_put || args.cmd_patch || args.cmd_delete {
        spag_method(&args);
    }
}

fn spag_env(args: &Args) {
    if args.cmd_show {
        spag_env_show(&args);
    } else if args.cmd_set {
        spag_env_set(&args);
    } else {
        panic!("BUG: Invalid command");
    }
}

fn spag_env_set(args: &Args) {
    println!("TODO");
    let y = file::load_yaml_file("active.yml");
    println!("{:?}", y);
}

fn spag_env_show(args: &Args) {
    let s = file::read_file("active.yml");
    println!("{}", s.trim());
}

fn spag_history(args: &Args) {
    println!("called spag history");
}

fn spag_request(args: &Args) {
    println!("called spag request");
}

fn spag_method(args: &Args) {
    let method = get_method_from_args(args);
    let endpoint = "http://localhost:5000".to_string();
    let uri = args.arg_resource.to_string();
    let mut req = SpagRequest::new(method, endpoint, uri);
    req.add_headers(args.arg_header.iter());
    do_request(&req);
}

fn do_request(req: &SpagRequest) {
    println!("{:?}", req);
    let mut handle = http::handle();
    let resp = req.prepare(&mut handle).exec().unwrap();
    println!("{}", resp);
}

fn get_method_from_args(args: &Args) -> Method {
    if args.cmd_get { Method::Get }
    else if args.cmd_post { Method::Post }
    else if args.cmd_put { Method::Put }
    else if args.cmd_patch { Method::Patch }
    else if args.cmd_delete { Method::Delete }
    else { panic!("BUG: method not recognized"); }
}
<commit_msg>Improve help<commit_after>extern crate curl;
extern crate docopt;

use curl::http::handle::Method;
use curl::http;
use docopt::Docopt;
use super::request::SpagRequest;
use super::file;

docopt!(Args derive Debug, "
Usage:
    spag (-h|--help)
    spag env set (<key> <val>)...
    spag env show [<environment>]
    spag (get|post|put|patch|delete) <resource> [(-H <header>)...]
    spag request <file> [(-H <header>)...]
    spag request show <file>
    spag history
    spag history show <index>

Options:
    -h, --help      Show this message
    -H, --header    Supply a header

Arguments:
    <resource>      The path of an api resource, like /v2/things
    <header>        An http header, like 'Content-type: application/json'
    <environment>   The name of an environment, like 'default'
    <index>         An index, starting at zero

Commands:
    env set         Set a key-value pair in the active environment
    env show        Print out the specified environment
    get             An HTTP GET request
    post            An HTTP POST request
    put             An HTTP PUT request
    patch           An HTTP PATCH request
    delete          An HTTP DELETE request
    request         Make a request using a predefined file
    request show    Show the specified request file
    history         Print a list of previously made requests
    history show    Print out a previous request by its index
");

pub fn main() {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
    println!("{:?}", args);

    if args.cmd_request {
        spag_request(&args);
    } else if args.cmd_history {
        spag_history(&args);
    } else if args.cmd_env {
        spag_env(&args);
    } else if args.cmd_get || args.cmd_post || args.cmd_put || args.cmd_patch || args.cmd_delete {
        spag_method(&args);
    }
}

fn spag_env(args: &Args) {
    if args.cmd_show {
        spag_env_show(&args);
    } else if args.cmd_set {
        spag_env_set(&args);
    } else {
        panic!("BUG: Invalid command");
    }
}

fn spag_env_set(args: &Args) {
    println!("TODO");
    let y = file::load_yaml_file("active.yml");
    println!("{:?}", y);
}

fn spag_env_show(args: &Args) {
    let s = file::read_file("active.yml");
    println!("{}", s.trim());
}

fn spag_history(args: &Args) {
    println!("called spag history");
}

fn spag_request(args: &Args) {
    println!("called spag request");
}

fn spag_method(args: &Args) {
    let method = get_method_from_args(args);
    let endpoint = "http://localhost:5000".to_string();
    let uri = args.arg_resource.to_string();
    let mut req = SpagRequest::new(method, endpoint, uri);
    req.add_headers(args.arg_header.iter());
    do_request(&req);
}

fn do_request(req: &SpagRequest) {
    println!("{:?}", req);
    let mut handle = http::handle();
    let resp = req.prepare(&mut handle).exec().unwrap();
    println!("{}", resp);
}

fn get_method_from_args(args: &Args) -> Method {
    if args.cmd_get { Method::Get }
    else if args.cmd_post { Method::Post }
    else if args.cmd_put { Method::Put }
    else if args.cmd_patch { Method::Patch }
    else if args.cmd_delete { Method::Delete }
    else { panic!("BUG: method not recognized"); }
}
<|endoftext|>


<commit_before><commit_msg>Add test<commit_after><|endoftext|>


<commit_before><commit_msg>Change GroupCurve25519 method signatures to returns references<commit_after><|endoftext|>


<commit_before><commit_msg>Error handle?<commit_after><|endoftext|>


<commit_before><commit_msg>Implemented sleep.<commit_after><|endoftext|>


<commit_before>extern crate pulldown_cmark;

use std::path::{Path, Component};
use std::error::Error;
use std::io;
use std::fs::{self, metadata, File};

use self::pulldown_cmark::{Parser, html, Options, OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};

/// Takes a path and returns a path containing just enough `../` to point to the root of the given path.
///
/// This is mostly interesting for a relative path to point back to the directory from where the
/// path starts.
///
/// ```ignore
/// let mut path = Path::new("some/relative/path");
///
/// println!("{}", path_to_root(&path));
/// ```
///
/// **Outputs**
///
/// ```text
/// "../../"
/// ```
///
/// **note:** it's not very fool-proof, if you find a situation where it doesn't return the correct
/// path. Consider [submitting a new issue](https://github.com/azerupi/mdBook/issues) or a
/// [pull-request](https://github.com/azerupi/mdBook/pulls) to improve it.

pub fn path_to_root(path: &Path) -> String {
    debug!("[fn]: path_to_root");
    // Remove filename and add "../" for every directory

    path.to_path_buf().parent().expect("")
        .components().fold(String::new(), |mut s, c| {
            match c {
                Component::Normal(_) => s.push_str("../"),
                _ => {
                    debug!("[*]: Other path component... {:?}", c);
                }
            }
            s
        })
}

/// This function creates a file and returns it. But before creating the file it checks every
/// directory in the path to see if it exists, and if it does not it will be created.

pub fn create_file(path: &Path) -> Result<File, Box<Error>> {
    debug!("[fn]: create_file");

    // Construct path
    if let Some(p) = path.parent() {
        debug!("Parent directory is: {:?}", p);

        try!(fs::create_dir_all(p));
    }

    debug!("[*]: Create file: {:?}", path);
    let f = match File::create(path) {
        Ok(f) => f,
        Err(e) => {
            debug!("File::create:    {}", e);
            return Err(Box::new(io::Error::new(io::ErrorKind::Other, format!("{}", e))))
        },
    };

    Ok(f)
}

/// Removes all the content of a directory but not the directory itself

pub fn remove_dir_content(dir: &Path) -> Result<(), Box<Error>> {
    for item in try!(fs::read_dir(dir)) {
        if let Ok(item) = item {
            let item = item.path();
            if item.is_dir() { try!(fs::remove_dir_all(item)); } else { try!(fs::remove_file(item)); }
        }
    }
    Ok(())
}

///
///
/// Copies all files of a directory to another one except the files with the extensions given in the
/// `ext_blacklist` array

pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blacklist: &[&str]) -> Result<(), Box<Error>> {
    debug!("[fn] copy_files_except_ext");
    // Check that from and to are different
    if from == to { return Ok(()) }
    debug!("[*] Loop");
    for entry in try!(fs::read_dir(from)) {
        let entry = try!(entry);
        debug!("[*] {:?}", entry.path());
        let metadata = try!(entry.metadata());

        // If the entry is a dir and the recursive option is enabled, call itself
        if metadata.is_dir() && recursive {
            if entry.path() == to.to_path_buf() { continue }
            debug!("[*] is dir");

            // check if output dir already exists
            if !to.join(entry.file_name()).exists() {
                try!(fs::create_dir(&to.join(entry.file_name())));
            }

            try!(copy_files_except_ext(
                &from.join(entry.file_name()),
                &to.join(entry.file_name()),
                true,
                ext_blacklist
            ));
        } else if metadata.is_file() {

            // Check if it is in the blacklist
            if let Some(ext) = entry.path().extension() {
                if ext_blacklist.contains(&ext.to_str().unwrap()) { continue }
                debug!("[*] creating path for file: {:?}", &to.join(entry.path().file_name().expect("a file should have a file name...")));

                output!("[*] copying file: {:?}\n    to {:?}", entry.path(), &to.join(entry.path().file_name().expect("a file should have a file name...")));
                try!(fs::copy(entry.path(), &to.join(entry.path().file_name().expect("a file should have a file name..."))));
            }
        }
    }
    Ok(())
}

///
///
/// Wrapper around the pulldown-cmark parser and renderer to render markdown

pub fn render_markdown(text: &str) -> String {
    let mut s = String::with_capacity(text.len() * 3 / 2);

    let mut opts = Options::empty();
    opts.insert(OPTION_ENABLE_TABLES);
    opts.insert(OPTION_ENABLE_FOOTNOTES);

    let p = Parser::new_ext(&text, opts);
    html::push_html(&mut s, p);
    s
}

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------

// tests

#[cfg(test)]
mod tests {
    extern crate tempdir;

    use super::copy_files_except_ext;
    use super::PathExt;
    use std::fs;

    #[test]
    fn copy_files_except_ext_test() {
        let tmp = match tempdir::TempDir::new("") {
            Ok(t) => t,
            Err(_) => panic!("Could not create a temp dir"),
        };

        // Create a couple of files
        if let Err(_) =  fs::File::create(&tmp.path().join("file.txt")) { panic!("Could not create file.txt") }
        if let Err(_) =  fs::File::create(&tmp.path().join("file.md")) { panic!("Could not create file.md") }
        if let Err(_) =  fs::File::create(&tmp.path().join("file.png")) { panic!("Could not create file.png") }
        if let Err(_) =  fs::create_dir(&tmp.path().join("sub_dir")) { panic!("Could not create sub_dir") }
        if let Err(_) =  fs::File::create(&tmp.path().join("sub_dir/file.png")) { panic!("Could not create sub_dir/file.png") }
        if let Err(_) =  fs::create_dir(&tmp.path().join("sub_dir_exists")) { panic!("Could not create sub_dir_exists") }
        if let Err(_) =  fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) { panic!("Could not create sub_dir_exists/file.txt") }

        // Create output dir
        if let Err(_) =  fs::create_dir(&tmp.path().join("output")) { panic!("Could not create output") }
        if let Err(_) =  fs::create_dir(&tmp.path().join("output/sub_dir_exists")) { panic!("Could not create output/sub_dir_exists") }

        match copy_files_except_ext(&tmp.path(), &tmp.path().join("output"), true, &["md"]) {
            Err(e) => panic!("Error while executing the function:\n{:?}", e),
            Ok(_) => {},
        }

        // Check if the correct files where created
        if !(&tmp.path().join("output/file.txt")).exists() { panic!("output/file.txt should exist") }
        if (&tmp.path().join("output/file.md")).exists() { panic!("output/file.md should not exist") }
        if !(&tmp.path().join("output/file.png")).exists() { panic!("output/file.png should exist") }
        if !(&tmp.path().join("output/sub_dir/file.png")).exists() { panic!("output/sub_dir/file.png should exist") }
        if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() { panic!("output/sub_dir/file.png should exist") }

    }
}
<commit_msg>Fix tests after removing PathExt from utils<commit_after>extern crate pulldown_cmark;

use std::path::{Path, Component};
use std::error::Error;
use std::io;
use std::fs::{self, metadata, File};

use self::pulldown_cmark::{Parser, html, Options, OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};

/// Takes a path and returns a path containing just enough `../` to point to the root of the given path.
///
/// This is mostly interesting for a relative path to point back to the directory from where the
/// path starts.
///
/// ```ignore
/// let mut path = Path::new("some/relative/path");
///
/// println!("{}", path_to_root(&path));
/// ```
///
/// **Outputs**
///
/// ```text
/// "../../"
/// ```
///
/// **note:** it's not very fool-proof, if you find a situation where it doesn't return the correct
/// path. Consider [submitting a new issue](https://github.com/azerupi/mdBook/issues) or a
/// [pull-request](https://github.com/azerupi/mdBook/pulls) to improve it.

pub fn path_to_root(path: &Path) -> String {
    debug!("[fn]: path_to_root");
    // Remove filename and add "../" for every directory

    path.to_path_buf().parent().expect("")
        .components().fold(String::new(), |mut s, c| {
            match c {
                Component::Normal(_) => s.push_str("../"),
                _ => {
                    debug!("[*]: Other path component... {:?}", c);
                }
            }
            s
        })
}

/// This function creates a file and returns it. But before creating the file it checks every
/// directory in the path to see if it exists, and if it does not it will be created.

pub fn create_file(path: &Path) -> Result<File, Box<Error>> {
    debug!("[fn]: create_file");

    // Construct path
    if let Some(p) = path.parent() {
        debug!("Parent directory is: {:?}", p);

        try!(fs::create_dir_all(p));
    }

    debug!("[*]: Create file: {:?}", path);
    let f = match File::create(path) {
        Ok(f) => f,
        Err(e) => {
            debug!("File::create:    {}", e);
            return Err(Box::new(io::Error::new(io::ErrorKind::Other, format!("{}", e))))
        },
    };

    Ok(f)
}

/// Removes all the content of a directory but not the directory itself

pub fn remove_dir_content(dir: &Path) -> Result<(), Box<Error>> {
    for item in try!(fs::read_dir(dir)) {
        if let Ok(item) = item {
            let item = item.path();
            if item.is_dir() { try!(fs::remove_dir_all(item)); } else { try!(fs::remove_file(item)); }
        }
    }
    Ok(())
}

///
///
/// Copies all files of a directory to another one except the files with the extensions given in the
/// `ext_blacklist` array

pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blacklist: &[&str]) -> Result<(), Box<Error>> {
    debug!("[fn] copy_files_except_ext");
    // Check that from and to are different
    if from == to { return Ok(()) }
    debug!("[*] Loop");
    for entry in try!(fs::read_dir(from)) {
        let entry = try!(entry);
        debug!("[*] {:?}", entry.path());
        let metadata = try!(entry.metadata());

        // If the entry is a dir and the recursive option is enabled, call itself
        if metadata.is_dir() && recursive {
            if entry.path() == to.to_path_buf() { continue }
            debug!("[*] is dir");

            // check if output dir already exists
            if !to.join(entry.file_name()).exists() {
                try!(fs::create_dir(&to.join(entry.file_name())));
            }

            try!(copy_files_except_ext(
                &from.join(entry.file_name()),
                &to.join(entry.file_name()),
                true,
                ext_blacklist
            ));
        } else if metadata.is_file() {

            // Check if it is in the blacklist
            if let Some(ext) = entry.path().extension() {
                if ext_blacklist.contains(&ext.to_str().unwrap()) { continue }
                debug!("[*] creating path for file: {:?}", &to.join(entry.path().file_name().expect("a file should have a file name...")));

                output!("[*] copying file: {:?}\n    to {:?}", entry.path(), &to.join(entry.path().file_name().expect("a file should have a file name...")));
                try!(fs::copy(entry.path(), &to.join(entry.path().file_name().expect("a file should have a file name..."))));
            }
        }
    }
    Ok(())
}

///
///
/// Wrapper around the pulldown-cmark parser and renderer to render markdown

pub fn render_markdown(text: &str) -> String {
    let mut s = String::with_capacity(text.len() * 3 / 2);

    let mut opts = Options::empty();
    opts.insert(OPTION_ENABLE_TABLES);
    opts.insert(OPTION_ENABLE_FOOTNOTES);

    let p = Parser::new_ext(&text, opts);
    html::push_html(&mut s, p);
    s
}

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------

// tests

#[cfg(test)]
mod tests {
    extern crate tempdir;

    use super::copy_files_except_ext;
    use std::fs;

    #[test]
    fn copy_files_except_ext_test() {
        let tmp = match tempdir::TempDir::new("") {
            Ok(t) => t,
            Err(_) => panic!("Could not create a temp dir"),
        };

        // Create a couple of files
        if let Err(_) =  fs::File::create(&tmp.path().join("file.txt")) { panic!("Could not create file.txt") }
        if let Err(_) =  fs::File::create(&tmp.path().join("file.md")) { panic!("Could not create file.md") }
        if let Err(_) =  fs::File::create(&tmp.path().join("file.png")) { panic!("Could not create file.png") }
        if let Err(_) =  fs::create_dir(&tmp.path().join("sub_dir")) { panic!("Could not create sub_dir") }
        if let Err(_) =  fs::File::create(&tmp.path().join("sub_dir/file.png")) { panic!("Could not create sub_dir/file.png") }
        if let Err(_) =  fs::create_dir(&tmp.path().join("sub_dir_exists")) { panic!("Could not create sub_dir_exists") }
        if let Err(_) =  fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) { panic!("Could not create sub_dir_exists/file.txt") }

        // Create output dir
        if let Err(_) =  fs::create_dir(&tmp.path().join("output")) { panic!("Could not create output") }
        if let Err(_) =  fs::create_dir(&tmp.path().join("output/sub_dir_exists")) { panic!("Could not create output/sub_dir_exists") }

        match copy_files_except_ext(&tmp.path(), &tmp.path().join("output"), true, &["md"]) {
            Err(e) => panic!("Error while executing the function:\n{:?}", e),
            Ok(_) => {},
        }

        // Check if the correct files where created
        if !(&tmp.path().join("output/file.txt")).exists() { panic!("output/file.txt should exist") }
        if (&tmp.path().join("output/file.md")).exists() { panic!("output/file.md should not exist") }
        if !(&tmp.path().join("output/file.png")).exists() { panic!("output/file.png should exist") }
        if !(&tmp.path().join("output/sub_dir/file.png")).exists() { panic!("output/sub_dir/file.png should exist") }
        if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() { panic!("output/sub_dir/file.png should exist") }

    }
}
<|endoftext|>


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

use std::collections::{HashMap, hash_map};
use std::iter::IntoIterator;

use uuid::Uuid;

use engine::Name;

/// Map UUID and name to T items.
#[derive(Debug)]
pub struct Table<T> {
    name_to_uuid: HashMap<Name, Uuid>,
    items: HashMap<Uuid, (Name, T)>,
}

impl<T> Default for Table<T> {
    fn default() -> Table<T> {
        Table {
            name_to_uuid: HashMap::default(),
            items: HashMap::default(),
        }
    }
}

pub struct Iter<'a, T: 'a> {
    items: hash_map::Iter<'a, Uuid, (Name, T)>,
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = (&'a Name, &'a Uuid, &'a T);

    #[inline]
    fn next(&mut self) -> Option<(&'a Name, &'a Uuid, &'a T)> {
        self.items
            .next()
            .map(|(uuid, &(ref name, ref item))| (&*name, uuid, item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.items.size_hint()
    }
}

pub struct IterMut<'a, T: 'a> {
    items: hash_map::IterMut<'a, Uuid, (Name, T)>,
}

impl<'a, T> Iterator for IterMut<'a, T> {
    type Item = (&'a Name, &'a Uuid, &'a mut T);

    #[inline]
    fn next(&mut self) -> Option<(&'a Name, &'a Uuid, &'a mut T)> {
        self.items
            .next()
            .map(|(uuid, &mut (ref name, ref mut item))| (&*name, uuid, item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.items.size_hint()
    }
}

pub struct IntoIter<T> {
    items: hash_map::IntoIter<Uuid, (Name, T)>,
}

impl<T> Iterator for IntoIter<T> {
    type Item = (Name, Uuid, T);

    #[inline]
    fn next(&mut self) -> Option<(Name, Uuid, T)> {
        self.items
            .next()
            .map(|(uuid, (name, item))| (name, uuid, item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.items.size_hint()
    }
}

impl<T> IntoIterator for Table<T> {
    type Item = (Name, Uuid, T);
    type IntoIter = IntoIter<T>;

    fn into_iter(self) -> IntoIter<T> {
        self.into_iter()
    }
}

impl<'a, T> IntoIterator for &'a Table<T> {
    type Item = (&'a Name, &'a Uuid, &'a T);
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Iter<'a, T> {
        self.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut Table<T> {
    type Item = (&'a Name, &'a Uuid, &'a mut T);
    type IntoIter = IterMut<'a, T>;

    fn into_iter(self) -> IterMut<'a, T> {
        self.iter_mut()
    }
}

/// All operations are O(1), although Name lookups are slightly disadvantaged
/// vs. Uuid lookups. In order to rename a T item, it must be removed,
/// renamed, and reinserted under the new name.
impl<T> Table<T> {
    pub fn is_empty(&self) -> bool {
        self.items.is_empty()
    }

    pub fn len(&self) -> usize {
        self.items.len()
    }

    pub fn iter(&self) -> Iter<T> {
        Iter { items: self.items.iter() }
    }

    pub fn iter_mut(&mut self) -> IterMut<T> {
        IterMut { items: self.items.iter_mut() }
    }

    pub fn into_iter(self) -> IntoIter<T> {
        IntoIter { items: self.items.into_iter() }
    }

    /// Returns true if map has an item corresponding to this name, else false.
    pub fn contains_name(&self, name: &str) -> bool {
        self.name_to_uuid.contains_key(name)
    }

    /// Returns true if map has an item corresponding to this uuid, else false.
    pub fn contains_uuid(&self, uuid: Uuid) -> bool {
        self.items.contains_key(&uuid)
    }

    /// Get item by name.
    pub fn get_by_name(&self, name: &str) -> Option<(Uuid, &T)> {
        self.name_to_uuid
            .get(&*name)
            .and_then(|uuid| self.items.get(uuid).map(|&(_, ref item)| (*uuid, item)))
    }

    /// Get item by uuid.
    pub fn get_by_uuid(&self, uuid: Uuid) -> Option<(Name, &T)> {
        self.items
            .get(&uuid)
            .map(|&(ref name, ref item)| (name.clone(), item))
    }

    /// Get mutable item by name.
    pub fn get_mut_by_name(&mut self, name: &str) -> Option<(Uuid, &mut T)> {
        let uuid = match self.name_to_uuid.get(name) {
            Some(uuid) => *uuid,
            None => return None,
        };
        self.items
            .get_mut(&uuid)
            .map(|&mut (_, ref mut item)| (uuid, item))
    }

    /// Get mutable item by uuid.
    pub fn get_mut_by_uuid(&mut self, uuid: Uuid) -> Option<(Name, &mut T)> {
        self.items
            .get_mut(&uuid)
            .map(|&mut (ref name, ref mut item)| (name.clone(), item))
    }

    /// Removes the item corresponding to name if there is one.
    pub fn remove_by_name(&mut self, name: &str) -> Option<(Uuid, T)> {
        if let Some(uuid) = self.name_to_uuid.remove(name) {
            self.items.remove(&uuid).map(|(_, item)| (uuid, item))
        } else {
            None
        }
    }

    /// Removes the item corresponding to the uuid if there is one.
    pub fn remove_by_uuid(&mut self, uuid: Uuid) -> Option<(Name, T)> {
        if let Some((name, item)) = self.items.remove(&uuid) {
            self.name_to_uuid.remove(&name);
            Some((name, item))
        } else {
            None
        }
    }

    /// Inserts an item for given uuid and name.
    /// Possibly returns the item displaced.
    pub fn insert(&mut self, name: Name, uuid: Uuid, item: T) -> Option<(Name, Uuid, T)> {
        match self.name_to_uuid.insert(name.clone(), uuid) {
            Some(old_uuid) => {
                // (existing name, _)
                match self.items.insert(uuid, (name, item)) {
                    // (existing name, existing uuid)
                    Some((old_name, old_item)) => Some((old_name, uuid, old_item)),
                    // (existing name, new uuid)
                    None => {
                        let (old_name, old_item) =
                            self.items.remove(&old_uuid).expect("should be there");
                        Some((old_name, old_uuid, old_item))
                    }
                }
            }
            None => {
                // (new name, existing uuid)
                if let Some((old_name, old_item)) = self.items.insert(uuid, (name, item)) {
                    let old_uuid = self.name_to_uuid
                        .remove(&old_name)
                        .expect("should be there");
                    Some((old_name, old_uuid, old_item))
                } else {
                    // (new name, new uuid)
                    None
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {

    use rand;
    use uuid::Uuid;

    use engine::Name;

    use super::Table;

    #[derive(Debug)]
    struct TestThing {
        name: String,
        uuid: Uuid,
        stuff: u32,
    }

    // A global invariant checker for the table.
    // Verifies proper relationship between internal data structures.
    fn table_invariant<T>(table: &Table<T>) -> () {
        for (uuid, &(ref name, _)) in &table.items {
            assert_eq!(*uuid, *table.name_to_uuid.get(name).unwrap())
        }

        // No extra garbage
        assert_eq!(table.name_to_uuid.len(), table.items.len())
    }

    impl TestThing {
        pub fn new(name: &str, uuid: Uuid) -> TestThing {
            TestThing {
                name: name.to_owned(),
                uuid: uuid.clone(),
                stuff: rand::random::<u32>(),
            }
        }
    }

    #[test]
    /// Remove a test object by its uuid.
    /// Mutate the removed test object.
    /// Verify that the table is now empty and that removing by name yields
    /// no result.
    fn remove_existing_item() {
        let mut t: Table<TestThing> = Table::default();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        t.insert(Name::new(name.to_owned()),
                 uuid,
                 TestThing::new(&name, uuid));
        table_invariant(&t);

        assert!(t.get_by_name(&name).is_some());
        assert!(t.get_by_uuid(uuid).is_some());
        let thing = t.remove_by_uuid(uuid);
        table_invariant(&t);
        assert!(thing.is_some());
        let mut thing = thing.unwrap();
        thing.1.stuff = 0;
        assert!(t.is_empty());
        assert!(t.remove_by_name(&name).is_none());
        table_invariant(&t);

        assert!(t.get_by_name(&name).is_none());
        assert!(t.get_by_uuid(uuid).is_none());
    }

    #[test]
    /// Insert a thing and then insert another thing with same keys.
    /// The previously inserted thing should be returned.
    /// You can't insert the identical thing, because that would be a move.
    /// This is good, because then you can't have a thing that is both in
    /// the table and not in the table.
    fn insert_same_keys() {
        let mut t: Table<TestThing> = Table::default();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        let thing = TestThing::new(&name, uuid);
        let thing_key = thing.stuff;
        let displaced = t.insert(Name::new(name.to_owned()), uuid, thing);
        table_invariant(&t);

        // There was nothing previously, so displaced must be empty.
        assert!(displaced.is_none());

        // t now contains the inserted thing.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(uuid));
        assert!(t.get_by_uuid(uuid).unwrap().1.stuff == thing_key);

        // Add another thing with the same keys.
        let thing2 = TestThing::new(&name, uuid);
        let thing_key2 = thing2.stuff;
        let displaced = t.insert(Name::new(name.to_owned()), uuid, thing2);
        table_invariant(&t);

        // It has displaced the old thing.
        assert!(displaced.is_some());
        let ref displaced_item = displaced.unwrap();
        assert!(&*displaced_item.0 == name);
        assert!(displaced_item.1 == uuid);

        // But it contains a thing with the same keys.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(uuid));
        assert!(t.get_by_uuid(uuid).unwrap().1.stuff == thing_key2);
        assert!(t.len() == 1);
    }

    #[test]
    /// Insert a thing and then insert another thing with the same name.
    /// The previously inserted thing should be returned.
    fn insert_same_name() {
        let mut t: Table<TestThing> = Table::default();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        let thing = TestThing::new(&name, uuid);
        let thing_key = thing.stuff;

        // There was nothing in the table before, so displaced is empty.
        let displaced = t.insert(Name::new(name.to_owned()), uuid, thing);
        table_invariant(&t);
        assert!(displaced.is_none());

        // t now contains thing.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(uuid));

        // Insert new item with different UUID.
        let uuid2 = Uuid::new_v4();
        let thing2 = TestThing::new(&name, uuid2);
        let thing_key2 = thing2.stuff;
        let displaced = t.insert(Name::new(name.to_owned()), uuid2, thing2);
        table_invariant(&t);

        // The items displaced consist exactly of the first item.
        assert!(displaced.is_some());
        let ref displaced_item = displaced.unwrap();
        assert!(&*displaced_item.0 == name);
        assert!(displaced_item.1 == uuid);
        assert!(displaced_item.2.stuff == thing_key);

        // The table contains the new item and has no memory of the old.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(uuid2));
        assert!(!t.contains_uuid(uuid));
        assert!(t.get_by_uuid(uuid2).unwrap().1.stuff == thing_key2);
        assert!(t.get_by_name(&name).unwrap().1.stuff == thing_key2);
        assert!(t.len() == 1);
    }

    #[test]
    /// Insert a thing and then insert another thing with the same uuid.
    /// The previously inserted thing should be returned.
    fn insert_same_uuid() {
        let mut t: Table<TestThing> = Table::default();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        let thing = TestThing::new(&name, uuid);
        let thing_key = thing.stuff;

        // There was nothing in the table before, so displaced is empty.
        let displaced = t.insert(Name::new(name.to_owned()), uuid, thing);
        table_invariant(&t);
        assert!(displaced.is_none());

        // t now contains thing.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(uuid));

        // Insert new item with different UUID.
        let name2 = "name2";
        let thing2 = TestThing::new(&name2, uuid);
        let thing_key2 = thing2.stuff;
        let displaced = t.insert(Name::new(name2.to_owned()), uuid, thing2);
        table_invariant(&t);

        // The items displaced consist exactly of the first item.
        assert!(displaced.is_some());
        let ref displaced_item = displaced.unwrap();
        assert!(&*displaced_item.0 == name);
        assert!(displaced_item.1 == uuid);
        assert!(displaced_item.2.stuff == thing_key);

        // The table contains the new item and has no memory of the old.
        assert!(t.contains_uuid(uuid));
        assert!(t.contains_name(name2));
        assert!(!t.contains_name(name));
        assert!(t.get_by_uuid(uuid).unwrap().1.stuff == thing_key2);
        assert!(t.get_by_name(&name2).unwrap().1.stuff == thing_key2);
        assert!(t.len() == 1);
    }
}
<commit_msg>Use assert_eq! instead of assert! when possible<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::collections::{HashMap, hash_map};
use std::iter::IntoIterator;

use uuid::Uuid;

use engine::Name;

/// Map UUID and name to T items.
#[derive(Debug)]
pub struct Table<T> {
    name_to_uuid: HashMap<Name, Uuid>,
    items: HashMap<Uuid, (Name, T)>,
}

impl<T> Default for Table<T> {
    fn default() -> Table<T> {
        Table {
            name_to_uuid: HashMap::default(),
            items: HashMap::default(),
        }
    }
}

pub struct Iter<'a, T: 'a> {
    items: hash_map::Iter<'a, Uuid, (Name, T)>,
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = (&'a Name, &'a Uuid, &'a T);

    #[inline]
    fn next(&mut self) -> Option<(&'a Name, &'a Uuid, &'a T)> {
        self.items
            .next()
            .map(|(uuid, &(ref name, ref item))| (&*name, uuid, item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.items.size_hint()
    }
}

pub struct IterMut<'a, T: 'a> {
    items: hash_map::IterMut<'a, Uuid, (Name, T)>,
}

impl<'a, T> Iterator for IterMut<'a, T> {
    type Item = (&'a Name, &'a Uuid, &'a mut T);

    #[inline]
    fn next(&mut self) -> Option<(&'a Name, &'a Uuid, &'a mut T)> {
        self.items
            .next()
            .map(|(uuid, &mut (ref name, ref mut item))| (&*name, uuid, item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.items.size_hint()
    }
}

pub struct IntoIter<T> {
    items: hash_map::IntoIter<Uuid, (Name, T)>,
}

impl<T> Iterator for IntoIter<T> {
    type Item = (Name, Uuid, T);

    #[inline]
    fn next(&mut self) -> Option<(Name, Uuid, T)> {
        self.items
            .next()
            .map(|(uuid, (name, item))| (name, uuid, item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.items.size_hint()
    }
}

impl<T> IntoIterator for Table<T> {
    type Item = (Name, Uuid, T);
    type IntoIter = IntoIter<T>;

    fn into_iter(self) -> IntoIter<T> {
        self.into_iter()
    }
}

impl<'a, T> IntoIterator for &'a Table<T> {
    type Item = (&'a Name, &'a Uuid, &'a T);
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Iter<'a, T> {
        self.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut Table<T> {
    type Item = (&'a Name, &'a Uuid, &'a mut T);
    type IntoIter = IterMut<'a, T>;

    fn into_iter(self) -> IterMut<'a, T> {
        self.iter_mut()
    }
}

/// All operations are O(1), although Name lookups are slightly disadvantaged
/// vs. Uuid lookups. In order to rename a T item, it must be removed,
/// renamed, and reinserted under the new name.
impl<T> Table<T> {
    pub fn is_empty(&self) -> bool {
        self.items.is_empty()
    }

    pub fn len(&self) -> usize {
        self.items.len()
    }

    pub fn iter(&self) -> Iter<T> {
        Iter { items: self.items.iter() }
    }

    pub fn iter_mut(&mut self) -> IterMut<T> {
        IterMut { items: self.items.iter_mut() }
    }

    pub fn into_iter(self) -> IntoIter<T> {
        IntoIter { items: self.items.into_iter() }
    }

    /// Returns true if map has an item corresponding to this name, else false.
    pub fn contains_name(&self, name: &str) -> bool {
        self.name_to_uuid.contains_key(name)
    }

    /// Returns true if map has an item corresponding to this uuid, else false.
    pub fn contains_uuid(&self, uuid: Uuid) -> bool {
        self.items.contains_key(&uuid)
    }

    /// Get item by name.
    pub fn get_by_name(&self, name: &str) -> Option<(Uuid, &T)> {
        self.name_to_uuid
            .get(&*name)
            .and_then(|uuid| self.items.get(uuid).map(|&(_, ref item)| (*uuid, item)))
    }

    /// Get item by uuid.
    pub fn get_by_uuid(&self, uuid: Uuid) -> Option<(Name, &T)> {
        self.items
            .get(&uuid)
            .map(|&(ref name, ref item)| (name.clone(), item))
    }

    /// Get mutable item by name.
    pub fn get_mut_by_name(&mut self, name: &str) -> Option<(Uuid, &mut T)> {
        let uuid = match self.name_to_uuid.get(name) {
            Some(uuid) => *uuid,
            None => return None,
        };
        self.items
            .get_mut(&uuid)
            .map(|&mut (_, ref mut item)| (uuid, item))
    }

    /// Get mutable item by uuid.
    pub fn get_mut_by_uuid(&mut self, uuid: Uuid) -> Option<(Name, &mut T)> {
        self.items
            .get_mut(&uuid)
            .map(|&mut (ref name, ref mut item)| (name.clone(), item))
    }

    /// Removes the item corresponding to name if there is one.
    pub fn remove_by_name(&mut self, name: &str) -> Option<(Uuid, T)> {
        if let Some(uuid) = self.name_to_uuid.remove(name) {
            self.items.remove(&uuid).map(|(_, item)| (uuid, item))
        } else {
            None
        }
    }

    /// Removes the item corresponding to the uuid if there is one.
    pub fn remove_by_uuid(&mut self, uuid: Uuid) -> Option<(Name, T)> {
        if let Some((name, item)) = self.items.remove(&uuid) {
            self.name_to_uuid.remove(&name);
            Some((name, item))
        } else {
            None
        }
    }

    /// Inserts an item for given uuid and name.
    /// Possibly returns the item displaced.
    pub fn insert(&mut self, name: Name, uuid: Uuid, item: T) -> Option<(Name, Uuid, T)> {
        match self.name_to_uuid.insert(name.clone(), uuid) {
            Some(old_uuid) => {
                // (existing name, _)
                match self.items.insert(uuid, (name, item)) {
                    // (existing name, existing uuid)
                    Some((old_name, old_item)) => Some((old_name, uuid, old_item)),
                    // (existing name, new uuid)
                    None => {
                        let (old_name, old_item) =
                            self.items.remove(&old_uuid).expect("should be there");
                        Some((old_name, old_uuid, old_item))
                    }
                }
            }
            None => {
                // (new name, existing uuid)
                if let Some((old_name, old_item)) = self.items.insert(uuid, (name, item)) {
                    let old_uuid = self.name_to_uuid
                        .remove(&old_name)
                        .expect("should be there");
                    Some((old_name, old_uuid, old_item))
                } else {
                    // (new name, new uuid)
                    None
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {

    use rand;
    use uuid::Uuid;

    use engine::Name;

    use super::Table;

    #[derive(Debug)]
    struct TestThing {
        name: String,
        uuid: Uuid,
        stuff: u32,
    }

    // A global invariant checker for the table.
    // Verifies proper relationship between internal data structures.
    fn table_invariant<T>(table: &Table<T>) -> () {
        for (uuid, &(ref name, _)) in &table.items {
            assert_eq!(*uuid, *table.name_to_uuid.get(name).unwrap())
        }

        // No extra garbage
        assert_eq!(table.name_to_uuid.len(), table.items.len())
    }

    impl TestThing {
        pub fn new(name: &str, uuid: Uuid) -> TestThing {
            TestThing {
                name: name.to_owned(),
                uuid: uuid.clone(),
                stuff: rand::random::<u32>(),
            }
        }
    }

    #[test]
    /// Remove a test object by its uuid.
    /// Mutate the removed test object.
    /// Verify that the table is now empty and that removing by name yields
    /// no result.
    fn remove_existing_item() {
        let mut t: Table<TestThing> = Table::default();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        t.insert(Name::new(name.to_owned()),
                 uuid,
                 TestThing::new(&name, uuid));
        table_invariant(&t);

        assert!(t.get_by_name(&name).is_some());
        assert!(t.get_by_uuid(uuid).is_some());
        let thing = t.remove_by_uuid(uuid);
        table_invariant(&t);
        assert!(thing.is_some());
        let mut thing = thing.unwrap();
        thing.1.stuff = 0;
        assert!(t.is_empty());
        assert!(t.remove_by_name(&name).is_none());
        table_invariant(&t);

        assert!(t.get_by_name(&name).is_none());
        assert!(t.get_by_uuid(uuid).is_none());
    }

    #[test]
    /// Insert a thing and then insert another thing with same keys.
    /// The previously inserted thing should be returned.
    /// You can't insert the identical thing, because that would be a move.
    /// This is good, because then you can't have a thing that is both in
    /// the table and not in the table.
    fn insert_same_keys() {
        let mut t: Table<TestThing> = Table::default();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        let thing = TestThing::new(&name, uuid);
        let thing_key = thing.stuff;
        let displaced = t.insert(Name::new(name.to_owned()), uuid, thing);
        table_invariant(&t);

        // There was nothing previously, so displaced must be empty.
        assert!(displaced.is_none());

        // t now contains the inserted thing.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(uuid));
        assert_eq!(t.get_by_uuid(uuid).unwrap().1.stuff, thing_key);

        // Add another thing with the same keys.
        let thing2 = TestThing::new(&name, uuid);
        let thing_key2 = thing2.stuff;
        let displaced = t.insert(Name::new(name.to_owned()), uuid, thing2);
        table_invariant(&t);

        // It has displaced the old thing.
        assert!(displaced.is_some());
        let ref displaced_item = displaced.unwrap();
        assert_eq!(&*displaced_item.0, name);
        assert_eq!(displaced_item.1, uuid);

        // But it contains a thing with the same keys.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(uuid));
        assert_eq!(t.get_by_uuid(uuid).unwrap().1.stuff, thing_key2);
        assert_eq!(t.len(), 1);
    }

    #[test]
    /// Insert a thing and then insert another thing with the same name.
    /// The previously inserted thing should be returned.
    fn insert_same_name() {
        let mut t: Table<TestThing> = Table::default();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        let thing = TestThing::new(&name, uuid);
        let thing_key = thing.stuff;

        // There was nothing in the table before, so displaced is empty.
        let displaced = t.insert(Name::new(name.to_owned()), uuid, thing);
        table_invariant(&t);
        assert!(displaced.is_none());

        // t now contains thing.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(uuid));

        // Insert new item with different UUID.
        let uuid2 = Uuid::new_v4();
        let thing2 = TestThing::new(&name, uuid2);
        let thing_key2 = thing2.stuff;
        let displaced = t.insert(Name::new(name.to_owned()), uuid2, thing2);
        table_invariant(&t);

        // The items displaced consist exactly of the first item.
        assert!(displaced.is_some());
        let ref displaced_item = displaced.unwrap();
        assert_eq!(&*displaced_item.0, name);
        assert_eq!(displaced_item.1, uuid);
        assert_eq!(displaced_item.2.stuff, thing_key);

        // The table contains the new item and has no memory of the old.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(uuid2));
        assert!(!t.contains_uuid(uuid));
        assert_eq!(t.get_by_uuid(uuid2).unwrap().1.stuff, thing_key2);
        assert_eq!(t.get_by_name(&name).unwrap().1.stuff, thing_key2);
        assert_eq!(t.len(), 1);
    }

    #[test]
    /// Insert a thing and then insert another thing with the same uuid.
    /// The previously inserted thing should be returned.
    fn insert_same_uuid() {
        let mut t: Table<TestThing> = Table::default();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        let thing = TestThing::new(&name, uuid);
        let thing_key = thing.stuff;

        // There was nothing in the table before, so displaced is empty.
        let displaced = t.insert(Name::new(name.to_owned()), uuid, thing);
        table_invariant(&t);
        assert!(displaced.is_none());

        // t now contains thing.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(uuid));

        // Insert new item with different UUID.
        let name2 = "name2";
        let thing2 = TestThing::new(&name2, uuid);
        let thing_key2 = thing2.stuff;
        let displaced = t.insert(Name::new(name2.to_owned()), uuid, thing2);
        table_invariant(&t);

        // The items displaced consist exactly of the first item.
        assert!(displaced.is_some());
        let ref displaced_item = displaced.unwrap();
        assert_eq!(&*displaced_item.0, name);
        assert_eq!(displaced_item.1, uuid);
        assert_eq!(displaced_item.2.stuff, thing_key);

        // The table contains the new item and has no memory of the old.
        assert!(t.contains_uuid(uuid));
        assert!(t.contains_name(name2));
        assert!(!t.contains_name(name));
        assert_eq!(t.get_by_uuid(uuid).unwrap().1.stuff, thing_key2);
        assert_eq!(t.get_by_name(&name2).unwrap().1.stuff, thing_key2);
        assert_eq!(t.len(), 1);
    }
}
<|endoftext|>


<commit_before><commit_msg>added replay trait<commit_after><|endoftext|>


<commit_before><commit_msg>Added an example how to create crosstalk by convolving a matrix with a matrix of impulse responses<commit_after>extern crate hound;
extern crate basic_dsp;
extern crate docopt;

use basic_dsp::*;
use basic_dsp::matrix::*;
use std::i16;
use std::env;
use docopt::Docopt;

const USAGE: &'static str = "
This program takes a source wav file, adds crosstalk
and then writes the result to the dest file.

Crosstalk means that you will hear parts of channel 1 in
channel 2 and vice versa.

Usage: crosstalk <source> <dest>
       crosstalk (--help)

Options:
    -h, --help  Display usage.
";

fn main() {
    let argv = env::args();
    let args = Docopt::new(USAGE)
                  .and_then(|d| d.argv(argv.into_iter()).parse())
                  .unwrap_or_else(|e| e.exit());
    if args.get_bool("-h") || args.get_bool("--help") {
        println!("{}", USAGE);
        std::process::exit(0);
    }

    let source = args.get_str("<source>");
    let dest = args.get_str("<dest>");

    let mut reader = hound::WavReader::open(source).expect("Failed to open input waveform");
    let samples: Vec<f32> = reader.samples::<f32>().map(|x|x.expect("Failed to read sample")).collect();
    assert_eq!(reader.spec().channels, 2);
    assert_eq!(reader.spec().sample_rate, 44100);
    assert_eq!(reader.spec().bits_per_sample, 32);

    let mut complex = samples.to_complex_time_vec();
    let mut channel1 = Vec::new().to_real_time_vec();
    let mut channel2 = Vec::new().to_real_time_vec();
    complex.get_real_imag(&mut channel1, &mut channel2);

    let mut mat = [channel1, channel2].to_mat();
    // The attenuation impulse response also adds an echo (expressed
    // by the value at index 0), but since the echo is only 3 samples and the
    // sample rate is 44.1 kHz the echo is < 1ms and no one will be able to hear that,
    // but it might be interesting enough for an example.
    let attenuation = vec!(0.2, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0).to_real_time_vec();
    let crosstalk = vec!(0.0, 0.0, 0.0, 0.3, 0.0, 0.0, 0.0).to_real_time_vec();

    let imp_resp = [
        [&attenuation, &crosstalk],
        [&crosstalk, &attenuation]
    ];

    let mut buffer = SingleBuffer::new();
    mat.convolve_vector(&mut buffer, &imp_resp).unwrap();

    let rows = &mat.rows();
    complex.set_real_imag(&rows[0], &rows[1])
        .expect("Should never fail, this Vec can be resized");

    let spec = hound::WavSpec {
        channels: 2,
        sample_rate: 44100,
        bits_per_sample: 16,
        sample_format: hound::SampleFormat::Int,
    };

    let mut writer = hound::WavWriter::create(dest, spec).expect("Failed to open output waveform");
    let mut sample_no = 0;
    for sample in &complex[..] {
        let amplitude = i16::MAX as f32;
        let sample = (sample * amplitude) as i16;
        writer.write_sample(sample).expect(&format!("Failed to write sample {}", sample_no));
        sample_no += 1;
    }

    writer.finalize().expect("Failed to close output waveform");

    let len = complex.points();
    println!("Finished processing {} samples", len);
}<|endoftext|>


<commit_before>use header::{Header, Raw, CookiePair, CookieJar};
use std::fmt::{self, Display};
use std::str::from_utf8;

/// `Set-Cookie` header, defined [RFC6265](http://tools.ietf.org/html/rfc6265#section-4.1)
///
/// The Set-Cookie HTTP response header is used to send cookies from the
/// server to the user agent.
///
/// Informally, the Set-Cookie response header contains the header name
/// "Set-Cookie" followed by a ":" and a cookie.  Each cookie begins with
/// a name-value-pair, followed by zero or more attribute-value pairs.
///
/// # ABNF
/// ```plain
///  set-cookie-header = "Set-Cookie:" SP set-cookie-string
/// set-cookie-string = cookie-pair *( ";" SP cookie-av )
/// cookie-pair       = cookie-name "=" cookie-value
/// cookie-name       = token
/// cookie-value      = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
/// cookie-octet      = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
///                       ; US-ASCII characters excluding CTLs,
///                       ; whitespace DQUOTE, comma, semicolon,
///                       ; and backslash
/// token             = <token, defined in [RFC2616], Section 2.2>
///
/// cookie-av         = expires-av / max-age-av / domain-av /
///                    path-av / secure-av / httponly-av /
///                     extension-av
/// expires-av        = "Expires=" sane-cookie-date
/// sane-cookie-date  = <rfc1123-date, defined in [RFC2616], Section 3.3.1>
/// max-age-av        = "Max-Age=" non-zero-digit *DIGIT
///                       ; In practice, both expires-av and max-age-av
///                       ; are limited to dates representable by the
///                       ; user agent.
/// non-zero-digit    = %x31-39
///                       ; digits 1 through 9
/// domain-av         = "Domain=" domain-value
/// domain-value      = <subdomain>
///                       ; defined in [RFC1034], Section 3.5, as
///                       ; enhanced by [RFC1123], Section 2.1
/// path-av           = "Path=" path-value
/// path-value        = <any CHAR except CTLs or ";">
/// secure-av         = "Secure"
/// httponly-av       = "HttpOnly"
/// extension-av      = <any CHAR except CTLs or ";">
/// ```
///
/// # Example values
/// * `SID=31d4d96e407aad42`
/// * `lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT`
/// * `lang=; Expires=Sun, 06 Nov 1994 08:49:37 GMT`
/// * `lang=en-US; Path=/; Domain=example.com`
///
/// # Example
/// ```
/// # extern crate hyper;
/// # extern crate cookie;
/// # fn main() {
/// // extern crate cookie;
///
/// use hyper::header::{Headers, SetCookie};
/// use cookie::Cookie as CookiePair;
///
/// let mut headers = Headers::new();
/// let mut cookie = CookiePair::new("foo".to_owned(), "bar".to_owned());
///
/// cookie.path = Some("/path".to_owned());
/// cookie.domain = Some("example.com".to_owned());
///
/// headers.set(
///     SetCookie(vec![
///         cookie,
///         CookiePair::new("baz".to_owned(), "quux".to_owned()),
///     ])
/// );
/// # }
/// ```
#[derive(Clone, PartialEq, Debug)]
pub struct SetCookie(pub Vec<CookiePair>);

__hyper__deref!(SetCookie => Vec<CookiePair>);

impl Header for SetCookie {
    fn header_name() -> &'static str {
        static NAME: &'static str = "Set-Cookie";
        NAME
    }

    fn parse_header(raw: &Raw) -> ::Result<SetCookie> {
        let mut set_cookies = Vec::with_capacity(raw.len());
        for set_cookies_raw in raw {
            if let Ok(s) = from_utf8(&set_cookies_raw[..]) {
                if let Ok(cookie) = s.parse() {
                    set_cookies.push(cookie);
                }
            }
        }

        if !set_cookies.is_empty() {
            Ok(SetCookie(set_cookies))
        } else {
            Err(::Error::Header)
        }
    }

    fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (i, cookie) in self.0.iter().enumerate() {
            if i != 0 {
                try!(f.write_str("\r\nSet-Cookie: "));
            }
            try!(Display::fmt(cookie, f));
        }
        Ok(())
    }
}

impl SetCookie {
    /// Use this to create SetCookie header from CookieJar using
    /// calculated delta.
    pub fn from_cookie_jar(jar: &CookieJar) -> SetCookie {
        SetCookie(jar.delta())
    }

    /// Use this on client to apply changes from SetCookie to CookieJar.
    /// Note that this will `panic!` if `CookieJar` is not root.
    pub fn apply_to_cookie_jar(&self, jar: &mut CookieJar) {
        for cookie in self.iter() {
            jar.add_original(cookie.clone())
        }
    }
}

#[test]
fn test_parse() {
    let h = Header::parse_header(&"foo=bar; HttpOnly".into());
    let mut c1 = CookiePair::new("foo".to_owned(), "bar".to_owned());
    c1.httponly = true;

    assert_eq!(h.ok(), Some(SetCookie(vec![c1])));
}

#[test]
fn test_fmt() {
    use header::Headers;

    let mut cookie = CookiePair::new("foo".to_owned(), "bar".to_owned());
    cookie.httponly = true;
    cookie.path = Some("/p".to_owned());
    let cookies = SetCookie(vec![cookie, CookiePair::new("baz".to_owned(), "quux".to_owned())]);
    let mut headers = Headers::new();
    headers.set(cookies);

    assert_eq!(
        &headers.to_string()[..],
        "Set-Cookie: foo=bar; HttpOnly; Path=/p\r\nSet-Cookie: baz=quux\r\n");
}

#[test]
fn cookie_jar() {
    let jar = CookieJar::new(b"secret");
    let cookie = CookiePair::new("foo".to_owned(), "bar".to_owned());
    jar.add(cookie);

    let cookies = SetCookie::from_cookie_jar(&jar);

    let mut new_jar = CookieJar::new(b"secret");
    cookies.apply_to_cookie_jar(&mut new_jar);

    assert_eq!(jar.find("foo"), new_jar.find("foo"));
    assert_eq!(jar.iter().collect::<Vec<CookiePair>>(), new_jar.iter().collect::<Vec<CookiePair>>());
}
<commit_msg>docs(headers): remove extraneous space<commit_after>use header::{Header, Raw, CookiePair, CookieJar};
use std::fmt::{self, Display};
use std::str::from_utf8;

/// `Set-Cookie` header, defined [RFC6265](http://tools.ietf.org/html/rfc6265#section-4.1)
///
/// The Set-Cookie HTTP response header is used to send cookies from the
/// server to the user agent.
///
/// Informally, the Set-Cookie response header contains the header name
/// "Set-Cookie" followed by a ":" and a cookie.  Each cookie begins with
/// a name-value-pair, followed by zero or more attribute-value pairs.
///
/// # ABNF
/// ```plain
/// set-cookie-header = "Set-Cookie:" SP set-cookie-string
/// set-cookie-string = cookie-pair *( ";" SP cookie-av )
/// cookie-pair       = cookie-name "=" cookie-value
/// cookie-name       = token
/// cookie-value      = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
/// cookie-octet      = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
///                       ; US-ASCII characters excluding CTLs,
///                       ; whitespace DQUOTE, comma, semicolon,
///                       ; and backslash
/// token             = <token, defined in [RFC2616], Section 2.2>
///
/// cookie-av         = expires-av / max-age-av / domain-av /
///                    path-av / secure-av / httponly-av /
///                     extension-av
/// expires-av        = "Expires=" sane-cookie-date
/// sane-cookie-date  = <rfc1123-date, defined in [RFC2616], Section 3.3.1>
/// max-age-av        = "Max-Age=" non-zero-digit *DIGIT
///                       ; In practice, both expires-av and max-age-av
///                       ; are limited to dates representable by the
///                       ; user agent.
/// non-zero-digit    = %x31-39
///                       ; digits 1 through 9
/// domain-av         = "Domain=" domain-value
/// domain-value      = <subdomain>
///                       ; defined in [RFC1034], Section 3.5, as
///                       ; enhanced by [RFC1123], Section 2.1
/// path-av           = "Path=" path-value
/// path-value        = <any CHAR except CTLs or ";">
/// secure-av         = "Secure"
/// httponly-av       = "HttpOnly"
/// extension-av      = <any CHAR except CTLs or ";">
/// ```
///
/// # Example values
/// * `SID=31d4d96e407aad42`
/// * `lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT`
/// * `lang=; Expires=Sun, 06 Nov 1994 08:49:37 GMT`
/// * `lang=en-US; Path=/; Domain=example.com`
///
/// # Example
/// ```
/// # extern crate hyper;
/// # extern crate cookie;
/// # fn main() {
/// // extern crate cookie;
///
/// use hyper::header::{Headers, SetCookie};
/// use cookie::Cookie as CookiePair;
///
/// let mut headers = Headers::new();
/// let mut cookie = CookiePair::new("foo".to_owned(), "bar".to_owned());
///
/// cookie.path = Some("/path".to_owned());
/// cookie.domain = Some("example.com".to_owned());
///
/// headers.set(
///     SetCookie(vec![
///         cookie,
///         CookiePair::new("baz".to_owned(), "quux".to_owned()),
///     ])
/// );
/// # }
/// ```
#[derive(Clone, PartialEq, Debug)]
pub struct SetCookie(pub Vec<CookiePair>);

__hyper__deref!(SetCookie => Vec<CookiePair>);

impl Header for SetCookie {
    fn header_name() -> &'static str {
        static NAME: &'static str = "Set-Cookie";
        NAME
    }

    fn parse_header(raw: &Raw) -> ::Result<SetCookie> {
        let mut set_cookies = Vec::with_capacity(raw.len());
        for set_cookies_raw in raw {
            if let Ok(s) = from_utf8(&set_cookies_raw[..]) {
                if let Ok(cookie) = s.parse() {
                    set_cookies.push(cookie);
                }
            }
        }

        if !set_cookies.is_empty() {
            Ok(SetCookie(set_cookies))
        } else {
            Err(::Error::Header)
        }
    }

    fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (i, cookie) in self.0.iter().enumerate() {
            if i != 0 {
                try!(f.write_str("\r\nSet-Cookie: "));
            }
            try!(Display::fmt(cookie, f));
        }
        Ok(())
    }
}

impl SetCookie {
    /// Use this to create SetCookie header from CookieJar using
    /// calculated delta.
    pub fn from_cookie_jar(jar: &CookieJar) -> SetCookie {
        SetCookie(jar.delta())
    }

    /// Use this on client to apply changes from SetCookie to CookieJar.
    /// Note that this will `panic!` if `CookieJar` is not root.
    pub fn apply_to_cookie_jar(&self, jar: &mut CookieJar) {
        for cookie in self.iter() {
            jar.add_original(cookie.clone())
        }
    }
}

#[test]
fn test_parse() {
    let h = Header::parse_header(&"foo=bar; HttpOnly".into());
    let mut c1 = CookiePair::new("foo".to_owned(), "bar".to_owned());
    c1.httponly = true;

    assert_eq!(h.ok(), Some(SetCookie(vec![c1])));
}

#[test]
fn test_fmt() {
    use header::Headers;

    let mut cookie = CookiePair::new("foo".to_owned(), "bar".to_owned());
    cookie.httponly = true;
    cookie.path = Some("/p".to_owned());
    let cookies = SetCookie(vec![cookie, CookiePair::new("baz".to_owned(), "quux".to_owned())]);
    let mut headers = Headers::new();
    headers.set(cookies);

    assert_eq!(
        &headers.to_string()[..],
        "Set-Cookie: foo=bar; HttpOnly; Path=/p\r\nSet-Cookie: baz=quux\r\n");
}

#[test]
fn cookie_jar() {
    let jar = CookieJar::new(b"secret");
    let cookie = CookiePair::new("foo".to_owned(), "bar".to_owned());
    jar.add(cookie);

    let cookies = SetCookie::from_cookie_jar(&jar);

    let mut new_jar = CookieJar::new(b"secret");
    cookies.apply_to_cookie_jar(&mut new_jar);

    assert_eq!(jar.find("foo"), new_jar.find("foo"));
    assert_eq!(jar.iter().collect::<Vec<CookiePair>>(), new_jar.iter().collect::<Vec<CookiePair>>());
}
<|endoftext|>


<commit_before><commit_msg>test that compare-exchange-weak-failure-rate=0.0 means what it says<commit_after>// compile-flags: -Zmiri-compare-exchange-weak-failure-rate=0.0
use std::sync::atomic::{AtomicBool, Ordering::*};

// Ensure that compare_exchange_weak never fails.
fn main() {
    let atomic = AtomicBool::new(false);
    let tries = 100;
    for _ in 0..tries {
        let cur = atomic.load(Relaxed);
        // Try (weakly) to flip the flag.
        if atomic.compare_exchange_weak(cur, !cur, Relaxed, Relaxed).is_err() {
            // We failed. Avoid panic machinery as that uses atomics/locks.
            eprintln!("compare_exchange_weak failed");
            std::process::abort();
        }
    }
}
<|endoftext|>


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

// compile-flags: -Z parse-only -Z continue-parse-after-error

pub fn test() {
    foo(|_|) //~ ERROR unexpected token: `)`
}

fn main() { }
<|endoftext|>


<commit_before><commit_msg>04 - mutability<commit_after>fn main() {
    let immutable_variable = 1i;
    let mut mutable_variable = 1i;

    println!("Before mutation: {}", mutable_variable);

    // Ok
    mutable_variable += 1;

    println!("After mutation: {}", mutable_variable);

    println!("This is immutable: {}", immutable_variable);

    // Error!
    // immutable_variable += 1;
}
<|endoftext|>


<commit_before><commit_msg>from_utf8 now returns Result instead of Option<commit_after><|endoftext|>


<commit_before><commit_msg>preload history cleanup<commit_after><|endoftext|>


<commit_before><commit_msg>Add core data structures for Version and VersionReq<commit_after>#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Version {
    pub major: u64,
    pub minor: u64,
    pub patch: u64,
    pub pre: String,
    pub build: String,
}

#[derive(Default, Clone, Eq, PartialEq, Hash, Debug)]
pub struct VersionReq {
    pub comparators: Vec<Comparator>,
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct Comparator {
    pub op: Op,
    pub major: u64,
    pub minor: Option<u64>,
    pub patch: Option<u64>,
    pub pre: String,
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Op {
    Exact,
    Greater,
    GreaterEq,
    Less,
    LessEq,
    Tilde,
    Caret,
    Wildcard,
}
<|endoftext|>


<commit_before><commit_msg>Rustfmt lib<commit_after><|endoftext|>


<commit_before><commit_msg>Add #![warn(missing_docs)]<commit_after><|endoftext|>


<commit_before><commit_msg>Work on phone_number_util<commit_after><|endoftext|>


<commit_before><commit_msg>fix(lib): UserRWX -> USER_RWX, add #![feature(slicing_syntax)]<commit_after><|endoftext|>


<commit_before><commit_msg>Added files via upload<commit_after>//
<|endoftext|>


<commit_before><commit_msg>Add RNA test from Rosalind challenge<commit_after>pub fn dna_to_rna_str(dna: &str ) -> ~str {
    std::str::replace(dna,"T", "U")
}

fn main() {
    let dna = ~"ACTG";
    let rna = dna_to_rna_str(dna);
    println!("DNA: {:}", dna);
    println!("RNA: {:}", rna);
}

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

    #[test]
    fn first_test(){
        let dna = ~"GATGGAACTTGACTACGTAAATT";
        assert_eq!(dna_to_rna_str(dna), ~"GAUGGAACUUGACUACGUAAAUU");
    }

}<|endoftext|>


<commit_before><commit_msg>Have FtpStream contain an SslContext since it can be cloned, unlike Ssl, and simplify some code<commit_after><|endoftext|>


<commit_before><commit_msg>Fix bug printing incorrect diagnostic lines<commit_after><|endoftext|>