<commit_before>//! Generate human readable digests for UUIDs
//!
//! Based on https://github.com/zacharyvoase/humanhash

extern crate uuid;

use uuid::Uuid;

const DEFAULT_WORDLIST: &'static [ &'static str ] = &[
    "ack", "alabama", "alanine", "alaska", "alpha", "angel", "apart", "april",
    "arizona", "arkansas", "artist", "asparagus", "aspen", "august", "autumn",
    "avocado", "bacon", "bakerloo", "batman", "beer", "berlin", "beryllium",
    "black", "blossom", "blue", "bluebird", "bravo", "bulldog", "burger",
    "butter", "california", "carbon", "cardinal", "carolina", "carpet", "cat",
    "ceiling", "charlie", "chicken", "coffee", "cola", "cold", "colorado",
    "comet", "connecticut", "crazy", "cup", "dakota", "december", "delaware",
    "delta", "diet", "don", "double", "early", "earth", "east", "echo",
    "edward", "eight", "eighteen", "eleven", "emma", "enemy", "equal",
    "failed", "fanta", "fifteen", "fillet", "finch", "fish", "five", "fix",
    "floor", "florida", "football", "four", "fourteen", "foxtrot", "freddie",
    "friend", "fruit", "gee", "georgia", "glucose", "golf", "green", "grey",
    "hamper", "happy", "harry", "hawaii", "helium", "high", "hot", "hotel",
    "hydrogen", "idaho", "illinois", "india", "indigo", "ink", "iowa",
    "island", "item", "jersey", "jig", "johnny", "juliet", "july", "jupiter",
    "kansas", "kentucky", "kilo", "king", "kitten", "lactose", "lake", "lamp",
    "lemon", "leopard", "lima", "lion", "lithium", "london", "louisiana",
    "low", "magazine", "magnesium", "maine", "mango", "march", "mars",
    "maryland", "massachusetts", "may", "mexico", "michigan", "mike",
    "minnesota", "mirror", "mississippi", "missouri", "mobile", "mockingbird",
    "monkey", "montana", "moon", "mountain", "muppet", "music", "nebraska",
    "neptune", "network", "nevada", "nine", "nineteen", "nitrogen", "north",
    "november", "nuts", "october", "ohio", "oklahoma", "one", "orange",
    "oranges", "oregon", "oscar", "oven", "oxygen", "papa", "paris", "pasta",
    "pennsylvania", "pip", "pizza", "pluto", "potato", "princess", "purple",
    "quebec", "queen", "quiet", "red", "river", "robert", "robin", "romeo",
    "rugby", "sad", "salami", "saturn", "september", "seven", "seventeen",
    "shade", "sierra", "single", "sink", "six", "sixteen", "skylark", "snake",
    "social", "sodium", "solar", "south", "spaghetti", "speaker", "spring",
    "stairway", "steak", "stream", "summer", "sweet", "table", "tango", "ten",
    "tennessee", "tennis", "texas", "thirteen", "three", "timing", "triple",
    "twelve", "twenty", "two", "uncle", "undress", "uniform", "uranus", "utah",
    "vegan", "venus", "vermont", "victor", "video", "violet", "virginia",
    "washington", "west", "whiskey", "white", "william", "winner", "winter",
    "wisconsin", "wolfram", "wyoming", "xray", "yankee", "yellow", "zebra",
    "zulu" ];

fn compress(bytes: &[u8], target: usize) -> Vec<u8> {
    let seg_size = bytes.len() / target;
    bytes
        .chunks(seg_size)
        .map(|c| {
            c.iter().fold(0u8, |acc, &x| acc ^ x)
        })
        .collect::<Vec<u8>>()
}

pub fn digest_four(uuid: &Uuid) -> String {
    compress(uuid.as_bytes(), 4)
        .iter()
        .map(|&x| DEFAULT_WORDLIST[x as usize].to_string())
        .collect::<Vec<String>>()
        .join("-")
}

#[cfg(test)]
mod tests {
    use super::uuid::Uuid;
    use super::DEFAULT_WORDLIST;
    use super::digest_four;

    const TEST_UUID: &'static str = "bc0f47f93dd046578d7eee645999b95e";

    #[test]
    fn it_works() {
        let tuid = Uuid::parse_str(TEST_UUID).unwrap();

        let x = digest_four(&tuid);

        assert_eq!(x, "august-yankee-lima-coffee");
    }
}
<commit_msg>Cargo fmt<commit_after>//! Generate human readable digests for UUIDs
//!
//! Based on https://github.com/zacharyvoase/humanhash

extern crate uuid;

use uuid::Uuid;

const DEFAULT_WORDLIST: &'static [ &'static str ] = &[
    "ack", "alabama", "alanine", "alaska", "alpha", "angel", "apart", "april",
    "arizona", "arkansas", "artist", "asparagus", "aspen", "august", "autumn",
    "avocado", "bacon", "bakerloo", "batman", "beer", "berlin", "beryllium",
    "black", "blossom", "blue", "bluebird", "bravo", "bulldog", "burger",
    "butter", "california", "carbon", "cardinal", "carolina", "carpet", "cat",
    "ceiling", "charlie", "chicken", "coffee", "cola", "cold", "colorado",
    "comet", "connecticut", "crazy", "cup", "dakota", "december", "delaware",
    "delta", "diet", "don", "double", "early", "earth", "east", "echo",
    "edward", "eight", "eighteen", "eleven", "emma", "enemy", "equal",
    "failed", "fanta", "fifteen", "fillet", "finch", "fish", "five", "fix",
    "floor", "florida", "football", "four", "fourteen", "foxtrot", "freddie",
    "friend", "fruit", "gee", "georgia", "glucose", "golf", "green", "grey",
    "hamper", "happy", "harry", "hawaii", "helium", "high", "hot", "hotel",
    "hydrogen", "idaho", "illinois", "india", "indigo", "ink", "iowa",
    "island", "item", "jersey", "jig", "johnny", "juliet", "july", "jupiter",
    "kansas", "kentucky", "kilo", "king", "kitten", "lactose", "lake", "lamp",
    "lemon", "leopard", "lima", "lion", "lithium", "london", "louisiana",
    "low", "magazine", "magnesium", "maine", "mango", "march", "mars",
    "maryland", "massachusetts", "may", "mexico", "michigan", "mike",
    "minnesota", "mirror", "mississippi", "missouri", "mobile", "mockingbird",
    "monkey", "montana", "moon", "mountain", "muppet", "music", "nebraska",
    "neptune", "network", "nevada", "nine", "nineteen", "nitrogen", "north",
    "november", "nuts", "october", "ohio", "oklahoma", "one", "orange",
    "oranges", "oregon", "oscar", "oven", "oxygen", "papa", "paris", "pasta",
    "pennsylvania", "pip", "pizza", "pluto", "potato", "princess", "purple",
    "quebec", "queen", "quiet", "red", "river", "robert", "robin", "romeo",
    "rugby", "sad", "salami", "saturn", "september", "seven", "seventeen",
    "shade", "sierra", "single", "sink", "six", "sixteen", "skylark", "snake",
    "social", "sodium", "solar", "south", "spaghetti", "speaker", "spring",
    "stairway", "steak", "stream", "summer", "sweet", "table", "tango", "ten",
    "tennessee", "tennis", "texas", "thirteen", "three", "timing", "triple",
    "twelve", "twenty", "two", "uncle", "undress", "uniform", "uranus", "utah",
    "vegan", "venus", "vermont", "victor", "video", "violet", "virginia",
    "washington", "west", "whiskey", "white", "william", "winner", "winter",
    "wisconsin", "wolfram", "wyoming", "xray", "yankee", "yellow", "zebra",
    "zulu" ];

fn compress(bytes: &[u8], target: usize) -> Vec<u8> {
    let seg_size = bytes.len() / target;
    bytes.chunks(seg_size)
        .map(|c| c.iter().fold(0u8, |acc, &x| acc ^ x))
        .collect::<Vec<u8>>()
}

pub fn digest_four(uuid: &Uuid) -> String {
    compress(uuid.as_bytes(), 4)
        .iter()
        .map(|&x| DEFAULT_WORDLIST[x as usize].to_string())
        .collect::<Vec<String>>()
        .join("-")
}

#[cfg(test)]
mod tests {
    use super::uuid::Uuid;
    use super::DEFAULT_WORDLIST;
    use super::digest_four;

    const TEST_UUID: &'static str = "bc0f47f93dd046578d7eee645999b95e";

    #[test]
    fn it_works() {
        let tuid = Uuid::parse_str(TEST_UUID).unwrap();

        let x = digest_four(&tuid);

        assert_eq!(x, "august-yankee-lima-coffee");
    }
}
<|endoftext|>


<commit_before>//! # Terminal progress bar for Rust
//!
//! Console progress bar for Rust Inspired from [pb](http://github.com/cheggaaa/pb), support and
//! tested on MacOS, Linux and Windows
//!
//! ![Screenshot](https://raw.githubusercontent.com/a8m/pb/master/gif/rec_v3.gif)
//!
//! [Documentation](http://a8m.github.io/pb/doc/pbr/index.html)
//!
//! ### Examples
//! 1. simple example
//!
//! ```ignore
//! extern crate pbr;
//!
//! use pbr::ProgressBar;
//! use std::thread;
//!
//! fn main() {
//!     let count = 1000;
//!     let mut pb = ProgressBar::new(count);
//!     pb.format("╢▌▌░╟");
//!     for _ in 0..count {
//!         pb.inc();
//!         thread::sleep_ms(200);
//!     }
//!     pb.finish_print("done");
//! }
//! ```
//!
//! 2. MultiBar example. see full example [here](https://github.com/a8m/pb/blob/master/examples/multi.rs)
//! ```ignore
//! extern crate pbr;
//!
//! use std::thread;
//! use pbr::MultiBar;
//! use std::time::Duration;
//!
//! fn main() {
//!     let mut mb = MultiBar::new();
//!     let count = 100;
//!     mb.println("Application header:");
//!
//!     let mut p1 = mb.create_bar(count);
//!     let _ = thread::spawn(move || {
//!         for _ in 0..count {
//!             p1.inc();
//!             thread::sleep(Duration::from_millis(100));
//!         }
//!         // notify the multibar that this bar finished.
//!         p1.finish();
//!     });
//!
//!     mb.println("add a separator between the two bars");
//!
//!     let mut p2 = mb.create_bar(count * 2);
//!     let _ = thread::spawn(move || {
//!         for _ in 0..count * 2 {
//!             p2.inc();
//!             thread::sleep(Duration::from_millis(100));
//!         }
//!         // notify the multibar that this bar finished.
//!         p2.finish();
//!     });
//!
//!     // start listen to all bars changes.
//!     // this is a blocking operation, until all bars will finish.
//!     // to ignore blocking, you can run it in a different thread.
//!     mb.listen();
//! }
//! ```
//!
//! 3. Broadcast writing(simple file copying)
//!
//! ```ignore
//! #![feature(io)]
//! extern crate pbr;
//!
//! use std::io::copy;
//! use std::io::prelude::*;
//! use std::fs::File;
//! use pbr::{ProgressBar, Units};
//!
//! fn main() {
//!     let mut file = File::open("/usr/share/dict/words").unwrap();
//!     let n_bytes = file.metadata().unwrap().len() as usize;
//!     let mut pb = ProgressBar::new(n_bytes);
//!     pb.set_units(Units::Bytes);
//!     let mut handle = File::create("copy-words").unwrap().broadcast(&mut pb);
//!     copy(&mut file, &mut handle).unwrap();
//!     pb.finish_print("done");
//! }
//! ```

// Macro for writing to the giving writer.
// Used in both pb.rs and multi.rs modules.
//
// # Examples
//
// ```
// let w = io::stdout();
// printfl!(w, "");
// printfl!(w, "\r{}", out);
//
// ```
macro_rules! printfl {
   ($w:expr, $($tt:tt)*) => {{
        $w.write(&format!($($tt)*).as_bytes()).ok().expect("write() fail");
        $w.flush().ok().expect("flush() fail");
    }}
}

#[macro_use]
extern crate time;
mod tty;
mod pb;
mod multi;
pub use pb::{ProgressBar, Units};
pub use multi::MultiBar;
use std::io::{Write, Stdout, stdout};

pub struct PbIter<T, I>
    where I: Iterator,
          T: Write
{
    iter: I,
    progress_bar: ProgressBar<T>,
}

impl<I> PbIter<Stdout, I>
    where I: Iterator
{
    pub fn new(iter: I) -> Self {
        Self::on(stdout(), iter)
    }
}

impl<T, I> PbIter<T, I>
    where I: Iterator,
          T: Write
{
    pub fn on(handle: T, iter: I) -> Self {
        let size = iter.size_hint().0;
        PbIter {
            iter: iter,
            progress_bar: ProgressBar::on(handle, size as u64),
        }
    }
}

impl<T, I> Iterator for PbIter<T, I>
    where I: Iterator,
          T: Write
{
    type Item = I::Item;

    fn next(&mut self) -> Option<I::Item> {
        match self.iter.next() {
            Some(i) => {
                self.progress_bar.inc();
                Some(i)
            }
            None => None,
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}
<commit_msg>docs: fix code highlighting<commit_after>//! # Terminal progress bar for Rust
//!
//! Console progress bar for Rust Inspired from [pb](http://github.com/cheggaaa/pb), support and
//! tested on MacOS, Linux and Windows
//!
//! ![Screenshot](https://raw.githubusercontent.com/a8m/pb/master/gif/rec_v3.gif)
//!
//! [Documentation](http://a8m.github.io/pb/doc/pbr/index.html)
//!
//! ### Examples
//! 1. simple example
//!
//! ```ignore
//! extern crate pbr;
//!
//! use pbr::ProgressBar;
//! use std::thread;
//!
//! fn main() {
//!     let count = 1000;
//!     let mut pb = ProgressBar::new(count);
//!     pb.format("╢▌▌░╟");
//!     for _ in 0..count {
//!         pb.inc();
//!         thread::sleep_ms(200);
//!     }
//!     pb.finish_print("done");
//! }
//! ```
//!
//! 2. MultiBar example. see full example [here](https://github.com/a8m/pb/blob/master/examples/multi.rs)
//!
//! ```ignore
//! extern crate pbr;
//!
//! use std::thread;
//! use pbr::MultiBar;
//! use std::time::Duration;
//!
//! fn main() {
//!     let mut mb = MultiBar::new();
//!     let count = 100;
//!     mb.println("Application header:");
//!
//!     let mut p1 = mb.create_bar(count);
//!     let _ = thread::spawn(move || {
//!         for _ in 0..count {
//!             p1.inc();
//!             thread::sleep(Duration::from_millis(100));
//!         }
//!         // notify the multibar that this bar finished.
//!         p1.finish();
//!     });
//!
//!     mb.println("add a separator between the two bars");
//!
//!     let mut p2 = mb.create_bar(count * 2);
//!     let _ = thread::spawn(move || {
//!         for _ in 0..count * 2 {
//!             p2.inc();
//!             thread::sleep(Duration::from_millis(100));
//!         }
//!         // notify the multibar that this bar finished.
//!         p2.finish();
//!     });
//!
//!     // start listen to all bars changes.
//!     // this is a blocking operation, until all bars will finish.
//!     // to ignore blocking, you can run it in a different thread.
//!     mb.listen();
//! }
//! ```
//!
//! 3. Broadcast writing(simple file copying)
//!
//! ```ignore
//! #![feature(io)]
//! extern crate pbr;
//!
//! use std::io::copy;
//! use std::io::prelude::*;
//! use std::fs::File;
//! use pbr::{ProgressBar, Units};
//!
//! fn main() {
//!     let mut file = File::open("/usr/share/dict/words").unwrap();
//!     let n_bytes = file.metadata().unwrap().len() as usize;
//!     let mut pb = ProgressBar::new(n_bytes);
//!     pb.set_units(Units::Bytes);
//!     let mut handle = File::create("copy-words").unwrap().broadcast(&mut pb);
//!     copy(&mut file, &mut handle).unwrap();
//!     pb.finish_print("done");
//! }
//! ```

// Macro for writing to the giving writer.
// Used in both pb.rs and multi.rs modules.
//
// # Examples
//
// ```
// let w = io::stdout();
// printfl!(w, "");
// printfl!(w, "\r{}", out);
//
// ```
macro_rules! printfl {
   ($w:expr, $($tt:tt)*) => {{
        $w.write(&format!($($tt)*).as_bytes()).ok().expect("write() fail");
        $w.flush().ok().expect("flush() fail");
    }}
}

#[macro_use]
extern crate time;
mod tty;
mod pb;
mod multi;
pub use pb::{ProgressBar, Units};
pub use multi::MultiBar;
use std::io::{Write, Stdout, stdout};

pub struct PbIter<T, I>
    where I: Iterator,
          T: Write
{
    iter: I,
    progress_bar: ProgressBar<T>,
}

impl<I> PbIter<Stdout, I>
    where I: Iterator
{
    pub fn new(iter: I) -> Self {
        Self::on(stdout(), iter)
    }
}

impl<T, I> PbIter<T, I>
    where I: Iterator,
          T: Write
{
    pub fn on(handle: T, iter: I) -> Self {
        let size = iter.size_hint().0;
        PbIter {
            iter: iter,
            progress_bar: ProgressBar::on(handle, size as u64),
        }
    }
}

impl<T, I> Iterator for PbIter<T, I>
    where I: Iterator,
          T: Write
{
    type Item = I::Item;

    fn next(&mut self) -> Option<I::Item> {
        match self.iter.next() {
            Some(i) => {
                self.progress_bar.inc();
                Some(i)
            }
            None => None,
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}
<|endoftext|>


<commit_before>use std::io::Command;
use std::os;
use std::str;

pub struct Options {
    pub statik: bool,
}

pub fn find_library(name: &str) -> Result<(), String> {
    find_library_opts(name, &default_options(name))
}

pub fn find_library_opts(name: &str, options: &Options) -> Result<(), String> {
    if os::getenv(format!("{}_NO_PKG_CONFIG", envify(name)).as_slice()).is_some() {
        return Err(format!("pkg-config requested to be aborted for {}", name))
    }
    let mut cmd = Command::new("pkg-config");
    if options.statik {
        cmd.arg("--static");
    }
    cmd.arg("--libs")
       .env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1")
       .arg(name);
    let out = try!(cmd.output().map_err(|e| {
        format!("failed to run `{}`: {}", cmd, e)
    }));
    let stdout = str::from_utf8(out.output.as_slice()).unwrap();
    let stderr = str::from_utf8(out.error.as_slice()).unwrap();
    if !out.status.success() {
        let mut msg = format!("`{}` did not exit successfully: {}", cmd,
                              out.status);
        if stdout.len() > 0 {
            msg.push_str("\n--- stdout\n");
            msg.push_str(stdout);
        }
        if stderr.len() > 0 {
            msg.push_str("\n--- stderr\n");
            msg.push_str(stderr);
        }
        return Err(msg)
    }

    for arg in stdout.split(' ').filter(|l| !l.is_empty() && l.len() > 2) {
        let val = arg.slice_from(2);
        if arg.starts_with("-l") {
            if options.statik {
                println!("cargo:rustc-flags=-l {}:static", val);
            } else {
                println!("cargo:rustc-flags=-l {}", val);
            }
        } else if arg.starts_with("-L") {
            println!("cargo:rustc-flags=-L {}", val);
        }
    }
    Ok(())
}

pub fn default_options(name: &str) -> Options {
    let name = envify(name);
    let statik = if os::getenv(format!("{}_STATIC", name).as_slice()).is_some() {
        true
    } else if os::getenv(format!("{}_DYNAMIC", name).as_slice()).is_some() {
        false
    } else if os::getenv("PKG_CONFIG_ALL_STATIC").is_some() {
        true
    } else if os::getenv("PKG_CONFIG_ALL_DYNAMIC").is_some() {
        false
    } else {
        false
    };
    Options { statik: statik }
}

fn envify(name: &str) -> String {
    name.chars().map(|c| c.to_uppercase()).map(|c| if c == '-' {'_'} else {c})
        .collect()
}
<commit_msg>Add an atleast-version config option<commit_after>use std::io::Command;
use std::os;
use std::str;

pub struct Options {
    pub statik: bool,
    pub atleast_version: Option<String>,
}

pub fn find_library(name: &str) -> Result<(), String> {
    find_library_opts(name, &default_options(name))
}

pub fn find_library_opts(name: &str, options: &Options) -> Result<(), String> {
    if os::getenv(format!("{}_NO_PKG_CONFIG", envify(name)).as_slice()).is_some() {
        return Err(format!("pkg-config requested to be aborted for {}", name))
    }
    let mut cmd = Command::new("pkg-config");
    if options.statik {
        cmd.arg("--static");
    }
    cmd.arg("--libs")
       .env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1")
       .arg(name);
    match options.atleast_version {
        Some(ref v) => { cmd.arg(format!("--atleast-version={}", v)); }
        None => {}
    }
    let out = try!(cmd.output().map_err(|e| {
        format!("failed to run `{}`: {}", cmd, e)
    }));
    let stdout = str::from_utf8(out.output.as_slice()).unwrap();
    let stderr = str::from_utf8(out.error.as_slice()).unwrap();
    if !out.status.success() {
        let mut msg = format!("`{}` did not exit successfully: {}", cmd,
                              out.status);
        if stdout.len() > 0 {
            msg.push_str("\n--- stdout\n");
            msg.push_str(stdout);
        }
        if stderr.len() > 0 {
            msg.push_str("\n--- stderr\n");
            msg.push_str(stderr);
        }
        return Err(msg)
    }

    for arg in stdout.split(' ').filter(|l| !l.is_empty() && l.len() > 2) {
        let val = arg.slice_from(2);
        if arg.starts_with("-l") {
            if options.statik {
                println!("cargo:rustc-flags=-l {}:static", val);
            } else {
                println!("cargo:rustc-flags=-l {}", val);
            }
        } else if arg.starts_with("-L") {
            println!("cargo:rustc-flags=-L {}", val);
        }
    }
    Ok(())
}

pub fn default_options(name: &str) -> Options {
    let name = envify(name);
    let statik = if os::getenv(format!("{}_STATIC", name).as_slice()).is_some() {
        true
    } else if os::getenv(format!("{}_DYNAMIC", name).as_slice()).is_some() {
        false
    } else if os::getenv("PKG_CONFIG_ALL_STATIC").is_some() {
        true
    } else if os::getenv("PKG_CONFIG_ALL_DYNAMIC").is_some() {
        false
    } else {
        false
    };
    Options { statik: statik, atleast_version: None }
}

fn envify(name: &str) -> String {
    name.chars().map(|c| c.to_uppercase()).map(|c| if c == '-' {'_'} else {c})
        .collect()
}
<|endoftext|>


<commit_before>extern crate md5;

pub fn puzzle(door_id: &str) -> String {
    let mut answer = String::new();
    let mut index = 0;

    for _ in 0..9 {
        let (new_index, next_char) = next_interesting_md5(door_id, index);
        index = new_index + 1;
        answer.push(next_char);
    }
    answer
}

pub fn next_interesting_md5(door_id: &str, mut index: u32) -> (u32, char) {
    loop {
        let candidate = format!("{}{}", door_id, index);

        let digest = String::from_utf8(
            md5::compute(candidate.as_bytes()).into_iter().cloned().collect()
        ).expect("creating string failed");

        if digest.starts_with("00000") {
            return (index, digest.chars().nth(5).expect("no 5th char"))
        } else {
            index += 1;
        }
    }

    (0, 'a')
}

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

}
<commit_msg>Remove unreachable code<commit_after>extern crate md5;

pub fn puzzle(door_id: &str) -> String {
    let mut answer = String::new();
    let mut index = 0;

    for _ in 0..9 {
        let (new_index, next_char) = next_interesting_md5(door_id, index);
        index = new_index + 1;
        answer.push(next_char);
    }
    answer
}

pub fn next_interesting_md5(door_id: &str, mut index: u32) -> (u32, char) {
    loop {
        let candidate = format!("{}{}", door_id, index);

        let digest = String::from_utf8(
            md5::compute(candidate.as_bytes()).into_iter().cloned().collect()
        ).expect("creating string failed");

        if digest.starts_with("00000") {
            return (index, digest.chars().nth(5).expect("no 5th char"))
        } else {
            index += 1;
        }
    }
}

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

}
<|endoftext|>


<commit_before>use std::error::Error;
use std::str::FromStr;

pub fn puzzle(input: &str) -> i32 {
    let instructions: Result<Vec<_>, _> = input.lines().map(|line| line.trim().parse()).collect();
    let instructions = instructions.expect("couldn't parse instructions");
    let mut machine = Machine::new();
    machine.execute(&instructions);
    machine.value_of(Register::A)
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Instruction {
    Copy(FromLocation, Register),
    Increment(Register),
    Decrement(Register),
    JumpNonZero(Register, i32),
}

impl FromStr for Instruction {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut parts = s.split_whitespace();
        match parts.next() {
            Some("cpy") => Ok(
                Instruction::Copy(
                    parts.next().ok_or("no from location")?.parse()?,
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            Some("inc") => Ok(
                Instruction::Increment(
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            Some("dec") => Ok(
                Instruction::Decrement(
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            Some("jnz") => Ok(
                Instruction::JumpNonZero(
                    parts.next().ok_or("no register")?.parse()?,
                    parts.next().ok_or("no offset")?.parse()?
                )
            ),
            Some(other) => Err(format!("Unknown instruction: {}", other).into()),
            None => Err("Instruction missing".into()),
        }
    }
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum FromLocation {
    Integer(i32),
    Register(Register),
}

impl FromStr for FromLocation {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        s.parse().map(FromLocation::Integer)
                 .or_else(|_| s.parse().map(FromLocation::Register))
    }
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Register {
    A,
    B,
    C,
    D,
}

impl FromStr for Register {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Register::*;
        match s {
            "a" => Ok(A),
            "b" => Ok(B),
            "c" => Ok(C),
            "d" => Ok(D),
            other => Err(format!("Unknown register {}", other).into()),
        }
    }
}

pub struct Machine {
    registers: [i32; 4],
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            registers: [0; 4],
        }
    }

    fn execute(&mut self, instructions: &[Instruction]) {
        let mut program_counter = 0;
        while let Some(&instruction) = instructions.get(program_counter) {
            let mut jump = 0;
            match instruction {
                Instruction::Copy(
                    FromLocation::Integer(i),
                    to
                ) => {
                    let index = Machine::register_index(to);
                    self.registers[index] = i;
                },
                Instruction::Copy(FromLocation::Register(from), to) => {
                    let index_from = Machine::register_index(from);
                    let index_to = Machine::register_index(to);
                    self.registers[index_to] = self.registers[index_from];
                },
                Instruction::Increment(register) => {
                    let index = Machine::register_index(register);
                    self.registers[index] += 1;
                },
                Instruction::Decrement(register) => {
                    let index = Machine::register_index(register);
                    self.registers[index] -= 1;
                },
                Instruction::JumpNonZero(register, offset) => {
                    let index = Machine::register_index(register);
                    if self.registers[index] != 0 {
                        jump = offset;
                    }
                },
            }
            let next_pc = program_counter as i32 + 1 + jump;
            if next_pc < 0 {
                panic!("Jumped too far back!")
            }
            program_counter = next_pc as usize;
        }
    }

    fn register_index(register: Register) -> usize {
        use Register::*;
        match register {
            A => 0,
            B => 1,
            C => 2,
            D => 3,
        }
    }

    fn value_of(&self, register: Register) -> i32 {
        let index = Machine::register_index(register);
        self.registers[index]
    }
}

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

    #[test]
    fn parse_cpy() {
        let instr: Instruction = "cpy 41 a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Copy(FromLocation::Integer(41), Register::A)
        );
    }

    #[test]
    fn parse_cpy_register() {
        let instr: Instruction = "cpy a c".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Copy(
                FromLocation::Register(Register::A),
                Register::C,
            )
        );
    }

    #[test]
    fn parse_inc() {
        let instr: Instruction = "inc a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Increment(Register::A)
        );
    }

    #[test]
    fn parse_dec() {
        let instr: Instruction = "dec a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Decrement(Register::A)
        );
    }

    #[test]
    fn parse_jnz() {
        let instr: Instruction = "jnz a 2".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::JumpNonZero(Register::A, 2)
        );
    }

    #[test]
    fn execute_copy() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Copy(
                    FromLocation::Integer(5),
                    Register::A,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::A), 5);
    }

    #[test]
    fn execute_copy_register() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Copy(
                    FromLocation::Integer(5),
                    Register::A,
                ),
                Instruction::Copy(
                    FromLocation::Register(Register::A),
                    Register::B,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::B), 5);
    }

    #[test]
    fn execute_increment() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Increment(
                    Register::C,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::C), 1);
    }

    #[test]
    fn execute_decrement() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Decrement(
                    Register::D,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::D), -1);
    }

    #[test]
    fn execute_jnz_when_zero() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                // D should be 0, jump doesn't happen
                Instruction::JumpNonZero(Register::D, 2),
                Instruction::Increment(
                    Register::A,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::A), 1);
    }

    #[test]
    fn execute_jnz_when_non_zero() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Decrement(
                    Register::D,
                ),
                Instruction::JumpNonZero(Register::D, 2),
                Instruction::Increment(
                    Register::A,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::A), 0);
    }

    #[test]
    fn sample() {
        let input = "cpy 41 a
            inc a
            inc a
            dec a
            jnz a 2
            dec a";
        assert_eq!(puzzle(input), 42);
    }
}
<commit_msg>Oh hey jnz can take values too<commit_after>use std::error::Error;
use std::str::FromStr;

pub fn puzzle(input: &str) -> i32 {
    let instructions: Result<Vec<_>, _> = input.lines().map(|line| line.trim().parse()).collect();
    let instructions = instructions.expect("couldn't parse instructions");
    let mut machine = Machine::new();
    machine.execute(&instructions);
    machine.value_of(Register::A)
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Instruction {
    Copy(FromLocation, Register),
    Increment(Register),
    Decrement(Register),
    JumpNonZero(FromLocation, i32),
}

impl FromStr for Instruction {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        println!("parsing instruction: {}", s);

        let mut parts = s.split_whitespace();
        match parts.next() {
            Some("cpy") => Ok(
                Instruction::Copy(
                    parts.next().ok_or("no from location")?.parse()?,
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            Some("inc") => Ok(
                Instruction::Increment(
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            Some("dec") => Ok(
                Instruction::Decrement(
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            Some("jnz") => Ok(
                Instruction::JumpNonZero(
                    parts.next().ok_or("no register")?.parse()?,
                    parts.next().ok_or("no offset")?.parse()?
                )
            ),
            Some(other) => Err(format!("Unknown instruction: {}", other).into()),
            None => Err("Instruction missing".into()),
        }
    }
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum FromLocation {
    Integer(i32),
    Register(Register),
}

impl FromStr for FromLocation {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        s.parse().map(FromLocation::Integer)
                 .or_else(|_| s.parse().map(FromLocation::Register))
    }
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Register {
    A,
    B,
    C,
    D,
}

impl FromStr for Register {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Register::*;
        match s {
            "a" => Ok(A),
            "b" => Ok(B),
            "c" => Ok(C),
            "d" => Ok(D),
            other => Err(format!("Unknown register {}", other).into()),
        }
    }
}

pub struct Machine {
    registers: [i32; 4],
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            registers: [0; 4],
        }
    }

    fn execute(&mut self, instructions: &[Instruction]) {
        let mut program_counter = 0;
        while let Some(&instruction) = instructions.get(program_counter) {
            let mut jump = 0;
            match instruction {
                Instruction::Copy(
                    FromLocation::Integer(i),
                    to
                ) => {
                    let index = Machine::register_index(to);
                    self.registers[index] = i;
                },
                Instruction::Copy(FromLocation::Register(from), to) => {
                    let index_from = Machine::register_index(from);
                    let index_to = Machine::register_index(to);
                    self.registers[index_to] = self.registers[index_from];
                },
                Instruction::Increment(register) => {
                    let index = Machine::register_index(register);
                    self.registers[index] += 1;
                },
                Instruction::Decrement(register) => {
                    let index = Machine::register_index(register);
                    self.registers[index] -= 1;
                },
                Instruction::JumpNonZero(FromLocation::Integer(i), offset) => {
                    if i != 0 {
                        jump = offset;
                    }
                },
                Instruction::JumpNonZero(FromLocation::Register(register), offset) => {
                    let index = Machine::register_index(register);
                    if self.registers[index] != 0 {
                        jump = offset;
                    }
                },
            }
            let next_pc = program_counter as i32 + 1 + jump;
            if next_pc < 0 {
                panic!("Jumped too far back!")
            }
            program_counter = next_pc as usize;
        }
    }

    fn register_index(register: Register) -> usize {
        use Register::*;
        match register {
            A => 0,
            B => 1,
            C => 2,
            D => 3,
        }
    }

    fn value_of(&self, register: Register) -> i32 {
        let index = Machine::register_index(register);
        self.registers[index]
    }
}

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

    #[test]
    fn parse_cpy() {
        let instr: Instruction = "cpy 41 a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Copy(FromLocation::Integer(41), Register::A)
        );
    }

    #[test]
    fn parse_cpy_register() {
        let instr: Instruction = "cpy a c".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Copy(
                FromLocation::Register(Register::A),
                Register::C,
            )
        );
    }

    #[test]
    fn parse_inc() {
        let instr: Instruction = "inc a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Increment(Register::A)
        );
    }

    #[test]
    fn parse_dec() {
        let instr: Instruction = "dec a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Decrement(Register::A)
        );
    }

    #[test]
    fn parse_jnz() {
        let instr: Instruction = "jnz a 2".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::JumpNonZero(FromLocation::Register(Register::A), 2)
        );
    }

    #[test]
    fn execute_copy() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Copy(
                    FromLocation::Integer(5),
                    Register::A,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::A), 5);
    }

    #[test]
    fn execute_copy_register() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Copy(
                    FromLocation::Integer(5),
                    Register::A,
                ),
                Instruction::Copy(
                    FromLocation::Register(Register::A),
                    Register::B,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::B), 5);
    }

    #[test]
    fn execute_increment() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Increment(
                    Register::C,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::C), 1);
    }

    #[test]
    fn execute_decrement() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Decrement(
                    Register::D,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::D), -1);
    }

    #[test]
    fn execute_jnz_when_zero() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                // D should be 0, jump doesn't happen
                Instruction::JumpNonZero(FromLocation::Register(Register::D), 2),
                Instruction::Increment(
                    Register::A,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::A), 1);
    }

    #[test]
    fn execute_jnz_when_non_zero() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Decrement(
                    Register::D,
                ),
                Instruction::JumpNonZero(FromLocation::Register(Register::D), 2),
                Instruction::Increment(
                    Register::A,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::A), 0);
    }

    #[test]
    fn sample() {
        let input = "cpy 41 a
            inc a
            inc a
            dec a
            jnz a 2
            dec a";
        assert_eq!(puzzle(input), 42);
    }
}
<|endoftext|>


<commit_before>// lib.rs
// Copyright 2016 Alexander Altman
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate diff;
extern crate itertools;
extern crate colored;

#[derive(Eq,Ord,PartialEq,PartialOrd,Hash,Clone,Copy,Debug)]
pub enum Provenance {
  Old,
  Shared,
  New,
}

pub trait ExtensionPoint {
  fn name(&self) -> String;

  fn description(&self) -> String;
}

impl<L: ExtensionPoint + ?Sized> ExtensionPoint for Box<L> {
  fn name(&self) -> String { self.as_ref().name() }

  fn description(&self) -> String { self.as_ref().description() }
}

mod language;
pub use language::*;

mod presentation;
pub use presentation::*;
<commit_msg>Add some `impl`s for `Provenance`.<commit_after>// lib.rs
// Copyright 2016 Alexander Altman
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate diff;
extern crate itertools;
extern crate colored;

#[derive(Eq,Ord,PartialEq,PartialOrd,Hash,Clone,Copy,Debug)]
pub enum Provenance {
  Old,
  Shared,
  New,
}
use Provenance::*;

impl<'a> PartialEq<Provenance> for &'a Provenance {
  fn eq(&self, other: &Provenance) -> bool { (**self as Provenance) == (*other as Provenance) }
}

impl<'a> PartialEq<&'a Provenance> for Provenance {
  fn eq(&self, other: &&'a Provenance) -> bool { (*self as Provenance) == (**other as Provenance) }
}

impl Provenance {
  pub fn is_old(&self) -> bool { self != New }

  pub fn is_old_only(&self) -> bool { self == Old }

  pub fn is_new(&self) -> bool { self != Old }

  pub fn is_new_only(&self) -> bool { self == New }

  pub fn is_shared(&self) -> bool { self == Shared }

  pub fn is_unshared(&self) -> bool { self != Shared }
}

pub trait ExtensionPoint {
  fn name(&self) -> String;

  fn description(&self) -> String;
}

impl<L: ExtensionPoint + ?Sized> ExtensionPoint for Box<L> {
  fn name(&self) -> String { self.as_ref().name() }

  fn description(&self) -> String { self.as_ref().description() }
}

mod language;
pub use language::*;

mod presentation;
pub use presentation::*;
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![crate_name = "cocoa"]
#![crate_type = "rlib"]

#![allow(missing_copy_implementations, non_snake_case, unstable)]

#[macro_use]
extern crate bitflags;
extern crate libc;

#[cfg(target_os="macos")]
pub mod appkit;
#[cfg(target_os="macos")]
pub mod base;
<commit_msg>Silence warnings by adding `std_misc` and `hash` features and removing the `unstable` warning allowance.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![crate_name = "cocoa"]
#![crate_type = "rlib"]

#![allow(missing_copy_implementations, non_snake_case)]
#![feature(std_misc, hash)]

#[macro_use]
extern crate bitflags;
extern crate libc;

#[cfg(target_os="macos")]
pub mod appkit;
#[cfg(target_os="macos")]
pub mod base;
<|endoftext|>


<commit_before>//! A collection of synchronization primitives that build on the primitives available in the
//! standard library.
//!
//! Name source: http://bulbapedia.bulbagarden.net/wiki/Synchronoise_(move)

mod util;

use std::sync::{Mutex, Condvar};
use std::time::Duration;

/// A synchronization primitive that signals when its count reaches zero.
///
/// With a `CountdownEvent`, it's possible to cause one thread to wait on a set of computations
/// occurring in other threads by making the other threads interact with the counter as they perform
/// their work.
///
/// The main limitation of a CountdownEvent is that once its counter reaches zero (even by starting
/// there), any attempts to update the counter will return `CountdownError::AlreadySet` until the
/// counter is reset by calling `reset` or `reset_to_count`.
///
/// # Example
///
/// ```
/// use synchronoise::CountdownEvent;
/// use std::sync::Arc;
/// use std::thread;
/// use std::time::Duration;
///
/// let counter = Arc::new(CountdownEvent::new(5));
///
/// for i in 0..5 {
///     let signal = counter.clone();
///     thread::spawn(move || {
///         thread::sleep(Duration::from_secs(3));
///         println!("thread {} activated!", i);
///         signal.decrement();
///     });
/// }
///
/// counter.wait();
///
/// println!("all done!");
/// ```
pub struct CountdownEvent {
    initial: isize,
    counter: Mutex<isize>,
    lock: Condvar,
}

///The collection of errors that can be returned by `CountdownEvent` methods.
pub enum CountdownError {
    ///Returned when adding to a counter would have caused it to overflow.
    SaturatedCounter,
    ///Returned when attempting to signal would have caused the counter to go below zero.
    TooManySignals,
    ///Returned when attempting to modify the counter after it has reached zero.
    AlreadySet,
}

impl CountdownEvent {
    ///Creates a new `CountdownEvent`, initialized to the given count.
    pub fn new(count: isize) -> CountdownEvent {
        CountdownEvent {
            initial: count,
            counter: Mutex::new(count),
            lock: Condvar::new(),
        }
    }

    ///Resets the counter to the count given to `new`.
    ///
    ///This function is safe because the `&mut self` enforces that no other references or locks
    ///exist.
    pub fn reset(&mut self) {
        self.counter = Mutex::new(self.initial);
        self.lock = Condvar::new();
    }

    ///Resets the counter to the given count.
    ///
    ///This function is safe because the `&mut self` enforces that no other references or locks
    ///exist.
    pub fn reset_to_count(&mut self, count: isize) {
        self.initial = count;
        self.reset();
    }

    ///Returns the current counter value.
    pub fn count(&self) -> isize {
        let lock = util::guts(self.counter.lock());

        *lock
    }

    ///Adds the given count to the counter.
    ///
    ///# Errors
    ///
    ///If the counter is already at or below zero, this function will return an error.
    ///
    ///If the given count would overflow an `isize`, this function will return an error.
    pub fn add(&self, count: isize) -> Result<(), CountdownError> {
        let mut lock = util::guts(self.counter.lock());

        if *lock <= 0 {
            return Err(CountdownError::AlreadySet);
        }

        if let Some(new_count) = count.checked_add(*lock) {
            *lock = new_count;
        } else {
            return Err(CountdownError::SaturatedCounter);
        }

        Ok(())
    }

    ///Subtracts the given count to the counter, and returns whether this caused any waiting
    ///threads to wake up.
    ///
    ///# Errors
    ///
    ///If the counter was already at or below zero, this function will return an error.
    ///
    ///If the given count is greater than the current counter, this function will return an error.
    pub fn signal(&self, count: isize) -> Result<bool, CountdownError> {
        let mut lock = util::guts(self.counter.lock());

        if *lock == 0 {
            return Err(CountdownError::AlreadySet);
        }

        if count <= *lock {
            *lock -= count;
        } else {
            return Err(CountdownError::TooManySignals);
        }

        if *lock == 0 {
            self.lock.notify_all();
            Ok(true)
        } else {
            Ok(false)
        }
    }

    ///Adds one to the count.
    ///
    ///# Errors
    ///
    ///See [`add`] for the situations where this function will return an error.
    ///
    ///[`add`]: #method.add
    pub fn increment(&self) -> Result<(), CountdownError> {
        self.add(1)
    }

    ///Subtracts one from the counter, and returns whether this caused any waiting threads to wake
    ///up.
    ///
    ///# Errors
    ///
    ///See [`signal`] for the situations where this function will return an error.
    ///
    ///[`signal`]: #method.signal
    pub fn decrement(&self) -> Result<bool, CountdownError> {
        self.signal(1)
    }

    ///Blocks the current thread until the counter reaches zero.
    ///
    ///This function will block indefinitely until the counter reaches zero. It will return
    ///immediately if it is already at zero.
    pub fn wait(&self) {
        let mut count = util::guts(self.counter.lock());

        while *count > 0 {
            count = util::guts(self.lock.wait(count));
        }
    }

    ///Blocks the current thread until the timer reaches zero, or until the given timeout elapses,
    ///returning the count at the time of wakeup and whether the timeout is known to have elapsed.
    ///
    ///This function will return immediately if the counter was already at zero. Otherwise, it will
    ///block for roughly no longer than `timeout`. Due to limitations in the platform specific
    ///implementation of `std::sync::Condvar`, this method could spuriously wake up both before the timeout
    ///elapsed and without the count being zero.
    pub fn wait_timeout(&self, timeout: Duration) -> (isize, bool) {
        let count = util::guts(self.counter.lock());

        if *count == 0 {
            return (*count, false);
        }

        let (count, status) = util::guts(self.lock.wait_timeout(count, timeout));

        (*count, status.timed_out())
    }
}

///Determines the reset behavior of a `SignalEvent`.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum SignalKind {
    ///An activated `SignalEvent` automatically resets when a thread is resumed.
    ///
    ///`SignalEvent`s with this kind will only resume one thread at a time.
    Auto,
    ///An activated `SignalEvent` must be manually reset to block threads again.
    ///
    ///`SignalEvent`s with this kind will signal every waiting thread to continue at once.
    Manual,
}

/// A synchronization primitive that allows one or more threads to wait on a signal from another
/// thread.
pub struct SignalEvent {
    reset: SignalKind,
    signal: Mutex<bool>,
    lock: Condvar,
}

impl SignalEvent {
    ///Creates a new `SignalEvent` with the given starting state and reset behavior.
    pub fn new(init_state: bool, signal_kind: SignalKind) -> SignalEvent {
        SignalEvent {
            reset: signal_kind,
            signal: Mutex::new(init_state),
            lock: Condvar::new(),
        }
    }

    ///Returns the current signal status of the `SignalEvent`.
    pub fn status(&self) -> bool {
        let signal = util::guts(self.signal.lock());

        *signal
    }

    ///Sets the signal on this `SignalEvent`, potentially waking up one or all threads waiting on
    ///it.
    pub fn signal(&self) {
        let mut signal = util::guts(self.signal.lock());

        *signal = true;

        match self.reset {
            SignalKind::Auto => self.lock.notify_one(),
            SignalKind::Manual => self.lock.notify_all(),
        }
    }

    ///Resets the signal on this `SignalEvent`, allowing threads that wait on it to block.
    pub fn reset(&self) {
        let mut signal = util::guts(self.signal.lock());

        *signal = false;
    }

    ///Blocks this thread until another thread calls `signal`.
    pub fn wait(&self) {
        let mut signal = util::guts(self.signal.lock());

        while !*signal {
            signal = util::guts(self.lock.wait(signal));
        }

        if self.reset == SignalKind::Auto {
            //don't want to call self.reset() since it would deadlock the mutex
            *signal = false;
        }
    }

    ///Blocks this thread until either another thread calls `signal`, or until the timeout elapses.
    ///
    ///This function returns both the status of the signal when it woke up, and whether the timeout
    ///was known to have elapsed. Note that due to platform-specific implementations of
    ///`std::sync::Condvar`, it's possible for this wait to spuriously wake up when neither the
    ///signal was set nor the timeout had elapsed.
    pub fn wait_timeout(&self, timeout: Duration) -> (bool, bool) {
        let mut signal = util::guts(self.signal.lock());

        if *signal {
            if self.reset == SignalKind::Auto {
                *signal = false;
            }
            return (true, false);
        }

        let (mut signal, status) = util::guts(self.lock.wait_timeout(signal, timeout));
        let ret = *signal;

        if self.reset == SignalKind::Auto {
            *signal = false;
        }

        (ret, status.timed_out())
    }
}
<commit_msg>extra docs for SignalEvent<commit_after>//! A collection of synchronization primitives that build on the primitives available in the
//! standard library.
//!
//! Name source: http://bulbapedia.bulbagarden.net/wiki/Synchronoise_(move)

mod util;

use std::sync::{Mutex, Condvar};
use std::time::Duration;

/// A synchronization primitive that signals when its count reaches zero.
///
/// With a `CountdownEvent`, it's possible to cause one thread to wait on a set of computations
/// occurring in other threads by making the other threads interact with the counter as they perform
/// their work.
///
/// The main limitation of a CountdownEvent is that once its counter reaches zero (even by starting
/// there), any attempts to update the counter will return `CountdownError::AlreadySet` until the
/// counter is reset by calling `reset` or `reset_to_count`.
///
/// # Example
///
/// ```
/// use synchronoise::CountdownEvent;
/// use std::sync::Arc;
/// use std::thread;
/// use std::time::Duration;
///
/// let counter = Arc::new(CountdownEvent::new(5));
///
/// for i in 0..5 {
///     let signal = counter.clone();
///     thread::spawn(move || {
///         thread::sleep(Duration::from_secs(3));
///         println!("thread {} activated!", i);
///         signal.decrement();
///     });
/// }
///
/// counter.wait();
///
/// println!("all done!");
/// ```
pub struct CountdownEvent {
    initial: isize,
    counter: Mutex<isize>,
    lock: Condvar,
}

///The collection of errors that can be returned by `CountdownEvent` methods.
pub enum CountdownError {
    ///Returned when adding to a counter would have caused it to overflow.
    SaturatedCounter,
    ///Returned when attempting to signal would have caused the counter to go below zero.
    TooManySignals,
    ///Returned when attempting to modify the counter after it has reached zero.
    AlreadySet,
}

impl CountdownEvent {
    ///Creates a new `CountdownEvent`, initialized to the given count.
    pub fn new(count: isize) -> CountdownEvent {
        CountdownEvent {
            initial: count,
            counter: Mutex::new(count),
            lock: Condvar::new(),
        }
    }

    ///Resets the counter to the count given to `new`.
    ///
    ///This function is safe because the `&mut self` enforces that no other references or locks
    ///exist.
    pub fn reset(&mut self) {
        self.counter = Mutex::new(self.initial);
        self.lock = Condvar::new();
    }

    ///Resets the counter to the given count.
    ///
    ///This function is safe because the `&mut self` enforces that no other references or locks
    ///exist.
    pub fn reset_to_count(&mut self, count: isize) {
        self.initial = count;
        self.reset();
    }

    ///Returns the current counter value.
    pub fn count(&self) -> isize {
        let lock = util::guts(self.counter.lock());

        *lock
    }

    ///Adds the given count to the counter.
    ///
    ///# Errors
    ///
    ///If the counter is already at or below zero, this function will return an error.
    ///
    ///If the given count would overflow an `isize`, this function will return an error.
    pub fn add(&self, count: isize) -> Result<(), CountdownError> {
        let mut lock = util::guts(self.counter.lock());

        if *lock <= 0 {
            return Err(CountdownError::AlreadySet);
        }

        if let Some(new_count) = count.checked_add(*lock) {
            *lock = new_count;
        } else {
            return Err(CountdownError::SaturatedCounter);
        }

        Ok(())
    }

    ///Subtracts the given count to the counter, and returns whether this caused any waiting
    ///threads to wake up.
    ///
    ///# Errors
    ///
    ///If the counter was already at or below zero, this function will return an error.
    ///
    ///If the given count is greater than the current counter, this function will return an error.
    pub fn signal(&self, count: isize) -> Result<bool, CountdownError> {
        let mut lock = util::guts(self.counter.lock());

        if *lock == 0 {
            return Err(CountdownError::AlreadySet);
        }

        if count <= *lock {
            *lock -= count;
        } else {
            return Err(CountdownError::TooManySignals);
        }

        if *lock == 0 {
            self.lock.notify_all();
            Ok(true)
        } else {
            Ok(false)
        }
    }

    ///Adds one to the count.
    ///
    ///# Errors
    ///
    ///See [`add`] for the situations where this function will return an error.
    ///
    ///[`add`]: #method.add
    pub fn increment(&self) -> Result<(), CountdownError> {
        self.add(1)
    }

    ///Subtracts one from the counter, and returns whether this caused any waiting threads to wake
    ///up.
    ///
    ///# Errors
    ///
    ///See [`signal`] for the situations where this function will return an error.
    ///
    ///[`signal`]: #method.signal
    pub fn decrement(&self) -> Result<bool, CountdownError> {
        self.signal(1)
    }

    ///Blocks the current thread until the counter reaches zero.
    ///
    ///This function will block indefinitely until the counter reaches zero. It will return
    ///immediately if it is already at zero.
    pub fn wait(&self) {
        let mut count = util::guts(self.counter.lock());

        while *count > 0 {
            count = util::guts(self.lock.wait(count));
        }
    }

    ///Blocks the current thread until the timer reaches zero, or until the given timeout elapses,
    ///returning the count at the time of wakeup and whether the timeout is known to have elapsed.
    ///
    ///This function will return immediately if the counter was already at zero. Otherwise, it will
    ///block for roughly no longer than `timeout`. Due to limitations in the platform specific
    ///implementation of `std::sync::Condvar`, this method could spuriously wake up both before the timeout
    ///elapsed and without the count being zero.
    pub fn wait_timeout(&self, timeout: Duration) -> (isize, bool) {
        let count = util::guts(self.counter.lock());

        if *count == 0 {
            return (*count, false);
        }

        let (count, status) = util::guts(self.lock.wait_timeout(count, timeout));

        (*count, status.timed_out())
    }
}

///Determines the reset behavior of a `SignalEvent`.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum SignalKind {
    ///An activated `SignalEvent` automatically resets when a thread is resumed.
    ///
    ///`SignalEvent`s with this kind will only resume one thread at a time.
    Auto,
    ///An activated `SignalEvent` must be manually reset to block threads again.
    ///
    ///`SignalEvent`s with this kind will signal every waiting thread to continue at once.
    Manual,
}

/// A synchronization primitive that allows one or more threads to wait on a signal from another
/// thread.
///
/// With a `SignalEvent`, it's possible to have one or more threads gate on a signal from another
/// thread. The behavior for what happens when an event is signaled depends on the value of the
/// `signal_kind` parameter given to `new`:
///
/// * A value of `SignalKind::Auto` will automatically reset the signal when a thread is resumed by
///   this event. If more than one thread is waiting on the event when it is signaled, only one
///   will be resumed.
/// * A value of `SignalKind::Manual` will remain signaled until it is manually reset. If more than
///   one thread is waiting on the event when it is signaled, all of them will be resumed. Any
///   other thread that tries to wait on the signal before it is reset will not be blocked at all.
///
/// # Example
///
/// ```
/// use synchronoise::{SignalEvent, SignalKind};
/// use std::sync::Arc;
/// use std::thread;
/// use std::time::Duration;
///
/// let start_signal = Arc::new(SignalEvent::new(false, SignalKind::Manual));
/// let stop_signal = Arc::new(SignalEvent::new(false, SignalKind::Auto));
/// let mut thread_count = 5;
///
/// for i in 0..thread_count {
///     let start = start_signal.clone();
///     let stop = stop_signal.clone();
///     thread::spawn(move || {
///         //as a Manual-reset signal, all the threads will start at the same time
///         start.wait();
///         thread::sleep(Duration::from_secs(i));
///         println!("thread {} activated!", i);
///         stop.signal();
///     });
/// }
///
/// start_signal.signal();
///
/// while thread_count > 0 {
///     //as an Auto-reset signal, this will automatically reset when resuming
///     //so when the loop comes back, we don't have to reset before blocking again
///     stop_signal.wait();
///     thread_count -= 1;
/// }
///
/// println!("all done!");
/// ```
pub struct SignalEvent {
    reset: SignalKind,
    signal: Mutex<bool>,
    lock: Condvar,
}

impl SignalEvent {
    ///Creates a new `SignalEvent` with the given starting state and reset behavior.
    pub fn new(init_state: bool, signal_kind: SignalKind) -> SignalEvent {
        SignalEvent {
            reset: signal_kind,
            signal: Mutex::new(init_state),
            lock: Condvar::new(),
        }
    }

    ///Returns the current signal status of the `SignalEvent`.
    pub fn status(&self) -> bool {
        let signal = util::guts(self.signal.lock());

        *signal
    }

    ///Sets the signal on this `SignalEvent`, potentially waking up one or all threads waiting on
    ///it.
    ///
    ///If more than one thread is waiting on the event, the behavior is different depending on the
    ///`SignalKind` passed to the event when it was created. For a value of Auto, one thread will
    ///be resumed. For a value of Manual, all waiting threads will be resumed.
    ///
    ///If no thread is currently waiting on the event, its state will be set regardless. Any future
    ///attempts to wait on the event will unblock immediately, except for a `SignalKind` of Auto,
    ///which will immediately unblock the first thread only.
    pub fn signal(&self) {
        let mut signal = util::guts(self.signal.lock());

        *signal = true;

        match self.reset {
            SignalKind::Auto => self.lock.notify_one(),
            SignalKind::Manual => self.lock.notify_all(),
        }
    }

    ///Resets the signal on this `SignalEvent`, allowing threads that wait on it to block.
    pub fn reset(&self) {
        let mut signal = util::guts(self.signal.lock());

        *signal = false;
    }

    ///Blocks this thread until another thread calls `signal`.
    ///
    ///If this event is already set, then the thread will immediately unblock. For events with a
    ///`SignalKind` of Auto, this will reset the signal so that the next one to wait will block.
    pub fn wait(&self) {
        let mut signal = util::guts(self.signal.lock());

        while !*signal {
            signal = util::guts(self.lock.wait(signal));
        }

        if self.reset == SignalKind::Auto {
            //don't want to call self.reset() since it would deadlock the mutex
            *signal = false;
        }
    }

    ///Blocks this thread until either another thread calls `signal`, or until the timeout elapses.
    ///
    ///This function returns both the status of the signal when it woke up, and whether the timeout
    ///was known to have elapsed. Note that due to platform-specific implementations of
    ///`std::sync::Condvar`, it's possible for this wait to spuriously wake up when neither the
    ///signal was set nor the timeout had elapsed.
    pub fn wait_timeout(&self, timeout: Duration) -> (bool, bool) {
        let mut signal = util::guts(self.signal.lock());

        if *signal {
            if self.reset == SignalKind::Auto {
                *signal = false;
            }
            return (true, false);
        }

        let (mut signal, status) = util::guts(self.lock.wait_timeout(signal, timeout));
        let ret = *signal;

        if self.reset == SignalKind::Auto {
            *signal = false;
        }

        (ret, status.timed_out())
    }
}
<|endoftext|>


<commit_before>//! [![logo](http://i.imgur.com/dnpEXyh.jpg)](http://i.imgur.com/RUEw8EW.png)
//!
//! bspline
//! ===
//! A library for computing B-spline interpolating curves on generic control points. bspline can
//! be used to evaluate B-splines of varying orders on any type that can be linearly interpolated,
//! ranging from floats, positions, RGB colors to transformation matrices and so on.
//!
//! The bspline logo was generated using this library with a cubic B-spline in 2D for the positioning
//! of the curve and a quadratic B-spline in RGB space to color it (check out the
//! [logo](https://github.com/Twinklebear/bspline/blob/master/examples/logo.rs) example!). Other
//! much simpler examples of 1D and 2D quadratic, cubic and quartic B-splines can also be found in
//! the [examples](https://github.com/Twinklebear/bspline/tree/master/examples).
//!
//! # 1D Example
//!
//! This example shows how to create the 1D cardinal cubic B-spline example shown on [Wikipedia's
//! B-splines page](https://en.wikipedia.org/wiki/B-spline). For examples of evaluating the spline
//! to an image and saving the output see the [examples](https://github.com/Twinklebear/bspline/tree/master/examples).
//!
//! ```rust
//! let points = vec![0.0, 0.0, 0.0, 6.0, 0.0, 0.0, 0.0];
//! let knots = vec![-2.0, -2.0, -2.0, -2.0, -1.0, 0.0, 1.0, 2.0, 2.0, 2.0, 2.0];
//! let degree = 3;
//! let spline = bspline::BSpline::new(degree, points, knots);
//! ```
//!
//! # Readings on B-splines
//!
//! The library assumes you are familiar at some level with how B-splines work, e.g. how
//! control points and knots and effect the curve produced. No interactive
//! editor is provided (at least currently). Some good places to start reading about B-splines to
//! effectively use this library can be found below.
//!
//! - [Wikipedia page on B-splines](https://en.wikipedia.org/wiki/B-spline)
//! - [Fundamentals of Computer Graphics](http://www.amazon.com/Fundamentals-Computer-Graphics-Peter-Shirley/dp/1568814690)
//! (has a good chapter on curves)
//! - [Splines and B-splines: An Introduction](http://www.uio.no/studier/emner/matnat/ifi/INF-MAT5340/v07/undervisningsmateriale/kap1.pdf)
//! - [Geometric Modeling](http://atrey.karlin.mff.cuni.cz/projekty/vrr/doc/grafika/geometric%20modelling.pdf)
//! - [A nice set of interactive examples](https://www.ibiblio.org/e-notes/Splines/Intro.htm)
//!

use std::ops::{Mul, Add};
use std::slice::Iter;

/// The interpolate trait is used to linearly interpolate between two types (or in the
/// case of Quaternions, spherically linearly interpolate). The B-spline curve uses this
/// trait to compute points on the curve for the given parameter value.
///
/// A default implementation of this trait is provided for all `T` that are `Mul<f32, Output = T>
/// + Add<Output = T> + Copy` since the interpolation provided by the trait is expected to be
/// a simple linear interpolation.
pub trait Interpolate {
    /// Linearly interpolate between `self` and `other` using `t`, for example with floats:
    ///
    /// ```text
    /// self * (1.0 - t) + other * t
    /// ```
    ///
    /// If the result returned is not a correct linear interpolation of the values the
    /// curve produced using the value may not be correct.
    fn interpolate(&self, other: &Self, t: f32) -> Self;
}

impl<T: Mul<f32, Output = T> + Add<Output = T> + Copy> Interpolate for T {
    fn interpolate(&self, other: &Self, t: f32) -> Self {
        *self * (1.0 - t) + *other * t
    }
}

/// Represents a B-spline that will use polynomials of the specified degree to interpolate
/// between the control points given the knots.
#[derive(Clone)]
pub struct BSpline<T: Interpolate + Copy> {
    /// Degree of the polynomial that we use to make the curve segments
    degree: usize,
    /// Control points for the curve
    control_points: Vec<T>,
    /// The knot vector
    knots: Vec<f32>,
}

impl<T: Interpolate + Copy> BSpline<T> {
    /// Create a new B-spline curve of the desired `degree` that will interpolate
    /// the `control_points` using the `knots`. The knots should be sorted in non-decreasing
    /// order, otherwise they will be sorted for you which may lead to undesired knots
    /// for control points. Note that this is in terms of the interpolating polynomial degree,
    /// if you are familiar with the convention of "B-spline curve order" the degree is `curve_order - 1`.
    ///
    /// Your curve must have a valid number of control points and knots or the function will panic. A B-spline
    /// curve requires at least as many control points as the degree (`control_points.len() >=
    /// degree`) and the number of knots should be equal to `control_points.len() + degree + 1`.
    pub fn new(degree: usize, control_points: Vec<T>, mut knots: Vec<f32>) -> BSpline<T> {
        if control_points.len() < degree {
            panic!("Too few control points for curve");
        }
        if knots.len() != control_points.len() + degree + 1 {
            panic!(format!("Invalid number of knots, got {}, expected {}", knots.len(),
                control_points.len() + degree + 1));
        }
        knots.sort_by(|a, b| a.partial_cmp(b).unwrap());
        BSpline { degree: degree, control_points: control_points, knots: knots }
    }
    /// Compute a point on the curve at `t`, the parameter **must** be in the inclusive range
    /// of values returned by `knot_domain`. If `t` is out of bounds this function will assert
    /// on debug builds and on release builds you'll likely get an out of bounds crash.
    pub fn point(&self, t: f32) -> T {
        debug_assert!(t >= self.knot_domain().0 && t < self.knot_domain().1);
        // Find the first index with a knot value greater than the t we're searching for. We want
        // to find i such that: knot[i] <= t < knot[i + 1]
        let i = match upper_bounds(&self.knots[..], t) {
            Some(x) if x == 0 => self.degree,
            Some(x) => x,
            None => self.knots.len() - self.degree - 1,
        };
        self.de_boor_iterative(t, i)
    }
    /// Get an iterator over the control points.
    pub fn control_points(&self) -> Iter<T> {
        self.control_points.iter()
    }
    /// Get an iterator over the knots.
    pub fn knots(&self) -> Iter<f32> {
        self.knots.iter()
    }
    /// Get the min and max knot domain values for finding the `t` range to compute
    /// the curve over. The curve is only defined over this range in [min, max), passing
    /// a `t` value out of this range will assert on debug builds and likely result in
    /// a crash on release builds.
    pub fn knot_domain(&self) -> (f32, f32) {
        (self.knots[self.degree], self.knots[self.knots.len() - 1 - self.degree])
    }
    /// Iteratively compute de Boor's B-spline algorithm, this computes the recursive
    /// de Boor algorithm tree from the bottom up. At each level we use the results
    /// from the previous one to compute this level and store the results in the
    /// array indices we no longer need to compute the current level (the left one
    /// used computing node j).
    fn de_boor_iterative(&self, t: f32, i_start: usize) -> T {
        let mut tmp = Vec::with_capacity(self.degree + 1);
        for j in 0..self.degree + 1 {
            let p = j + i_start - self.degree - 1;
            tmp.push(self.control_points[p]);
        }
        for lvl in 0..self.degree {
            let k = lvl + 1;
            for j in 0..self.degree - lvl {
                let i = j + k + i_start - self.degree;
                let alpha = (t - self.knots[i - 1]) / (self.knots[i + self.degree - k] - self.knots[i - 1]);
                if alpha.is_nan() {
                    panic!("alpha has nans");
                }
                tmp[j] = tmp[j].interpolate(&tmp[j + 1], alpha);
            }
        }
        tmp[0]
    }
}

/// Return the index of the first element greater than the value passed.
/// The data **must** be sorted.
/// If no element greater than the value passed is found the function returns None.
fn upper_bounds(data: &[f32], value: f32) -> Option<usize> {
    let mut first = 0usize;
    let mut step;
    let mut count = data.len() as isize;
    while count > 0 {
        step = count / 2;
        let it = first + step as usize;
        if !value.lt(&data[it]) {
            first = it + 1;
            count -= step + 1;
        } else {
            count = step;
        }
    }
    // If we didn't find an element greater than value
    if first == data.len() {
        None
    } else {
        Some(first)
    }
}

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

    /// Check that the bspline returns the values we expect it to at various t values
    fn check_bspline(spline: &BSpline<f32>, expect: &Vec<(f32, f32)>) -> bool {
        expect.iter().fold(true, |ac, &(t, x)| ac && spline.point(t) == x)
    }

    #[test]
    fn linear_bspline() {
        let expect = vec![(0.0, 0.0), (0.2, 0.2), (0.4, 0.4), (0.6, 0.6),
                          (0.8, 0.8), (1.0, 1.0)];
        let points = vec![0.0, 1.0];
        let knots = vec![0.0, 0.0, 1.0, 1.0];
        let degree = 1;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
    #[test]
    fn quadratic_bspline() {
        let expect = vec![(0.0, 0.0), (0.5, 0.125), (1.0, 0.5), (1.4, 0.74), (1.5, 0.75),
                          (1.6, 0.74), (2.0, 0.5), (2.5, 0.125), (3.0, 0.0)];
        let points = vec![0.0, 0.0, 1.0, 0.0, 0.0];
        let knots = vec![0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 3.0];
        let degree = 2;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
    #[test]
    fn cubic_bspline() {
        let expect = vec![(-2.0, 0.0), (-1.5, 0.125), (-1.0, 1.0), (-0.6, 2.488),
                           (0.0, 4.0), (0.5, 2.875), (1.5, 0.12500001), (2.0, 0.0)];
        let points = vec![0.0, 0.0, 0.0, 6.0, 0.0, 0.0, 0.0];
        let knots = vec![-2.0, -2.0, -2.0, -2.0, -1.0, 0.0, 1.0, 2.0, 2.0, 2.0, 2.0];
        let degree = 3;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
    #[test]
    fn quartic_bspline() {
        let expect = vec![(0.0, 0.0), (0.4, 0.0010666668), (1.0, 0.041666668),
                          (1.5, 0.19791667), (2.0, 0.4583333), (2.5, 0.5989583),
                          (3.0, 0.4583333), (3.2, 0.35206667), (4.1, 0.02733751),
                          (4.5, 0.002604167), (5.0, 0.0)];
        let points = vec![0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0];
        let knots = vec![0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 5.0, 5.0, 5.0];
        let degree = 4;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
}

<commit_msg>Fix handling of t values mapping into the last `degree` knots<commit_after>//! [![logo](http://i.imgur.com/dnpEXyh.jpg)](http://i.imgur.com/RUEw8EW.png)
//!
//! bspline
//! ===
//! A library for computing B-spline interpolating curves on generic control points. bspline can
//! be used to evaluate B-splines of varying orders on any type that can be linearly interpolated,
//! ranging from floats, positions, RGB colors to transformation matrices and so on.
//!
//! The bspline logo was generated using this library with a cubic B-spline in 2D for the positioning
//! of the curve and a quadratic B-spline in RGB space to color it (check out the
//! [logo](https://github.com/Twinklebear/bspline/blob/master/examples/logo.rs) example!). Other
//! much simpler examples of 1D and 2D quadratic, cubic and quartic B-splines can also be found in
//! the [examples](https://github.com/Twinklebear/bspline/tree/master/examples).
//!
//! # 1D Example
//!
//! This example shows how to create the 1D cardinal cubic B-spline example shown on [Wikipedia's
//! B-splines page](https://en.wikipedia.org/wiki/B-spline). For examples of evaluating the spline
//! to an image and saving the output see the [examples](https://github.com/Twinklebear/bspline/tree/master/examples).
//!
//! ```rust
//! let points = vec![0.0, 0.0, 0.0, 6.0, 0.0, 0.0, 0.0];
//! let knots = vec![-2.0, -2.0, -2.0, -2.0, -1.0, 0.0, 1.0, 2.0, 2.0, 2.0, 2.0];
//! let degree = 3;
//! let spline = bspline::BSpline::new(degree, points, knots);
//! ```
//!
//! # Readings on B-splines
//!
//! The library assumes you are familiar at some level with how B-splines work, e.g. how
//! control points and knots and effect the curve produced. No interactive
//! editor is provided (at least currently). Some good places to start reading about B-splines to
//! effectively use this library can be found below.
//!
//! - [Wikipedia page on B-splines](https://en.wikipedia.org/wiki/B-spline)
//! - [Fundamentals of Computer Graphics](http://www.amazon.com/Fundamentals-Computer-Graphics-Peter-Shirley/dp/1568814690)
//! (has a good chapter on curves)
//! - [Splines and B-splines: An Introduction](http://www.uio.no/studier/emner/matnat/ifi/INF-MAT5340/v07/undervisningsmateriale/kap1.pdf)
//! - [Geometric Modeling](http://atrey.karlin.mff.cuni.cz/projekty/vrr/doc/grafika/geometric%20modelling.pdf)
//! - [A nice set of interactive examples](https://www.ibiblio.org/e-notes/Splines/Intro.htm)
//!

use std::ops::{Mul, Add};
use std::slice::Iter;

/// The interpolate trait is used to linearly interpolate between two types (or in the
/// case of Quaternions, spherically linearly interpolate). The B-spline curve uses this
/// trait to compute points on the curve for the given parameter value.
///
/// A default implementation of this trait is provided for all `T` that are `Mul<f32, Output = T>
/// + Add<Output = T> + Copy` since the interpolation provided by the trait is expected to be
/// a simple linear interpolation.
pub trait Interpolate {
    /// Linearly interpolate between `self` and `other` using `t`, for example with floats:
    ///
    /// ```text
    /// self * (1.0 - t) + other * t
    /// ```
    ///
    /// If the result returned is not a correct linear interpolation of the values the
    /// curve produced using the value may not be correct.
    fn interpolate(&self, other: &Self, t: f32) -> Self;
}

impl<T: Mul<f32, Output = T> + Add<Output = T> + Copy> Interpolate for T {
    fn interpolate(&self, other: &Self, t: f32) -> Self {
        *self * (1.0 - t) + *other * t
    }
}

/// Represents a B-spline that will use polynomials of the specified degree to interpolate
/// between the control points given the knots.
#[derive(Clone)]
pub struct BSpline<T: Interpolate + Copy> {
    /// Degree of the polynomial that we use to make the curve segments
    degree: usize,
    /// Control points for the curve
    control_points: Vec<T>,
    /// The knot vector
    knots: Vec<f32>,
}

impl<T: Interpolate + Copy> BSpline<T> {
    /// Create a new B-spline curve of the desired `degree` that will interpolate
    /// the `control_points` using the `knots`. The knots should be sorted in non-decreasing
    /// order, otherwise they will be sorted for you which may lead to undesired knots
    /// for control points. Note that this is in terms of the interpolating polynomial degree,
    /// if you are familiar with the convention of "B-spline curve order" the degree is `curve_order - 1`.
    ///
    /// Your curve must have a valid number of control points and knots or the function will panic. A B-spline
    /// curve requires at least as many control points as the degree (`control_points.len() >=
    /// degree`) and the number of knots should be equal to `control_points.len() + degree + 1`.
    pub fn new(degree: usize, control_points: Vec<T>, mut knots: Vec<f32>) -> BSpline<T> {
        if control_points.len() < degree {
            panic!("Too few control points for curve");
        }
        if knots.len() != control_points.len() + degree + 1 {
            panic!(format!("Invalid number of knots, got {}, expected {}", knots.len(),
                control_points.len() + degree + 1));
        }
        knots.sort_by(|a, b| a.partial_cmp(b).unwrap());
        BSpline { degree: degree, control_points: control_points, knots: knots }
    }
    /// Compute a point on the curve at `t`, the parameter **must** be in the inclusive range
    /// of values returned by `knot_domain`. If `t` is out of bounds this function will assert
    /// on debug builds and on release builds you'll likely get an out of bounds crash.
    pub fn point(&self, t: f32) -> T {
        debug_assert!(t >= self.knot_domain().0 && t <= self.knot_domain().1);
        // Find the first index with a knot value greater than the t we're searching for. We want
        // to find i such that: knot[i] <= t < knot[i + 1]
        let i = match upper_bounds(&self.knots[..], t) {
            Some(x) if x == 0 => self.degree,
            Some(x) if x >= self.knots.len() - self.degree - 1 =>
                self.knots.len() - self.degree - 1,
            Some(x) => x,
            None => self.knots.len() - self.degree - 1,
        };
        self.de_boor_iterative(t, i)
    }
    /// Get an iterator over the control points.
    pub fn control_points(&self) -> Iter<T> {
        self.control_points.iter()
    }
    /// Get an iterator over the knots.
    pub fn knots(&self) -> Iter<f32> {
        self.knots.iter()
    }
    /// Get the min and max knot domain values for finding the `t` range to compute
    /// the curve over. The curve is only defined over this inclusive range in [min, max],
    /// passing a `t` value out of this range will assert on debug builds and likely result in
    /// a crash on release builds.
    pub fn knot_domain(&self) -> (f32, f32) {
        (self.knots[self.degree], self.knots[self.knots.len() - 1 - self.degree])
    }
    /// Iteratively compute de Boor's B-spline algorithm, this computes the recursive
    /// de Boor algorithm tree from the bottom up. At each level we use the results
    /// from the previous one to compute this level and store the results in the
    /// array indices we no longer need to compute the current level (the left one
    /// used computing node j).
    fn de_boor_iterative(&self, t: f32, i_start: usize) -> T {
        let mut tmp = Vec::with_capacity(self.degree + 1);
        for j in 0..self.degree + 1 {
            let p = j + i_start - self.degree - 1;
            tmp.push(self.control_points[p]);
        }
        for lvl in 0..self.degree {
            let k = lvl + 1;
            for j in 0..self.degree - lvl {
                let i = j + k + i_start - self.degree;
                let alpha = (t - self.knots[i - 1]) / (self.knots[i + self.degree - k] - self.knots[i - 1]);
                if alpha.is_nan() {
                    panic!("alpha has nans");
                }
                tmp[j] = tmp[j].interpolate(&tmp[j + 1], alpha);
            }
        }
        tmp[0]
    }
}

/// Return the index of the first element greater than the value passed.
/// The data **must** be sorted.
/// If no element greater than the value passed is found the function returns None.
fn upper_bounds(data: &[f32], value: f32) -> Option<usize> {
    let mut first = 0usize;
    let mut step;
    let mut count = data.len() as isize;
    while count > 0 {
        step = count / 2;
        let it = first + step as usize;
        if !value.lt(&data[it]) {
            first = it + 1;
            count -= step + 1;
        } else {
            count = step;
        }
    }
    // If we didn't find an element greater than value
    if first == data.len() {
        None
    } else {
        Some(first)
    }
}

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

    /// Check that the bspline returns the values we expect it to at various t values
    fn check_bspline(spline: &BSpline<f32>, expect: &Vec<(f32, f32)>) -> bool {
        expect.iter().fold(true, |ac, &(t, x)| ac && spline.point(t) == x)
    }

    #[test]
    fn linear_bspline() {
        let expect = vec![(0.0, 0.0), (0.2, 0.2), (0.4, 0.4), (0.6, 0.6),
                          (0.8, 0.8), (1.0, 1.0)];
        let points = vec![0.0, 1.0];
        let knots = vec![0.0, 0.0, 1.0, 1.0];
        let degree = 1;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
    #[test]
    fn quadratic_bspline() {
        let expect = vec![(0.0, 0.0), (0.5, 0.125), (1.0, 0.5), (1.4, 0.74), (1.5, 0.75),
                          (1.6, 0.74), (2.0, 0.5), (2.5, 0.125), (3.0, 0.0)];
        let points = vec![0.0, 0.0, 1.0, 0.0, 0.0];
        let knots = vec![0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 3.0];
        let degree = 2;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
    #[test]
    fn cubic_bspline() {
        let expect = vec![(-2.0, 0.0), (-1.5, 0.125), (-1.0, 1.0), (-0.6, 2.488),
                           (0.0, 4.0), (0.5, 2.875), (1.5, 0.12500001), (2.0, 0.0)];
        let points = vec![0.0, 0.0, 0.0, 6.0, 0.0, 0.0, 0.0];
        let knots = vec![-2.0, -2.0, -2.0, -2.0, -1.0, 0.0, 1.0, 2.0, 2.0, 2.0, 2.0];
        let degree = 3;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
    #[test]
    fn quartic_bspline() {
        let expect = vec![(0.0, 0.0), (0.4, 0.0010666668), (1.0, 0.041666668),
                          (1.5, 0.19791667), (2.0, 0.4583333), (2.5, 0.5989583),
                          (3.0, 0.4583333), (3.2, 0.35206667), (4.1, 0.02733751),
                          (4.5, 0.002604167), (5.0, 0.0)];
        let points = vec![0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0];
        let knots = vec![0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 5.0, 5.0, 5.0];
        let degree = 4;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
}

<|endoftext|>


<commit_before>// DOCS

#[macro_use] extern crate quick_error;
#[macro_use] extern crate string_cache;
extern crate mime;
extern crate hyper;
extern crate url;
extern crate kuchiki;
extern crate image;

mod strategies;
mod util;

use kuchiki::traits::*;
use kuchiki::parse_html;

use hyper::client::IntoUrl;

use image::GenericImage;
use strategies::Strategy;
use std::io::Read;
use util::AsImageFormat;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Hyper(error: hyper::Error) { from() }
        Io(error: std::io::Error) { from() }
        Image(error: image::ImageError) { from() }
        Other(msg: String) {
            description(msg)
        }
    }
}

pub struct IconScraper {
    document_url: url::Url,
    dom: Option<kuchiki::NodeRef>,
}

impl IconScraper {
    pub fn from_http<I: IntoUrl>(url: I) -> Self {
        let url = url.into_url().unwrap();
        let dom = parse_html().from_http(url.clone()).ok();
        IconScraper {
            document_url: url,
            dom: dom
        }
    }

    /// Search the document for icon metadata, also brute-force some favicon paths.
    ///
    /// **Note:** This operation is fairly costly, it is recommended to cache the results!
    ///
    /// # Panics
    ///
    /// If the document is not fetched yet.
    pub fn fetch_icons(&mut self) -> IconCollection {
        let icons = strategies::LinkRelStrategy.get_guesses(self)
            .into_iter()
            .chain(strategies::DefaultFaviconPathStrategy.get_guesses(self).into_iter())
            .filter_map(|mut icon| if icon.fetch_dimensions().is_ok() { Some(icon) } else { None })
            .collect::<Vec<_>>();

        IconCollection::from_raw(icons)
    }
}

pub struct IconCollection {
    icons: Vec<Icon>
}

impl IconCollection {
    fn from_raw(mut icons: Vec<Icon>) -> Self {
        icons.sort_by(|a, b| {
            (a.width.unwrap() * a.height.unwrap())
                .cmp(&(b.width.unwrap() * b.height.unwrap()))
        });
        IconCollection {
            icons: icons
        }
    }

    /// Return an icon that is at least of the given dimensions
    ///
    /// If there's only one icon available, it will return that icon. If there's no icon available,
    /// None is returned.
    pub fn at_least(mut self, width: u32, height: u32) -> Option<Icon> {
        let largest = self.icons.pop();
        self.icons
            .into_iter()
            .skip_while(|icon| icon.width.unwrap() < width || icon.height.unwrap() < height)
            .next()
            .or(largest)
    }

    /// Return the largest icon
    pub fn largest(mut self) -> Option<Icon> {
        self.icons.pop()
    }

    /// [unstable] Give up ownership of the inner datastructure: A vector of icons, sorted
    /// ascendingly by size
    pub fn into_raw_parts(self) -> Vec<Icon> {
        self.icons
    }
}

pub struct Icon {
    pub url: url::Url,
    pub raw: Option<Vec<u8>>,
    pub mime_type: Option<mime::Mime>,
    pub width: Option<u32>,
    pub height: Option<u32>
}

impl Icon {
    pub fn from_url(url: url::Url) -> Self {
        Icon {
            url: url,
            raw: None,
            mime_type: None,
            width: None,
            height: None
        }
    }

    pub fn fetch(&mut self) -> Result<(), Error> {
        if self.raw.is_some() {
            return Ok(());
        };

        let client = hyper::client::Client::new();
        let mut response = try!(client.get(self.url.clone()).send());

        let mut bytes: Vec<u8> = vec![];
        try!(response.read_to_end(&mut bytes));
        if !response.status.is_success() {
            return Err(Error::Other(format!("Bad status code: {:?}", response.status)));
        }

        let mime_type: mime::Mime = match response.headers.get::<hyper::header::ContentType>() {
            Some(x) => x.clone().0,
            None => return Err(Error::Other("No Content-Type found.".to_owned()))
        };
        let (better_mime_type, image_format) = match mime_type.parse_image_format() {
            Some(x) => x,
            None => return Err(Error::Other(format!("Invalid image type: {:?}", mime_type)))
        };
        let image = try!(image::load_from_memory_with_format(&bytes, image_format));

        self.width = Some(image.width());
        self.height = Some(image.height());
        self.raw = Some(bytes);
        self.mime_type = Some(better_mime_type);
        Ok(())
    }

    pub fn fetch_dimensions(&mut self) -> Result<(), Error> {
        match (self.width, self.height) {
            (Some(_), Some(_)) => Ok(()),
            _ => self.fetch()
        }
    }
}
<commit_msg>Explicitly refuse gzip encoding<commit_after>// DOCS

#[macro_use] extern crate quick_error;
#[macro_use] extern crate string_cache;
extern crate mime;
extern crate hyper;
extern crate url;
extern crate kuchiki;
extern crate image;

mod strategies;
mod util;

use kuchiki::traits::*;
use kuchiki::parse_html;

use hyper::client::IntoUrl;

use image::GenericImage;
use strategies::Strategy;
use std::io::Read;
use util::AsImageFormat;

#[inline]
fn accept_identity_encoding() -> hyper::header::AcceptEncoding {
    use hyper::header::{AcceptEncoding, Encoding, qitem};
    AcceptEncoding(vec![qitem(Encoding::Identity)])
}

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Hyper(error: hyper::Error) { from() }
        Io(error: std::io::Error) { from() }
        Image(error: image::ImageError) { from() }
        Other(msg: String) {
            description(msg)
        }
    }
}

pub struct IconScraper {
    document_url: url::Url,
    dom: Option<kuchiki::NodeRef>,
}

impl IconScraper {
    pub fn from_http<I: IntoUrl>(url: I) -> Self {
        use hyper::Client;

        let url = url.into_url().unwrap();
        let dom = {
            let client = Client::new();
            client.get(url.clone())
                .header(accept_identity_encoding())
                .send()
                .and_then(|r| parse_html().from_http(r)).ok()
        };

        IconScraper {
            document_url: url,
            dom: dom
        }
    }

    /// Search the document for icon metadata, also brute-force some favicon paths.
    ///
    /// **Note:** This operation is fairly costly, it is recommended to cache the results!
    ///
    /// # Panics
    ///
    /// If the document is not fetched yet.
    pub fn fetch_icons(&mut self) -> IconCollection {
        let icons = strategies::LinkRelStrategy.get_guesses(self)
            .into_iter()
            .chain(strategies::DefaultFaviconPathStrategy.get_guesses(self).into_iter())
            .filter_map(|mut icon| if icon.fetch_dimensions().is_ok() { Some(icon) } else { None })
            .collect::<Vec<_>>();

        IconCollection::from_raw(icons)
    }
}

pub struct IconCollection {
    icons: Vec<Icon>
}

impl IconCollection {
    fn from_raw(mut icons: Vec<Icon>) -> Self {
        icons.sort_by(|a, b| {
            (a.width.unwrap() * a.height.unwrap())
                .cmp(&(b.width.unwrap() * b.height.unwrap()))
        });
        IconCollection {
            icons: icons
        }
    }

    /// Return an icon that is at least of the given dimensions
    ///
    /// If there's only one icon available, it will return that icon. If there's no icon available,
    /// None is returned.
    pub fn at_least(mut self, width: u32, height: u32) -> Option<Icon> {
        let largest = self.icons.pop();
        self.icons
            .into_iter()
            .skip_while(|icon| icon.width.unwrap() < width || icon.height.unwrap() < height)
            .next()
            .or(largest)
    }

    /// Return the largest icon
    pub fn largest(mut self) -> Option<Icon> {
        self.icons.pop()
    }

    /// [unstable] Give up ownership of the inner datastructure: A vector of icons, sorted
    /// ascendingly by size
    pub fn into_raw_parts(self) -> Vec<Icon> {
        self.icons
    }
}

pub struct Icon {
    pub url: url::Url,
    pub raw: Option<Vec<u8>>,
    pub mime_type: Option<mime::Mime>,
    pub width: Option<u32>,
    pub height: Option<u32>
}

impl Icon {
    pub fn from_url(url: url::Url) -> Self {
        Icon {
            url: url,
            raw: None,
            mime_type: None,
            width: None,
            height: None
        }
    }

    pub fn fetch(&mut self) -> Result<(), Error> {
        if self.raw.is_some() {
            return Ok(());
        };

        let client = hyper::client::Client::new();
        let mut response = try!(client
                                .get(self.url.clone())
                                .header(accept_identity_encoding())
                                .send());

        let mut bytes: Vec<u8> = vec![];
        try!(response.read_to_end(&mut bytes));
        if !response.status.is_success() {
            return Err(Error::Other(format!("Bad status code: {:?}", response.status)));
        }

        let mime_type: mime::Mime = match response.headers.get::<hyper::header::ContentType>() {
            Some(x) => x.clone().0,
            None => return Err(Error::Other("No Content-Type found.".to_owned()))
        };
        let (better_mime_type, image_format) = match mime_type.parse_image_format() {
            Some(x) => x,
            None => return Err(Error::Other(format!("Invalid image type: {:?}", mime_type)))
        };
        let image = try!(image::load_from_memory_with_format(&bytes, image_format));

        self.width = Some(image.width());
        self.height = Some(image.height());
        self.raw = Some(bytes);
        self.mime_type = Some(better_mime_type);
        Ok(())
    }

    pub fn fetch_dimensions(&mut self) -> Result<(), Error> {
        match (self.width, self.height) {
            (Some(_), Some(_)) => Ok(()),
            _ => self.fetch()
        }
    }
}
<|endoftext|>