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

#![cfg(not(test))]

#[macro_use]
extern crate log;
extern crate rustfmt;
extern crate toml;
extern crate env_logger;
extern crate getopts;

use rustfmt::{run, run_from_stdin};
use rustfmt::config::{Config, WriteMode};

use std::env;
use std::fs::{self, File};
use std::io::{self, ErrorKind, Read, Write};
use std::path::{Path, PathBuf};
use std::str::FromStr;

use getopts::{Matches, Options};

/// Rustfmt operations.
enum Operation {
    /// Format files and their child modules.
    Format {
        files: Vec<PathBuf>,
        config_path: Option<PathBuf>,
    },
    /// Print the help message.
    Help,
    // Print version information
    Version,
    /// Print detailed configuration help.
    ConfigHelp,
    /// Invalid program input.
    InvalidInput {
        reason: String,
    },
    /// No file specified, read from stdin
    Stdin {
        input: String,
        config_path: Option<PathBuf>,
    },
}

/// Try to find a project file in the given directory and its parents. Returns the path of a the
/// nearest project file if one exists, or `None` if no project file was found.
fn lookup_project_file(dir: &Path) -> io::Result<Option<PathBuf>> {
    let mut current = if dir.is_relative() {
        try!(env::current_dir()).join(dir)
    } else {
        dir.to_path_buf()
    };

    current = try!(fs::canonicalize(current));

    loop {
        let config_file = current.join("rustfmt.toml");
        match fs::metadata(&config_file) {
            Ok(md) => {
                // Properly handle unlikely situation of a directory named `rustfmt.toml`.
                if md.is_file() {
                    return Ok(Some(config_file));
                }
            }
            // If it's not found, we continue searching; otherwise something went wrong and we
            // return the error.
            Err(e) => {
                if e.kind() != ErrorKind::NotFound {
                    return Err(e);
                }
            }
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Ok(None);
        }
    }
}

/// Resolve the config for input in `dir`.
///
/// Returns the `Config` to use, and the path of the project file if there was
/// one.
fn resolve_config(dir: &Path) -> io::Result<(Config, Option<PathBuf>)> {
    let path = try!(lookup_project_file(dir));
    if path.is_none() {
        return Ok((Config::default(), None));
    }
    let path = path.unwrap();
    let mut file = try!(File::open(&path));
    let mut toml = String::new();
    try!(file.read_to_string(&mut toml));
    Ok((Config::from_toml(&toml), Some(path)))
}

/// read the given config file path recursively if present else read the project file path
fn match_cli_path_or_file(config_path: Option<PathBuf>,
                          input_file: &Path)
                          -> io::Result<(Config, Option<PathBuf>)> {

    if let Some(config_file) = config_path {
        let (toml, path) = try!(resolve_config(config_file.as_ref()));
        if path.is_some() {
            return Ok((toml, path));
        }
    }
    resolve_config(input_file)
}

fn update_config(config: &mut Config, matches: &Matches) -> Result<(), String> {
    config.verbose = matches.opt_present("verbose");
    config.skip_children = matches.opt_present("skip-children");

    let write_mode = matches.opt_str("write-mode");
    match matches.opt_str("write-mode").map(|wm| WriteMode::from_str(&wm)) {
        None => Ok(()),
        Some(Ok(write_mode)) => {
            config.write_mode = write_mode;
            Ok(())
        }
        Some(Err(_)) => Err(format!("Invalid write-mode: {}", write_mode.expect("cannot happen"))),
    }
}

fn execute() -> i32 {
    let mut opts = Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("V", "version", "show version information");
    opts.optflag("v", "verbose", "show progress");
    opts.optopt("",
                "write-mode",
                "mode to write in (not usable when piping from stdin)",
                "[replace|overwrite|display|diff|coverage|checkstyle]");
    opts.optflag("", "skip-children", "don't reformat child modules");

    opts.optflag("",
                 "config-help",
                 "show details of rustfmt configuration options");
    opts.optopt("",
                "config-path",
                "Recursively searches the given path for the rustfmt.toml config file. If not \
                 found reverts to the input file path",
                "[Path for the configuration file]");

    let matches = match opts.parse(env::args().skip(1)) {
        Ok(m) => m,
        Err(e) => {
            print_usage(&opts, &e.to_string());
            return 1;
        }
    };

    let operation = determine_operation(&matches);

    match operation {
        Operation::InvalidInput { reason } => {
            print_usage(&opts, &reason);
            1
        }
        Operation::Help => {
            print_usage(&opts, "");
            0
        }
        Operation::Version => {
            print_version();
            0
        }
        Operation::ConfigHelp => {
            Config::print_docs();
            0
        }
        Operation::Stdin { input, config_path } => {
            // try to read config from local directory
            let (mut config, _) = match_cli_path_or_file(config_path, &env::current_dir().unwrap())
                                      .expect("Error resolving config");

            // write_mode is always Plain for Stdin.
            config.write_mode = WriteMode::Plain;

            run_from_stdin(input, &config);
            0
        }
        Operation::Format { files, config_path } => {
            let mut config = Config::default();
            let mut path = None;
            // Load the config path file if provided
            if let Some(config_file) = config_path {
                let (cfg_tmp, path_tmp) = resolve_config(config_file.as_ref())
                                              .expect(&format!("Error resolving config for {:?}",
                                                               config_file));
                config = cfg_tmp;
                path = path_tmp;
            };
            if let Some(path) = path.as_ref() {
                println!("Using rustfmt config file {}", path.display());
            }
            for file in files {
                // Check the file directory if the config-path could not be read or not provided
                if path.is_none() {
                    let (config_tmp, path_tmp) = resolve_config(file.parent().unwrap())
                                                     .expect(&format!("Error resolving config \
                                                                       for {}",
                                                                      file.display()));
                    if let Some(path) = path_tmp.as_ref() {
                        println!("Using rustfmt config file {} for {}",
                                 path.display(),
                                 file.display());
                    }
                    config = config_tmp;
                }

                if let Err(e) = update_config(&mut config, &matches) {
                    print_usage(&opts, &e);
                    return 1;
                }
                run(&file, &config);
            }
            0
        }
    }
}

fn main() {
    let _ = env_logger::init();
    let exit_code = execute();

    // Make sure standard output is flushed before we exit.
    std::io::stdout().flush().unwrap();

    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

fn print_usage(opts: &Options, reason: &str) {
    let reason = format!("{}\nusage: {} [options] <file>...",
                         reason,
                         env::args_os().next().unwrap().to_string_lossy());
    println!("{}", opts.usage(&reason));
}

fn print_version() {
    println!("{}.{}.{}{}",
             option_env!("CARGO_PKG_VERSION_MAJOR").unwrap_or("X"),
             option_env!("CARGO_PKG_VERSION_MINOR").unwrap_or("X"),
             option_env!("CARGO_PKG_VERSION_PATCH").unwrap_or("X"),
             option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""));
}

fn determine_operation(matches: &Matches) -> Operation {
    if matches.opt_present("h") {
        return Operation::Help;
    }

    if matches.opt_present("config-help") {
        return Operation::ConfigHelp;
    }

    if matches.opt_present("version") {
        return Operation::Version;
    }

    // Read the config_path and convert to parent dir if a file is provided.
    let config_path: Option<PathBuf> = matches.opt_str("config-path")
                                              .map(PathBuf::from)
                                              .and_then(|dir| {
                                                  if dir.is_file() {
                                                      return dir.parent().map(|v| v.into());
                                                  }
                                                  Some(dir)
                                              });

    // if no file argument is supplied, read from stdin
    if matches.free.is_empty() {

        let mut buffer = String::new();
        match io::stdin().read_to_string(&mut buffer) {
            Ok(..) => (),
            Err(e) => return Operation::InvalidInput { reason: e.to_string() },
        }

        return Operation::Stdin {
            input: buffer,
            config_path: config_path,
        };
    }

    let files: Vec<_> = matches.free.iter().map(PathBuf::from).collect();

    Operation::Format {
        files: files,
        config_path: config_path,
    }
}
<commit_msg>Write non-output to stderr when there is output<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg(not(test))]

#[macro_use]
extern crate log;
extern crate rustfmt;
extern crate toml;
extern crate env_logger;
extern crate getopts;

use rustfmt::{run, run_from_stdin};
use rustfmt::config::{Config, WriteMode};

use std::env;
use std::fs::{self, File};
use std::io::{self, ErrorKind, Read, Write};
use std::path::{Path, PathBuf};
use std::str::FromStr;

use getopts::{Matches, Options};

macro_rules! msg(
    ($($arg:tt)*) => (
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

/// Rustfmt operations.
enum Operation {
    /// Format files and their child modules.
    Format {
        files: Vec<PathBuf>,
        config_path: Option<PathBuf>,
    },
    /// Print the help message.
    Help,
    // Print version information
    Version,
    /// Print detailed configuration help.
    ConfigHelp,
    /// Invalid program input.
    InvalidInput {
        reason: String,
    },
    /// No file specified, read from stdin
    Stdin {
        input: String,
        config_path: Option<PathBuf>,
    },
}

/// Try to find a project file in the given directory and its parents. Returns the path of a the
/// nearest project file if one exists, or `None` if no project file was found.
fn lookup_project_file(dir: &Path) -> io::Result<Option<PathBuf>> {
    let mut current = if dir.is_relative() {
        try!(env::current_dir()).join(dir)
    } else {
        dir.to_path_buf()
    };

    current = try!(fs::canonicalize(current));

    loop {
        let config_file = current.join("rustfmt.toml");
        match fs::metadata(&config_file) {
            Ok(md) => {
                // Properly handle unlikely situation of a directory named `rustfmt.toml`.
                if md.is_file() {
                    return Ok(Some(config_file));
                }
            }
            // If it's not found, we continue searching; otherwise something went wrong and we
            // return the error.
            Err(e) => {
                if e.kind() != ErrorKind::NotFound {
                    return Err(e);
                }
            }
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Ok(None);
        }
    }
}

/// Resolve the config for input in `dir`.
///
/// Returns the `Config` to use, and the path of the project file if there was
/// one.
fn resolve_config(dir: &Path) -> io::Result<(Config, Option<PathBuf>)> {
    let path = try!(lookup_project_file(dir));
    if path.is_none() {
        return Ok((Config::default(), None));
    }
    let path = path.unwrap();
    let mut file = try!(File::open(&path));
    let mut toml = String::new();
    try!(file.read_to_string(&mut toml));
    Ok((Config::from_toml(&toml), Some(path)))
}

/// read the given config file path recursively if present else read the project file path
fn match_cli_path_or_file(config_path: Option<PathBuf>,
                          input_file: &Path)
                          -> io::Result<(Config, Option<PathBuf>)> {

    if let Some(config_file) = config_path {
        let (toml, path) = try!(resolve_config(config_file.as_ref()));
        if path.is_some() {
            return Ok((toml, path));
        }
    }
    resolve_config(input_file)
}

fn update_config(config: &mut Config, matches: &Matches) -> Result<(), String> {
    config.verbose = matches.opt_present("verbose");
    config.skip_children = matches.opt_present("skip-children");

    let write_mode = matches.opt_str("write-mode");
    match matches.opt_str("write-mode").map(|wm| WriteMode::from_str(&wm)) {
        None => Ok(()),
        Some(Ok(write_mode)) => {
            config.write_mode = write_mode;
            Ok(())
        }
        Some(Err(_)) => Err(format!("Invalid write-mode: {}", write_mode.expect("cannot happen"))),
    }
}

fn execute() -> i32 {
    let mut opts = Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("V", "version", "show version information");
    opts.optflag("v", "verbose", "show progress");
    opts.optopt("",
                "write-mode",
                "mode to write in (not usable when piping from stdin)",
                "[replace|overwrite|display|diff|coverage|checkstyle]");
    opts.optflag("", "skip-children", "don't reformat child modules");

    opts.optflag("",
                 "config-help",
                 "show details of rustfmt configuration options");
    opts.optopt("",
                "config-path",
                "Recursively searches the given path for the rustfmt.toml config file. If not \
                 found reverts to the input file path",
                "[Path for the configuration file]");

    let matches = match opts.parse(env::args().skip(1)) {
        Ok(m) => m,
        Err(e) => {
            print_usage(&opts, &e.to_string());
            return 1;
        }
    };

    let operation = determine_operation(&matches);

    match operation {
        Operation::InvalidInput { reason } => {
            print_usage(&opts, &reason);
            1
        }
        Operation::Help => {
            print_usage(&opts, "");
            0
        }
        Operation::Version => {
            print_version();
            0
        }
        Operation::ConfigHelp => {
            Config::print_docs();
            0
        }
        Operation::Stdin { input, config_path } => {
            // try to read config from local directory
            let (mut config, _) = match_cli_path_or_file(config_path, &env::current_dir().unwrap())
                                      .expect("Error resolving config");

            // write_mode is always Plain for Stdin.
            config.write_mode = WriteMode::Plain;

            run_from_stdin(input, &config);
            0
        }
        Operation::Format { files, config_path } => {
            let mut config = Config::default();
            let mut path = None;
            // Load the config path file if provided
            if let Some(config_file) = config_path {
                let (cfg_tmp, path_tmp) = resolve_config(config_file.as_ref())
                                              .expect(&format!("Error resolving config for {:?}",
                                                               config_file));
                config = cfg_tmp;
                path = path_tmp;
            };
            if let Some(path) = path.as_ref() {
                msg!("Using rustfmt config file {}", path.display());
            }
            for file in files {
                // Check the file directory if the config-path could not be read or not provided
                if path.is_none() {
                    let (config_tmp, path_tmp) = resolve_config(file.parent().unwrap())
                                                     .expect(&format!("Error resolving config \
                                                                       for {}",
                                                                      file.display()));
                    if let Some(path) = path_tmp.as_ref() {
                        msg!("Using rustfmt config file {} for {}",
                                 path.display(),
                                 file.display());
                    }
                    config = config_tmp;
                }

                if let Err(e) = update_config(&mut config, &matches) {
                    print_usage(&opts, &e);
                    return 1;
                }
                run(&file, &config);
            }
            0
        }
    }
}

fn main() {
    let _ = env_logger::init();
    let exit_code = execute();

    // Make sure standard output is flushed before we exit.
    std::io::stdout().flush().unwrap();

    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

fn print_usage(opts: &Options, reason: &str) {
    let reason = format!("{}\nusage: {} [options] <file>...",
                         reason,
                         env::args_os().next().unwrap().to_string_lossy());
    println!("{}", opts.usage(&reason));
}

fn print_version() {
    println!("{}.{}.{}{}",
             option_env!("CARGO_PKG_VERSION_MAJOR").unwrap_or("X"),
             option_env!("CARGO_PKG_VERSION_MINOR").unwrap_or("X"),
             option_env!("CARGO_PKG_VERSION_PATCH").unwrap_or("X"),
             option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""));
}

fn determine_operation(matches: &Matches) -> Operation {
    if matches.opt_present("h") {
        return Operation::Help;
    }

    if matches.opt_present("config-help") {
        return Operation::ConfigHelp;
    }

    if matches.opt_present("version") {
        return Operation::Version;
    }

    // Read the config_path and convert to parent dir if a file is provided.
    let config_path: Option<PathBuf> = matches.opt_str("config-path")
                                              .map(PathBuf::from)
                                              .and_then(|dir| {
                                                  if dir.is_file() {
                                                      return dir.parent().map(|v| v.into());
                                                  }
                                                  Some(dir)
                                              });

    // if no file argument is supplied, read from stdin
    if matches.free.is_empty() {

        let mut buffer = String::new();
        match io::stdin().read_to_string(&mut buffer) {
            Ok(..) => (),
            Err(e) => return Operation::InvalidInput { reason: e.to_string() },
        }

        return Operation::Stdin {
            input: buffer,
            config_path: config_path,
        };
    }

    let files: Vec<_> = matches.free.iter().map(PathBuf::from).collect();

    Operation::Format {
        files: files,
        config_path: config_path,
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate alice;
extern crate rand;

use std::fs::File;
use std::io::Cursor;
use glium::{DisplayBuild, Surface};
use glium::glutin::{Event, ElementState, VirtualKeyCode/*, MouseScrollDelta, MouseButton*/};
//use alice::model::rendering::{ModelRenderer, prepare_model};
use alice::model::{Model/*, Path, Point*/};
use alice::widget::rendering::ElementRenderer;
use alice::widget::{Element, Widget, Group, Grid, ModelElement, Text};
//use alice::data::{Vec2, Vec3};
//use rand::{thread_rng, Rng};

fn main() {
    let display = glium::glutin::WindowBuilder::new()
        .with_title(format!("Alice"))
        .with_dimensions(1024, 768)
        .with_vsync()
        .build_glium()
        .unwrap();
    let window = display.get_window().unwrap();

    //let mut renderer = ModelRenderer::new(&display);

    let model = if let Some(path) = std::env::args().nth(1) {
        let file = File::open(path).unwrap();
        let mut reader = alice::data::BinaryReader::new(file);
        Model::read(&mut reader).unwrap()
    } else {
        let bytes = include_bytes!("cat.model");
        let file: Cursor<&[u8]> = Cursor::new(bytes);
        let mut reader = alice::data::BinaryReader::new(file);
        Model::read(&mut reader).unwrap()
    };

    //let mut wobble = WobbleModel::new(&model, 0.5, 0.95);

    let mut renderer = ElementRenderer::new(&display);

    let root = Element::Widget(Widget {
        location: (200.0, 100.0),
        size: (500.0, 300.0),
        fill_colour: (0.9, 0.0, 0.0, 1.0),

        children: vec![
            Element::Widget(Widget {
                location: (10.0, 20.0),
                size: (100.0, 100.0),
                fill_colour: (0.7, 0.3, 0.8, 1.0),
                .. Default::default()
            }),
            Element::Widget(Widget {
                location: (120.0, 20.0),
                size: (100.0, 100.0),
                fill_colour: (0.3, 0.8, 0.7, 1.0),
                border_colour: (0.9, 0.3, 0.9),
                border_width: 10,
                .. Default::default()
            }),
            Element::Group(Group {
                location: (300.0, 200.0),
                children: vec![
                    Element::Widget(Widget {
                        location: (0.0, 0.0),
                        size: (20.0, 20.0),
                        fill_colour: (0.8, 0.7, 0.3, 1.0),
                        .. Default::default()
                    }),
                    Element::Widget(Widget {
                        location: (25.0, 0.0),
                        size: (20.0, 20.0),
                        fill_colour: (0.3, 0.3, 0.7, 1.0),
                        .. Default::default()
                    }),
                ]
            }),
            Element::Grid(Grid {
                bounds: ((100.0, 100.0), (400.0, 300.0)),
                size: (50.0, 20.0),
                offset: (0.0, 0.0),
                colour: (0.9, 0.9, 0.9),
                .. Default::default()
            }),
            Element::Model(ModelElement {
                location: (250.0, 150.0),
                scale: 0.2,
                model: model
            }),
            Element::Text(Text {
                location: (2.0, 2.0),
                size: 12.0,
                colour: (1.0, 1.0, 1.0),
                value: "Hello World!".to_string()
            })
        ],
        .. Default::default()
    });

    /*let mut x = 512.0;
    let mut y = 384.0;
    let mut scale = 1.0;
    let mut mouse_pos = (0, 0);*/

    loop {
        let mut target = display.draw();
        target.clear_color(0.02, 0.02, 0.02, 1.0);

        let (w, h) = window.get_inner_size_points().unwrap();
        renderer.set_size(w as f32, h as f32);

        renderer.draw(&mut target, &root);

        /*wobble.tick();
        let model = prepare_model(&display, &wobble.model());
        renderer.draw(&mut target, x, y, scale, &model);*/

        target.finish().unwrap();

        for ev in display.poll_events() {
            match ev {
                Event::Closed => return,
                Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Escape)) => return,
                /*Event::ReceivedCharacter(' ') => wobble.shuffle(10.0 / scale as f64),
                Event::ReceivedCharacter('+') => scale *= 1.1,
                Event::ReceivedCharacter('=') => scale *= 1.1,
                Event::ReceivedCharacter('-') => scale /= 1.1,
                Event::ReceivedCharacter('0') => {
                    x = w as f32 / 2.0;
                    y = h as f32 / 2.0;
                    scale = 1.0;
                }
                Event::MouseWheel(MouseScrollDelta::PixelDelta(dx, dy)) => {
                    x -= dx;
                    y += dy;
                },
                Event::MouseMoved(p) => mouse_pos = p,
                Event::MouseInput(ElementState::Pressed, MouseButton::Left) => {
                    let f = window.hidpi_factor() as f64;
                    let (mx, my) = (mouse_pos.0 as f64 / f, h as f64 - mouse_pos.1 as f64 / f);
                    let (mx, my) = (mx - x as f64, my - y as f64);
                    let (mx, my) = (mx / scale as f64, my / scale as f64);
                    wobble.push((mx, my), 0.3, 100.0 / scale as f64)
                },*/
                _ => ()
            }
        }
    }
}

/*struct WobbleModel {
    spring: f64,
    damping: f64,
    paths: Vec<WobblePath>,
}

struct WobblePath {
    colour: Vec3,
    points: Vec<WobblePoint>
}

struct WobblePoint {
    location: Vec2,
    curve_bias: f64,
    offset: Vec2,
    velocity: Vec2
}

fn gauss(c: f64, x: f64) -> f64 {
    (-x * x / (2.0 * c * c)).exp()
}

impl WobbleModel {
    pub fn new(model: &Model, spring: f64, damping: f64) -> WobbleModel {
        WobbleModel {
            spring: spring,
            damping: damping,
            paths: model.paths
                .iter()
                .map(|path| WobblePath {
                    colour: path.colour,
                    points: path.points
                        .iter()
                        .map(|point| WobblePoint {
                            location: point.location,
                            curve_bias: point.curve_bias,
                            offset: (0.0, 0.0),
                            velocity: (0.0, 0.0)
                        })
                        .collect()
                })
                .collect()
        }
    }

    pub fn model(&self) -> Model {
        Model {
            paths: self.paths
                .iter()
                .map(|path| Path {
                    colour: path.colour,
                    points: path.points
                        .iter()
                        .map(|point| {
                            let x = point.location.0 + point.offset.0;
                            let y = point.location.1 + point.offset.1;
                            Point {
                                location: (x, y),
                                curve_bias: point.curve_bias
                            }
                        })
                        .collect()
                })
                .collect()
        }
    }

    pub fn shuffle(&mut self, v: f64) {
        let mut rng = rand::thread_rng();
        for path in self.paths.iter_mut() {
            for point in path.points.iter_mut() {
                point.velocity.0 += rng.gen_range(-v, v);
                point.velocity.1 += rng.gen_range(-v, v);
            }
        }
    }

    pub fn push(&mut self, (x, y): Vec2, s: f64, w: f64) {
        for path in self.paths.iter_mut() {
            for point in path.points.iter_mut() {
                let (px, py) = point.location;
                let (dx, dy) = (px - x, py - y);
                let d = (dx * dx + dy * dy).sqrt();
                let d = s * gauss(w, d);

                point.velocity.0 += d * dx;
                point.velocity.1 += d * dy;
            }
        }
    }

    pub fn tick(&mut self) {
        for path in self.paths.iter_mut() {
            for point in path.points.iter_mut() {
                let (mut ox, mut oy) = point.offset;
                let (mut vx, mut vy) = point.velocity;

                vx += -self.spring * ox;
                vy += -self.spring * oy;
                vx *= self.damping;
                vy *= self.damping;

                ox += vx;
                oy += vy;

                point.offset = (ox, oy);
                point.velocity = (vx, vy);
            }
        }
    }
}
*/
<commit_msg>Remove old rubbish from widgets.rs<commit_after>#[macro_use]
extern crate glium;
extern crate alice;
extern crate rand;

use std::fs::File;
use std::io::Cursor;
use glium::{DisplayBuild, Surface};
use glium::glutin::{Event, ElementState, VirtualKeyCode};
use alice::model::{Model};
use alice::widget::rendering::ElementRenderer;
use alice::widget::{Element, Widget, Group, Grid, ModelElement, Text};

fn main() {
    let display = glium::glutin::WindowBuilder::new()
        .with_title(format!("Alice"))
        .with_dimensions(1024, 768)
        .with_vsync()
        .build_glium()
        .unwrap();
    let window = display.get_window().unwrap();

    let model = if let Some(path) = std::env::args().nth(1) {
        let file = File::open(path).unwrap();
        let mut reader = alice::data::BinaryReader::new(file);
        Model::read(&mut reader).unwrap()
    } else {
        let bytes = include_bytes!("cat.model");
        let file: Cursor<&[u8]> = Cursor::new(bytes);
        let mut reader = alice::data::BinaryReader::new(file);
        Model::read(&mut reader).unwrap()
    };

    let mut renderer = ElementRenderer::new(&display);

    let root = Element::Widget(Widget {
        location: (200.0, 100.0),
        size: (500.0, 300.0),
        fill_colour: (0.9, 0.0, 0.0, 1.0),

        children: vec![
            Element::Widget(Widget {
                location: (10.0, 20.0),
                size: (100.0, 100.0),
                fill_colour: (0.7, 0.3, 0.8, 1.0),
                .. Default::default()
            }),
            Element::Widget(Widget {
                location: (120.0, 20.0),
                size: (100.0, 100.0),
                fill_colour: (0.3, 0.8, 0.7, 1.0),
                border_colour: (0.9, 0.3, 0.9),
                border_width: 10,
                .. Default::default()
            }),
            Element::Group(Group {
                location: (300.0, 200.0),
                children: vec![
                    Element::Widget(Widget {
                        location: (0.0, 0.0),
                        size: (20.0, 20.0),
                        fill_colour: (0.8, 0.7, 0.3, 1.0),
                        .. Default::default()
                    }),
                    Element::Widget(Widget {
                        location: (25.0, 0.0),
                        size: (20.0, 20.0),
                        fill_colour: (0.3, 0.3, 0.7, 1.0),
                        .. Default::default()
                    }),
                ]
            }),
            Element::Grid(Grid {
                bounds: ((100.0, 100.0), (400.0, 300.0)),
                size: (50.0, 20.0),
                offset: (0.0, 0.0),
                colour: (0.9, 0.9, 0.9),
                .. Default::default()
            }),
            Element::Model(ModelElement {
                location: (250.0, 150.0),
                scale: 0.2,
                model: model
            }),
            Element::Text(Text {
                location: (2.0, 2.0),
                size: 12.0,
                colour: (1.0, 1.0, 1.0),
                value: "Hello World!".to_string()
            })
        ],
        .. Default::default()
    });

    loop {
        let mut target = display.draw();
        target.clear_color(0.02, 0.02, 0.02, 1.0);

        let (w, h) = window.get_inner_size_points().unwrap();
        renderer.set_size(w as f32, h as f32);

        renderer.draw(&mut target, &root);

        target.finish().unwrap();

        for ev in display.poll_events() {
            match ev {
                Event::Closed => return,
                Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Escape)) => return,
                _ => ()
            }
        }
    }
}
<|endoftext|>


<commit_before>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the self-application combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinators Y and Z](https://en.wikipedia.org/wiki/Fixed-point_combinator)
//! * the reverse application combinator T

use term::{Term, abs, app};
use term::Term::*;

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(i(), Var(1)), NOR, 0, false), Var(1));
/// assert_eq!(beta(app(i(), abs(Var(1))), NOR, 0, false), abs(Var(1)));
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = TRUE
///
/// # Example
/// ```
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(k(), Var(1), Var(2)), NOR, 0, false), Var(1));
/// assert_eq!(beta(app!(k(), Var(2), Var(1)), NOR, 0, false), Var(2));
/// ```
pub fn k() -> Term { abs!(2, Var(2)) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::*;
///
/// assert_eq!(
///     beta(app!(s(), Var(1), Var(2), Var(3)), NOR, 0, false),
///     app!(Var(1), Var(3), app(Var(2), Var(3)))
/// );
/// ```
pub fn s() -> Term {
    abs!(3, app!(Var(3), Var(1), app(Var(2), Var(1))))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(iota(), iota()), NOR, 0, false), i());
/// assert_eq!(beta(app(iota(), app(iota(), app(iota(), iota()))), NOR, 0, false), k());
/// assert_eq!(beta(app(iota(), app(iota(), app(iota(), app(iota(), iota())))), NOR, 0, false), s());
/// ```
pub fn iota() -> Term { abs(app!(Var(1), s(), k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::*;
///
/// assert_eq!(
///     beta(app!(b(), Var(1), Var(2), Var(3)), NOR, 0, false),
///     app(Var(1), app(Var(2), Var(3)))
/// );
/// ```
pub fn b() -> Term {
    abs!(3, app(Var(3), app(Var(2), Var(1))))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::*;
///
/// assert_eq!(
///     beta(app!(c(), Var(1), Var(2), Var(3)), NOR, 0, false),
///     app!(Var(1), Var(3), Var(2))
/// );
/// ```
pub fn c() -> Term {
    abs!(3, app!(Var(3), Var(1), Var(2)))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::*;
///
/// assert_eq!(
///     beta(app!(w(), Var(1), Var(2)), NOR, 0, false),
///     app!(Var(1), Var(2), Var(2))
/// );
/// ```
pub fn w() -> Term {
    abs!(2, app!(Var(2), Var(1), Var(1)))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs!(2, app(Var(1), app!(Var(2), Var(2), Var(1)))) }
*/
/// ω - the self-application combinator.
///
/// ω := λx.x x = λ 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::*;
///
/// assert_eq!(
///     beta(app(om(), Var(1)), NOR, 0, false),
///     app(Var(1), Var(1))
/// );
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
/// ```
/// use lambda_calculus::combinators::omm;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(omm(), NOR, 3, false), omm()); // 3 β-reductions do nothing
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the lazy fixed-point combinator.
///
/// It is suitable for `NOR` (normal), `HNO` (hybrid normal), `CBN` (call-by-name) and `HSP`
/// (head spine) reduction `Order`s.
///
/// Y := λf.(λx.f (x x)) (λx.f (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
///
/// # Example
/// ```
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::*;
///
/// fn dummy() -> Term { abs(Var(2)) } // a dummy term that won't easily reduce
///
/// assert_eq!(
///     beta(app(y(), dummy()), NOR, 0, false),
///     beta(app(dummy(), app(y(), dummy())), NOR, 0, false)
/// );
/// ```
pub fn y() -> Term {
    abs(app(
        abs(app(Var(2), app(Var(1), Var(1)))),
        abs(app(Var(2), app(Var(1), Var(1))))
    ))
}

/// Z - the strict fixed-point combinator.
///
/// It will work with all the reduction orders suitable for its lazy counterpart (the `Y`
/// combinator). In addition, it will also work with `CBV` (call-by-value) and `HAP` (hybrid
/// applicative) reduction `Order`s, but with them it's not a drop-in replacement for the `Y`
/// combinator - in order for such expressions to work, they need to be modified so that the
/// evaluation of arguments of conditionals and other terms that need to be lazy is delayed.
///
/// Z := λf.(λx.f (λv.x x v)) (λx.f (λv.x x v)) = λ (λ 2 (λ 2 2 1)) (λ 2 (λ 2 2 1))
///
/// # Example
/// ```
/// use lambda_calculus::combinators::z;
/// use lambda_calculus::*;
///
/// fn dummy() -> Term { abs(Var(2)) } // a dummy term that won't easily reduce
///
/// assert_eq!(
///     beta(app(z(), dummy()), CBV, 0, false),
///     beta(app(dummy(), app(z(), dummy())), CBV, 0, false)
/// );
/// ```
pub fn z() -> Term {
    abs(app(
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1))))),
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1)))))
    ))
}

/// T - the reverse application combinator.
///
/// T := λxf. f x = λ λ 1 2
///
/// # Example
/// ```
/// use lambda_calculus::combinators::t;
/// use lambda_calculus::*;
///
/// assert_eq!(
///     beta(app!(t(), Var(1), Var(2)), NOR, 0, false),
///     app(Var(2), Var(1))
/// );
/// ```
pub fn t() -> Term {
    abs!(2, app(Var(1), Var(2)))
}
<commit_msg>remove the unused U combinator<commit_after>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
//! * the self-application combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinators Y and Z](https://en.wikipedia.org/wiki/Fixed-point_combinator)
//! * the reverse application combinator T

use term::{Term, abs, app};
use term::Term::*;

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(i(), Var(1)), NOR, 0, false), Var(1));
/// assert_eq!(beta(app(i(), abs(Var(1))), NOR, 0, false), abs(Var(1)));
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = TRUE
///
/// # Example
/// ```
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(k(), Var(1), Var(2)), NOR, 0, false), Var(1));
/// assert_eq!(beta(app!(k(), Var(2), Var(1)), NOR, 0, false), Var(2));
/// ```
pub fn k() -> Term { abs!(2, Var(2)) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::*;
///
/// assert_eq!(
///     beta(app!(s(), Var(1), Var(2), Var(3)), NOR, 0, false),
///     app!(Var(1), Var(3), app(Var(2), Var(3)))
/// );
/// ```
pub fn s() -> Term {
    abs!(3, app!(Var(3), Var(1), app(Var(2), Var(1))))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(iota(), iota()), NOR, 0, false), i());
/// assert_eq!(beta(app(iota(), app(iota(), app(iota(), iota()))), NOR, 0, false), k());
/// assert_eq!(beta(app(iota(), app(iota(), app(iota(), app(iota(), iota())))), NOR, 0, false), s());
/// ```
pub fn iota() -> Term { abs(app!(Var(1), s(), k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::*;
///
/// assert_eq!(
///     beta(app!(b(), Var(1), Var(2), Var(3)), NOR, 0, false),
///     app(Var(1), app(Var(2), Var(3)))
/// );
/// ```
pub fn b() -> Term {
    abs!(3, app(Var(3), app(Var(2), Var(1))))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::*;
///
/// assert_eq!(
///     beta(app!(c(), Var(1), Var(2), Var(3)), NOR, 0, false),
///     app!(Var(1), Var(3), Var(2))
/// );
/// ```
pub fn c() -> Term {
    abs!(3, app!(Var(3), Var(1), Var(2)))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::*;
///
/// assert_eq!(
///     beta(app!(w(), Var(1), Var(2)), NOR, 0, false),
///     app!(Var(1), Var(2), Var(2))
/// );
/// ```
pub fn w() -> Term {
    abs!(2, app!(Var(2), Var(1), Var(1)))
}

/// ω - the self-application combinator.
///
/// ω := λx.x x = λ 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::*;
///
/// assert_eq!(
///     beta(app(om(), Var(1)), NOR, 0, false),
///     app(Var(1), Var(1))
/// );
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
/// ```
/// use lambda_calculus::combinators::omm;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(omm(), NOR, 3, false), omm()); // 3 β-reductions do nothing
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the lazy fixed-point combinator.
///
/// It is suitable for `NOR` (normal), `HNO` (hybrid normal), `CBN` (call-by-name) and `HSP`
/// (head spine) reduction `Order`s.
///
/// Y := λf.(λx.f (x x)) (λx.f (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
///
/// # Example
/// ```
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::*;
///
/// fn dummy() -> Term { abs(Var(2)) } // a dummy term that won't easily reduce
///
/// assert_eq!(
///     beta(app(y(), dummy()), NOR, 0, false),
///     beta(app(dummy(), app(y(), dummy())), NOR, 0, false)
/// );
/// ```
pub fn y() -> Term {
    abs(app(
        abs(app(Var(2), app(Var(1), Var(1)))),
        abs(app(Var(2), app(Var(1), Var(1))))
    ))
}

/// Z - the strict fixed-point combinator.
///
/// It will work with all the reduction orders suitable for its lazy counterpart (the `Y`
/// combinator). In addition, it will also work with `CBV` (call-by-value) and `HAP` (hybrid
/// applicative) reduction `Order`s, but with them it's not a drop-in replacement for the `Y`
/// combinator - in order for such expressions to work, they need to be modified so that the
/// evaluation of arguments of conditionals and other terms that need to be lazy is delayed.
///
/// Z := λf.(λx.f (λv.x x v)) (λx.f (λv.x x v)) = λ (λ 2 (λ 2 2 1)) (λ 2 (λ 2 2 1))
///
/// # Example
/// ```
/// use lambda_calculus::combinators::z;
/// use lambda_calculus::*;
///
/// fn dummy() -> Term { abs(Var(2)) } // a dummy term that won't easily reduce
///
/// assert_eq!(
///     beta(app(z(), dummy()), CBV, 0, false),
///     beta(app(dummy(), app(z(), dummy())), CBV, 0, false)
/// );
/// ```
pub fn z() -> Term {
    abs(app(
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1))))),
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1)))))
    ))
}

/// T - the reverse application combinator.
///
/// T := λxf. f x = λ λ 1 2
///
/// # Example
/// ```
/// use lambda_calculus::combinators::t;
/// use lambda_calculus::*;
///
/// assert_eq!(
///     beta(app!(t(), Var(1), Var(2)), NOR, 0, false),
///     app(Var(2), Var(1))
/// );
/// ```
pub fn t() -> Term {
    abs!(2, app(Var(1), Var(2)))
}
<|endoftext|>


<commit_before>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the looping combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinators Y and Z](https://en.wikipedia.org/wiki/Fixed-point_combinator)
//! * the thrush (reverse application) combinator T

use term::*;
use term::Term::*;

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(i().app(zero()), &Normal, None), zero());
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = TRUE
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(k(), zero(), one()), &Normal, None), zero());
/// # }
/// ```
pub fn k() -> Term { abs(abs(Var(2))) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(s(), 0.into(), 1.into(), 2.into()), &Normal, None),
///            beta(app!(Term::from(0), 2.into(), app!(Term::from(1), 2.into())), &Normal, None)
/// );
/// # }
/// ```
pub fn s() -> Term {
    abs(abs(abs(
        app!(Var(3), Var(1), app(Var(2), Var(1)))
    )))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(iota(), iota()), &Normal, None), i());
/// assert_eq!(beta(app!(iota(), app!(iota(), app!(iota(), iota()))), &Normal, None), k());
/// assert_eq!(beta(app!(iota(), app!(iota(), app!(iota(), app!(iota(), iota())))), &Normal, None),
///            s());
/// # }
/// ```
pub fn iota() -> Term { abs(app!(Var(1), s(), k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(b(), 0.into(),           1.into(), 2.into() ), &Normal, None),
///            beta(app!(Term::from(0), app!(Term::from(1), 2.into())), &Normal, None)
/// );
/// # }
/// ```
pub fn b() -> Term {
    abs(abs(abs(
        app(Var(3), app(Var(2), Var(1)))
    )))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(c(), 0.into(), 1.into(), 2.into()), &Normal, None),
///            beta(app!(Term::from(0), 2.into(), 1.into()), &Normal, None)
/// );
/// # }
/// ```
pub fn c() -> Term {
    abs(abs(abs(
        app!(Var(3), Var(1), Var(2))
    )))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(   w(), zero(), one()), &Normal, None),
///            beta(app!(zero(),  one(), one()), &Normal, None)
/// );
/// # }
/// ```
pub fn w() -> Term {
    abs(abs(
        app!(Var(2), Var(1), Var(1))
    ))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs(abs(Var(1).app(Var(2).app(Var(2)).app(Var(1))))) }
*/
/// ω - the looping combinator.
///
/// ω := λx.x x = λ 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(  om().app(zero()), &Normal, None),
///            beta(zero().app(zero()), &Normal, None)
/// );
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
/// ```
/// use lambda_calculus::combinators::omm;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(omm(), &Normal, Some(3)), omm());
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the lazy fixed-point combinator intended for the `Normal` evaluation `Order`.
///
/// Y := λf.(λx.f (x x)) (λx.f (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(             app!(y(), zero() ), &Normal, None),
///            beta(app!(zero(), app!(y(), zero())), &Normal, None)
/// );
/// # }
/// ```
pub fn y() -> Term {
    abs(app(
        abs(app(Var(2), app(Var(1), Var(1)))),
        abs(app(Var(2), app(Var(1), Var(1))))
    ))
}

/// Z - the strict fixed-point combinator intended for the `CallByValue` evaluation `Order`.
///
/// Z := λf.(λx.f (λv.x x v)) (λx.f (λv.x x v)) = λ (λ 2 (λ 2 2 1)) (λ 2 (λ 2 2 1))
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::z;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(             app!(z(), zero()) , &CallByValue, None),
///            beta(app!(zero(), app!(z(), zero())), &CallByValue, None)
/// );
/// # }
/// ```
pub fn z() -> Term {
    abs(app(
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1))))),
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1)))))
    ))
}

/// T - the thrush combinator
///
/// T := λxf. f x = λ λ 1 2
///
/// # Example
/// ```
/// use lambda_calculus::combinators::t;
/// use lambda_calculus::arithmetic::{zero, one};
///
/// assert_eq!(t().apply(&zero()).and_then(|t| t.apply(&one())), Ok(one().app(zero())));
/// ```
pub fn t() -> Term {
    abs(abs(
        app(Var(1), Var(2))
    ))
}
<commit_msg>improve Y and Z combinator docs<commit_after>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the looping combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinators Y and Z](https://en.wikipedia.org/wiki/Fixed-point_combinator)
//! * the thrush (reverse application) combinator T

use term::*;
use term::Term::*;

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(i().app(zero()), &Normal, None), zero());
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = TRUE
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(k(), zero(), one()), &Normal, None), zero());
/// # }
/// ```
pub fn k() -> Term { abs(abs(Var(2))) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(s(), 0.into(), 1.into(), 2.into()), &Normal, None),
///            beta(app!(Term::from(0), 2.into(), app!(Term::from(1), 2.into())), &Normal, None)
/// );
/// # }
/// ```
pub fn s() -> Term {
    abs(abs(abs(
        app!(Var(3), Var(1), app(Var(2), Var(1)))
    )))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(iota(), iota()), &Normal, None), i());
/// assert_eq!(beta(app!(iota(), app!(iota(), app!(iota(), iota()))), &Normal, None), k());
/// assert_eq!(beta(app!(iota(), app!(iota(), app!(iota(), app!(iota(), iota())))), &Normal, None),
///            s());
/// # }
/// ```
pub fn iota() -> Term { abs(app!(Var(1), s(), k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(b(), 0.into(),           1.into(), 2.into() ), &Normal, None),
///            beta(app!(Term::from(0), app!(Term::from(1), 2.into())), &Normal, None)
/// );
/// # }
/// ```
pub fn b() -> Term {
    abs(abs(abs(
        app(Var(3), app(Var(2), Var(1)))
    )))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(c(), 0.into(), 1.into(), 2.into()), &Normal, None),
///            beta(app!(Term::from(0), 2.into(), 1.into()), &Normal, None)
/// );
/// # }
/// ```
pub fn c() -> Term {
    abs(abs(abs(
        app!(Var(3), Var(1), Var(2))
    )))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(   w(), zero(), one()), &Normal, None),
///            beta(app!(zero(),  one(), one()), &Normal, None)
/// );
/// # }
/// ```
pub fn w() -> Term {
    abs(abs(
        app!(Var(2), Var(1), Var(1))
    ))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs(abs(Var(1).app(Var(2).app(Var(2)).app(Var(1))))) }
*/
/// ω - the looping combinator.
///
/// ω := λx.x x = λ 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(  om().app(zero()), &Normal, None),
///            beta(zero().app(zero()), &Normal, None)
/// );
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
/// ```
/// use lambda_calculus::combinators::omm;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(omm(), &Normal, Some(3)), omm());
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the lazy fixed-point combinator suitable for `Normal` and `HybridNormal` β-reduction
/// `Order`s.
///
/// Y := λf.(λx.f (x x)) (λx.f (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(             app!(y(), zero() ), &Normal, None),
///            beta(app!(zero(), app!(y(), zero())), &Normal, None)
/// );
/// # }
/// ```
pub fn y() -> Term {
    abs(app(
        abs(app(Var(2), app(Var(1), Var(1)))),
        abs(app(Var(2), app(Var(1), Var(1))))
    ))
}

/// Z - the strict fixed-point combinator suitable for `Normal`, `HybridNormal`, `CallByValue` and
/// `HybridApplicative` β-reduction `Order`s.
///
/// Z := λf.(λx.f (λv.x x v)) (λx.f (λv.x x v)) = λ (λ 2 (λ 2 2 1)) (λ 2 (λ 2 2 1))
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::z;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(             app!(z(), zero() ), &CallByValue, None),
///            beta(app!(zero(), app!(z(), zero())), &CallByValue, None)
/// );
/// # }
/// ```
pub fn z() -> Term {
    abs(app(
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1))))),
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1)))))
    ))
}

/// T - the thrush combinator
///
/// T := λxf. f x = λ λ 1 2
///
/// # Example
/// ```
/// use lambda_calculus::combinators::t;
/// use lambda_calculus::arithmetic::{zero, one};
///
/// assert_eq!(t().apply(&zero()).and_then(|t| t.apply(&one())), Ok(one().app(zero())));
/// ```
pub fn t() -> Term {
    abs(abs(
        app(Var(1), Var(2))
    ))
}
<|endoftext|>


<commit_before>extern crate brotli2;
extern crate flate2;
extern crate zopfli;

use structs::*;
use errors::*;
use std::fs::File;
use std::io::{Read, Write};

use std::path::Path;

impl CompressionFormat for CompressionAlgorithm {
    fn extension(&self) -> &'static str {
        match self {
            &CompressionAlgorithm::Brotli => "br",
            &CompressionAlgorithm::GZip => "gz",
            &CompressionAlgorithm::WebP => "webp",
            &CompressionAlgorithm::Zopfli => "gz",
        }
    }
}

impl FileCompressor for CompressionAlgorithm {
    fn compress(&self, src: &Path, dst: &Path, quality: Option<u8>) -> Result<()> {
        match self {
            &CompressionAlgorithm::GZip => gzip_compress(src, dst, quality),
            &CompressionAlgorithm::Brotli => brotli_compress(src, dst, quality),
            &CompressionAlgorithm::WebP => webp_compress(src, dst, quality),
            &CompressionAlgorithm::Zopfli => zopfli_compress(src, dst),
            // _ => bail!("Compression algorithm not implemented!"),
        }
    }
}

fn gzip_compress(src_path: &Path, dst_path: &Path, quality: Option<u8>) -> Result<()> {
    let mut src = File::open(src_path)?;
    let dst = File::create(dst_path)?;

    let level = match quality {
        None => flate2::Compression::Default,
        Some(0) => flate2::Compression::None,
        Some(1) => flate2::Compression::Fast,
        Some(2...6) => flate2::Compression::Default,
        Some(3...9) => flate2::Compression::Best,
        _ => bail!("Invalid --quality parameter specified!"),
    };

    let mut encoder = flate2::write::GzEncoder::new(dst, level);
    let mut buf = [0u8; 1024];
    loop {
        let bytes_read = src.read(&mut buf).chain_err(|| "Error reading from source file!")?;
        match bytes_read {
            0 => break, //end of file
            l => encoder.write_all(&buf[0..l]).chain_err(|| "Fatal gzip encoder error!")?,
        };
    }

    Ok(())
}

fn brotli_compress(src_path: &Path, dst_path: &Path, quality: Option<u8>) -> Result<()> {
    let mut src = File::open(src_path)?;
    let dst = File::create(dst_path)?;

    let level = match quality {
        None => 6,
        Some(q @ 0...11) => q,
        _ => bail!("Invalid --quality parameter specified!"),
    };

    let mut encoder = brotli2::write::BrotliEncoder::new(dst, level as u32);
    let mut buf = [0u8; 1024];
    loop {
        let bytes_read = src.read(&mut buf).chain_err(|| "Error reading from source file!")?;
        match bytes_read {
            0 => break, //end of file
            l => encoder.write_all(&buf[0..l]).chain_err(|| "Fatal gzip encoder error!")?,
        };
    }

    Ok(())
}

fn zopfli_compress(src_path: &Path, dst_path: &Path) -> Result<()> {
    let mut src = File::open(src_path)?;
    let mut dst = File::create(dst_path)?;

    let mut src_data = Vec::<u8>::new();
    src.read_to_end(&mut src_data)?;

    zopfli::compress(&zopfli::Options::default(), &zopfli::Format::Gzip, &mut src_data, &mut dst)?;

    Ok(())
}

fn webp_compress(src_path: &Path, dst_path: &Path, quality: Option<u8>) -> Result<()> {
    use std::process::Command;

    let output = Command::new("cwebp")
        .arg("-q")
        .arg(quality.unwrap_or(90).to_string())
        .arg(src_path.as_os_str())
        .arg("-o")
        .arg(dst_path.as_os_str())
        .output()
        .chain_err(|| "Error executing cwebp!")?;

    if !output.status.success() {
        bail!("Error compressing via webp: {:?}", output);
    }

    Ok(())
}
<commit_msg>Bail when --quality is specified for zopfli compression<commit_after>extern crate brotli2;
extern crate flate2;
extern crate zopfli;

use structs::*;
use errors::*;
use std::fs::File;
use std::io::{Read, Write};

use std::path::Path;

impl CompressionFormat for CompressionAlgorithm {
    fn extension(&self) -> &'static str {
        match self {
            &CompressionAlgorithm::Brotli => "br",
            &CompressionAlgorithm::GZip => "gz",
            &CompressionAlgorithm::WebP => "webp",
            &CompressionAlgorithm::Zopfli => "gz",
        }
    }
}

impl FileCompressor for CompressionAlgorithm {
    fn compress(&self, src: &Path, dst: &Path, quality: Option<u8>) -> Result<()> {
        match self {
            &CompressionAlgorithm::GZip => gzip_compress(src, dst, quality),
            &CompressionAlgorithm::Brotli => brotli_compress(src, dst, quality),
            &CompressionAlgorithm::WebP => webp_compress(src, dst, quality),
            &CompressionAlgorithm::Zopfli => zopfli_compress(src, dst, quality),
            // _ => bail!("Compression algorithm not implemented!"),
        }
    }
}

fn gzip_compress(src_path: &Path, dst_path: &Path, quality: Option<u8>) -> Result<()> {
    let mut src = File::open(src_path)?;
    let dst = File::create(dst_path)?;

    let level = match quality {
        None => flate2::Compression::Default,
        Some(0) => flate2::Compression::None,
        Some(1) => flate2::Compression::Fast,
        Some(2...6) => flate2::Compression::Default,
        Some(3...9) => flate2::Compression::Best,
        _ => bail!("Invalid --quality parameter specified!"),
    };

    let mut encoder = flate2::write::GzEncoder::new(dst, level);
    let mut buf = [0u8; 1024];
    loop {
        let bytes_read = src.read(&mut buf).chain_err(|| "Error reading from source file!")?;
        match bytes_read {
            0 => break, //end of file
            l => encoder.write_all(&buf[0..l]).chain_err(|| "Fatal gzip encoder error!")?,
        };
    }

    Ok(())
}

fn brotli_compress(src_path: &Path, dst_path: &Path, quality: Option<u8>) -> Result<()> {
    let mut src = File::open(src_path)?;
    let dst = File::create(dst_path)?;

    let level = match quality {
        None => 6,
        Some(q @ 0...11) => q,
        _ => bail!("Invalid --quality parameter specified!"),
    };

    let mut encoder = brotli2::write::BrotliEncoder::new(dst, level as u32);
    let mut buf = [0u8; 1024];
    loop {
        let bytes_read = src.read(&mut buf).chain_err(|| "Error reading from source file!")?;
        match bytes_read {
            0 => break, //end of file
            l => encoder.write_all(&buf[0..l]).chain_err(|| "Fatal gzip encoder error!")?,
        };
    }

    Ok(())
}

fn zopfli_compress(src_path: &Path, dst_path: &Path, quality: Option<u8>) -> Result<()> {
    if quality.is_some() {
        bail!("--quality is not implemented for zopfli compression");
    }

    let mut src = File::open(src_path)?;
    let mut dst = File::create(dst_path)?;

    let mut src_data = Vec::<u8>::new();
    src.read_to_end(&mut src_data)?;

    zopfli::compress(&zopfli::Options::default(), &zopfli::Format::Gzip, &mut src_data, &mut dst)?;

    Ok(())
}

fn webp_compress(src_path: &Path, dst_path: &Path, quality: Option<u8>) -> Result<()> {
    use std::process::Command;

    let output = Command::new("cwebp")
        .arg("-q")
        .arg(quality.unwrap_or(90).to_string())
        .arg(src_path.as_os_str())
        .arg("-o")
        .arg(dst_path.as_os_str())
        .output()
        .chain_err(|| "Error executing cwebp!")?;

    if !output.status.success() {
        bail!("Error compressing via webp: {:?}", output);
    }

    Ok(())
}
<|endoftext|>


<commit_before>use dispatcher::request::InternalRequest;

pub use self::linear::LinearContext;
pub use self::map::MapContext;

pub mod base;
pub mod event;
pub mod map;

pub enum Context {
    Linear(LinearContext),
    Map(MapContext)
}

impl From<Context> for Box<self::event::EventHandler<InternalRequest>> {
    fn from(context: Context) -> Box<self::event::EventHandler<InternalRequest>> {
        match context {
            Context::Linear(context) => Box::new(context),
            Context::Map(context) => Box::new(context),
        }
    }
}

pub mod linear {
    use uuid::Uuid;
    use std::rc::Rc;

    use conditions::Conditions;
    use context::event::{EventHandler};
    use message::{Message};
    use state::State;
    use timer::TimerEvent;
    use dispatcher::request::{InternalRequest, Request};
    use context::base::{
        BaseContext,
        BaseContextBuilder
    };

    pub struct LinearContext {
        base: BaseContext,
        state: State
    }

    impl LinearContext {
        pub fn new(uuid: Uuid, conditions: Conditions) -> LinearContext {
            LinearContext {
                base: BaseContextBuilder::new(uuid, conditions).build(),
                state: State::new()
            }
        }

        pub fn on_event(&mut self, event: InternalRequest) {
            match event {
                Request::Timer(event) => {
                    self.on_timer(&event)
                },
                Request::Message(message) => {
                    self.on_message(message)
                },
                _ => {}
            }
        }

        pub fn on_timer(&mut self, event: &TimerEvent) {
            self.base.on_timer(event, &mut self.state)
        }

        pub fn on_message(&mut self, event: Rc<Message>) {
            self.base.on_message(event, &mut self.state);
        }

        pub fn is_open(&self) -> bool {
            self.state.is_open()
        }

        pub fn patterns(&self) -> &[String] {
            &self.base.conditions().patterns
        }
    }

    impl From<BaseContext> for LinearContext {
        fn from(context: BaseContext) -> LinearContext {
            println!("LinearContext created with uuid: {}", &context.uuid().to_hyphenated_string());
            println!("LinearContext created with name: {:?}", &context.name());
            LinearContext {
                base: context,
                state: State::new()
            }
        }
    }

    impl EventHandler<InternalRequest> for LinearContext {
        fn handlers(&self) -> &[String] {
            self.patterns()
        }
        fn handle_event(&mut self, event: InternalRequest) {
            println!("LinearContext: handle_event() {:?}", self.base.name());
            self.on_event(event);
        }
    }
}

#[cfg(test)]
mod test {
    use uuid::Uuid;
    use std::rc::Rc;

    use message::{
        MessageBuilder
    };
    use timer::TimerEvent;
    use context::LinearContext;
    use conditions::ConditionsBuilder;

    #[test]
    fn test_given_close_condition_with_timeout_when_the_timeout_expires_then_the_condition_is_met() {
        let timeout = 100;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), ConditionsBuilder::new(timeout).patterns(patterns).build());
        let msg1 = MessageBuilder::new(&msg_id).build();
        let event = Rc::new(msg1);
        assert_false!(context.is_open());
        context.on_message(event);
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(50));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(49));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_max_size_when_the_max_size_reached_then_the_condition_is_met() {
        let timeout = 100;
        let max_size = 3;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), ConditionsBuilder::new(timeout).max_size(max_size).patterns(patterns).build());
        let msg1 = MessageBuilder::new(&msg_id).build();
        let event = Rc::new(msg1);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_without_renewing_messages_then_the_condition_is_met() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), ConditionsBuilder::new(timeout).renew_timeout(renew_timeout).patterns(patterns).build());
        let msg1 = MessageBuilder::new(&msg_id).build();
        let event = Rc::new(msg1);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_with_renewing_messages_then_the_context_is_not_closed() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), ConditionsBuilder::new(timeout).renew_timeout(renew_timeout).patterns(patterns).build());
        let msg1 = MessageBuilder::new(&msg_id).build();
        let event = Rc::new(msg1);
        assert_false!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
    }
}
<commit_msg>context: export BaseContext and BaseContextBuilder<commit_after>use dispatcher::request::InternalRequest;

pub use self::linear::LinearContext;
pub use self::map::MapContext;
pub use self::base::BaseContext;
pub use self::base::BaseContextBuilder;

pub mod base;
pub mod event;
pub mod map;

pub enum Context {
    Linear(LinearContext),
    Map(MapContext)
}

impl From<Context> for Box<self::event::EventHandler<InternalRequest>> {
    fn from(context: Context) -> Box<self::event::EventHandler<InternalRequest>> {
        match context {
            Context::Linear(context) => Box::new(context),
            Context::Map(context) => Box::new(context),
        }
    }
}

pub mod linear {
    use uuid::Uuid;
    use std::rc::Rc;

    use conditions::Conditions;
    use context::event::{EventHandler};
    use message::{Message};
    use state::State;
    use timer::TimerEvent;
    use dispatcher::request::{InternalRequest, Request};
    use context::base::{
        BaseContext,
        BaseContextBuilder
    };

    pub struct LinearContext {
        base: BaseContext,
        state: State
    }

    impl LinearContext {
        pub fn new(uuid: Uuid, conditions: Conditions) -> LinearContext {
            LinearContext {
                base: BaseContextBuilder::new(uuid, conditions).build(),
                state: State::new()
            }
        }

        pub fn on_event(&mut self, event: InternalRequest) {
            match event {
                Request::Timer(event) => {
                    self.on_timer(&event)
                },
                Request::Message(message) => {
                    self.on_message(message)
                },
                _ => {}
            }
        }

        pub fn on_timer(&mut self, event: &TimerEvent) {
            self.base.on_timer(event, &mut self.state)
        }

        pub fn on_message(&mut self, event: Rc<Message>) {
            self.base.on_message(event, &mut self.state);
        }

        pub fn is_open(&self) -> bool {
            self.state.is_open()
        }

        pub fn patterns(&self) -> &[String] {
            &self.base.conditions().patterns
        }
    }

    impl From<BaseContext> for LinearContext {
        fn from(context: BaseContext) -> LinearContext {
            println!("LinearContext created with uuid: {}", &context.uuid().to_hyphenated_string());
            println!("LinearContext created with name: {:?}", &context.name());
            LinearContext {
                base: context,
                state: State::new()
            }
        }
    }

    impl EventHandler<InternalRequest> for LinearContext {
        fn handlers(&self) -> &[String] {
            self.patterns()
        }
        fn handle_event(&mut self, event: InternalRequest) {
            println!("LinearContext: handle_event() {:?}", self.base.name());
            self.on_event(event);
        }
    }
}

#[cfg(test)]
mod test {
    use uuid::Uuid;
    use std::rc::Rc;

    use message::{
        MessageBuilder
    };
    use timer::TimerEvent;
    use context::LinearContext;
    use conditions::ConditionsBuilder;

    #[test]
    fn test_given_close_condition_with_timeout_when_the_timeout_expires_then_the_condition_is_met() {
        let timeout = 100;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), ConditionsBuilder::new(timeout).patterns(patterns).build());
        let msg1 = MessageBuilder::new(&msg_id).build();
        let event = Rc::new(msg1);
        assert_false!(context.is_open());
        context.on_message(event);
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(50));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(49));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_max_size_when_the_max_size_reached_then_the_condition_is_met() {
        let timeout = 100;
        let max_size = 3;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), ConditionsBuilder::new(timeout).max_size(max_size).patterns(patterns).build());
        let msg1 = MessageBuilder::new(&msg_id).build();
        let event = Rc::new(msg1);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_without_renewing_messages_then_the_condition_is_met() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), ConditionsBuilder::new(timeout).renew_timeout(renew_timeout).patterns(patterns).build());
        let msg1 = MessageBuilder::new(&msg_id).build();
        let event = Rc::new(msg1);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_with_renewing_messages_then_the_context_is_not_closed() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), ConditionsBuilder::new(timeout).renew_timeout(renew_timeout).patterns(patterns).build());
        let msg1 = MessageBuilder::new(&msg_id).build();
        let event = Rc::new(msg1);
        assert_false!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

use std::fs::File;
use std::io::{BufReader, Read};
use std::mem;
use std::path::Path;
use std::ptr;

use hex;
use libsodium_sys;

use error::Result;

const BUF_SIZE: usize = 1024;

/// Calculate the BLAKE2b hash of a file, return as a hex string
/// digest size = 32 BYTES
/// NOTE: the hashing is keyless
pub fn hash_file<P>(filename: P) -> Result<String>
where
    P: AsRef<Path>,
{
    let file = File::open(filename.as_ref())?;
    let mut reader = BufReader::new(file);
    hash_reader(&mut reader)
}

pub fn hash_string(data: &str) -> String {
    let mut out = [0u8; libsodium_sys::crypto_generichash_BYTES];
    let mut st = vec![0u8; (unsafe { libsodium_sys::crypto_generichash_statebytes() })];
    let pst = unsafe {
        mem::transmute::<*mut u8, *mut libsodium_sys::crypto_generichash_state>(st.as_mut_ptr())
    };
    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
        libsodium_sys::crypto_generichash_update(pst, data[..].as_ptr(), data.len() as u64);
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    hex::encode(out)
}

pub fn hash_bytes(data: &[u8]) -> String {
    let mut out = [0u8; libsodium_sys::crypto_generichash_BYTES];
    let mut st = vec![0u8; (unsafe { libsodium_sys::crypto_generichash_statebytes() })];
    let pst = unsafe {
        mem::transmute::<*mut u8, *mut libsodium_sys::crypto_generichash_state>(st.as_mut_ptr())
    };
    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
        libsodium_sys::crypto_generichash_update(pst, data[..].as_ptr(), data.len() as u64);
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    hex::encode(out)
}

pub fn hash_reader(reader: &mut BufReader<File>) -> Result<String> {
    let mut out = [0u8; libsodium_sys::crypto_generichash_BYTES];
    let mut st = vec![0u8; (unsafe { libsodium_sys::crypto_generichash_statebytes() })];
    let pst = unsafe {
        mem::transmute::<*mut u8, *mut libsodium_sys::crypto_generichash_state>(st.as_mut_ptr())
    };
    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
    }
    let mut buf = [0u8; BUF_SIZE];
    loop {
        let bytes_read = reader.read(&mut buf)?;
        if bytes_read == 0 {
            break;
        }
        let chunk = &buf[0..bytes_read];
        unsafe {
            libsodium_sys::crypto_generichash_update(pst, chunk.as_ptr(), chunk.len() as u64);
        }
    }
    unsafe {
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    Ok(hex::encode(out))
}

#[cfg(test)]
mod test {
    use std::env;
    #[allow(unused_imports)]
    use std::fs::{self, File};
    #[allow(unused_imports)]
    use std::io;
    use std::path::PathBuf;

    #[cfg(feature = "functional")]
    use hyper::{header, Client, Url};
    use super::*;
    use super::super::test_support::*;

    #[allow(dead_code)]
    fn mk_local_tmpdir() -> PathBuf {
        let dir = env::current_exe()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .join("tmp");
        fs::create_dir_all(&dir).unwrap();
        dir
    }

    #[test]
    fn hash_file_working() {
        // The expected values were computed using the `b2sum` program from
        // https://github.com/dchest/b2sum using the the `-s=32` option. For example:
        //      b2sum -s=32 signme.dat

        let computed = hash_file(&fixture("signme.dat")).unwrap();
        let expected = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
        assert_eq!(computed, expected);

        let computed = hash_file(&fixture("happyhumans-20160424223347.sig.key")).unwrap();
        let expected = "e966844bbc50b7a3a6d81e94dd38e27b92814b944095a8e55f1780921bfcfbe1";
        assert_eq!(computed, expected);

        let computed = hash_file(&fixture("happyhumans-20160424223347.pub")).unwrap();
        let expected = "b80c4f412f9a0a7727b6e6f115e1b5fa3bae79ad2fcf47f769ed4e42cfb12265";
        assert_eq!(computed, expected);
    }

    #[test]
    #[cfg(feature = "functional")]
    fn hash_file_large_binary() {
        let url = "http://ftp.kernel.org/pub/linux/kernel/v4.x/linux-4.3.tar.gz";
        let dst: PathBuf = {
            let file = mk_local_tmpdir().join(url.rsplit('/').next().unwrap());
            if !file.is_file() {
                let client = match env::var("http_proxy") {
                    Ok(url) => {
                        let url = Url::parse(&url).unwrap();
                        Client::with_http_proxy(
                            url.host_str().unwrap().to_string(),
                            url.port_or_known_default().unwrap(),
                        )
                    }
                    _ => Client::new(),
                };
                let mut response = client
                    .get(url)
                    .header(header::Connection::close())
                    .send()
                    .unwrap();
                let mut f = File::create(&file).unwrap();
                io::copy(&mut response, &mut f).unwrap();
            }
            file
        };
        let computed = hash_file(&dst);
        let expected = "ba640dc063f0ed27e60b38dbb7cf19778cf7805d9fc91eb129fb68b409d46414";
        assert_eq!(computed, expected);
    }
}
<commit_msg>[core] Address Rust 1.25.0 compiler warnings in crypto module.<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

use std::fs::File;
use std::io::{BufReader, Read};
use std::mem;
use std::path::Path;
use std::ptr;

use hex;
use libsodium_sys;

use error::Result;

const BUF_SIZE: usize = 1024;

/// Calculate the BLAKE2b hash of a file, return as a hex string
/// digest size = 32 BYTES
/// NOTE: the hashing is keyless
pub fn hash_file<P>(filename: P) -> Result<String>
where
    P: AsRef<Path>,
{
    let file = File::open(filename.as_ref())?;
    let mut reader = BufReader::new(file);
    hash_reader(&mut reader)
}

pub fn hash_string(data: &str) -> String {
    let mut out = [0u8; libsodium_sys::crypto_generichash_BYTES];
    let mut st = vec![0u8; unsafe { libsodium_sys::crypto_generichash_statebytes() }];
    let pst = unsafe {
        mem::transmute::<*mut u8, *mut libsodium_sys::crypto_generichash_state>(st.as_mut_ptr())
    };
    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
        libsodium_sys::crypto_generichash_update(pst, data[..].as_ptr(), data.len() as u64);
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    hex::encode(out)
}

pub fn hash_bytes(data: &[u8]) -> String {
    let mut out = [0u8; libsodium_sys::crypto_generichash_BYTES];
    let mut st = vec![0u8; unsafe { libsodium_sys::crypto_generichash_statebytes() }];
    let pst = unsafe {
        mem::transmute::<*mut u8, *mut libsodium_sys::crypto_generichash_state>(st.as_mut_ptr())
    };
    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
        libsodium_sys::crypto_generichash_update(pst, data[..].as_ptr(), data.len() as u64);
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    hex::encode(out)
}

pub fn hash_reader(reader: &mut BufReader<File>) -> Result<String> {
    let mut out = [0u8; libsodium_sys::crypto_generichash_BYTES];
    let mut st = vec![0u8; unsafe { libsodium_sys::crypto_generichash_statebytes() }];
    let pst = unsafe {
        mem::transmute::<*mut u8, *mut libsodium_sys::crypto_generichash_state>(st.as_mut_ptr())
    };
    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
    }
    let mut buf = [0u8; BUF_SIZE];
    loop {
        let bytes_read = reader.read(&mut buf)?;
        if bytes_read == 0 {
            break;
        }
        let chunk = &buf[0..bytes_read];
        unsafe {
            libsodium_sys::crypto_generichash_update(pst, chunk.as_ptr(), chunk.len() as u64);
        }
    }
    unsafe {
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    Ok(hex::encode(out))
}

#[cfg(test)]
mod test {
    use std::env;
    #[allow(unused_imports)]
    use std::fs::{self, File};
    #[allow(unused_imports)]
    use std::io;
    use std::path::PathBuf;

    #[cfg(feature = "functional")]
    use hyper::{header, Client, Url};
    use super::*;
    use super::super::test_support::*;

    #[allow(dead_code)]
    fn mk_local_tmpdir() -> PathBuf {
        let dir = env::current_exe()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .join("tmp");
        fs::create_dir_all(&dir).unwrap();
        dir
    }

    #[test]
    fn hash_file_working() {
        // The expected values were computed using the `b2sum` program from
        // https://github.com/dchest/b2sum using the the `-s=32` option. For example:
        //      b2sum -s=32 signme.dat

        let computed = hash_file(&fixture("signme.dat")).unwrap();
        let expected = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
        assert_eq!(computed, expected);

        let computed = hash_file(&fixture("happyhumans-20160424223347.sig.key")).unwrap();
        let expected = "e966844bbc50b7a3a6d81e94dd38e27b92814b944095a8e55f1780921bfcfbe1";
        assert_eq!(computed, expected);

        let computed = hash_file(&fixture("happyhumans-20160424223347.pub")).unwrap();
        let expected = "b80c4f412f9a0a7727b6e6f115e1b5fa3bae79ad2fcf47f769ed4e42cfb12265";
        assert_eq!(computed, expected);
    }

    #[test]
    #[cfg(feature = "functional")]
    fn hash_file_large_binary() {
        let url = "http://ftp.kernel.org/pub/linux/kernel/v4.x/linux-4.3.tar.gz";
        let dst: PathBuf = {
            let file = mk_local_tmpdir().join(url.rsplit('/').next().unwrap());
            if !file.is_file() {
                let client = match env::var("http_proxy") {
                    Ok(url) => {
                        let url = Url::parse(&url).unwrap();
                        Client::with_http_proxy(
                            url.host_str().unwrap().to_string(),
                            url.port_or_known_default().unwrap(),
                        )
                    }
                    _ => Client::new(),
                };
                let mut response = client
                    .get(url)
                    .header(header::Connection::close())
                    .send()
                    .unwrap();
                let mut f = File::create(&file).unwrap();
                io::copy(&mut response, &mut f).unwrap();
            }
            file
        };
        let computed = hash_file(&dst);
        let expected = "ba640dc063f0ed27e60b38dbb7cf19778cf7805d9fc91eb129fb68b409d46414";
        assert_eq!(computed, expected);
    }
}
<|endoftext|>


<commit_before>//! Full implementation of HMAC in accordance with [RFC 2104](http://tools.ietf.org/html/rfc2104)
//!
//!# Examples
//!
//!```
//!use rust_oauth::crypto::hmac;
//!let key = "key".as_bytes();
//!let msg = "The quick brown fox jumps over the lazy dog".as_bytes();
//!let hmac = hmac::hmac_sha1(msg, key);
//!
//!
//!

use std::ops::{BitXor};
use super::sha1;

// HMAC constants defined in RFC
const BLOCKSIZE : uint = 64;
const IPAD : [u8, ..BLOCKSIZE] = [0x36u8, ..BLOCKSIZE];
const OPAD : [u8, ..BLOCKSIZE] = [0x5cu8, ..BLOCKSIZE];

struct U8BLOCK([u8, ..BLOCKSIZE]);

impl BitXor<[u8, ..BLOCKSIZE], [u8, ..BLOCKSIZE]> for U8BLOCK{
    fn bitxor(self, _rhs : [u8, ..BLOCKSIZE]) -> [u8, ..BLOCKSIZE]{
        let U8BLOCK(t) = self;
        let mut x = t;
        for i in range(0, BLOCKSIZE){
            x[i] = t[i] ^ _rhs[i];
        };
        x
    }
}

/// Generate the hmac using the hashing function, message, and key provided.
pub fn hmac_sha1(msg : &[u8], key : &[u8]) -> [u8, ..20]{
    let mut key_new : [u8, ..BLOCKSIZE] = [0u8, ..BLOCKSIZE];

    if key.len() > BLOCKSIZE{
        let hash = sha1::sha1(key);
        for x in range(0, hash.len()){
            key_new[x] = hash[x];
        }
    } else {
        for x in range(0, key.len()){
            key_new[x] = key[x];
        }
    }
    let mut v = Vec::new();
    v.push_all(&(U8BLOCK(key_new) ^ IPAD));
    v.push_all(msg);
    let temp : [u8, ..20] = sha1::sha1(v.as_slice());
    v = Vec::new();
    v.push_all(&(U8BLOCK(key_new) ^ OPAD));
    v.push_all(&temp);
    sha1::sha1(v.as_slice())

}

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

    #[test]
    fn hamc_test1(){
        let key = "key".as_bytes();
        let msg = "The quick brown fox jumps over the lazy dog".as_bytes();
        let h = hmac_sha1(msg, key);
        println!("");
        assert!(h ==
            [0xdeu8, 0x7cu8, 0x9bu8, 0x85u8, 0xb8u8,
             0xb7u8, 0x8au8, 0xa6u8, 0xbcu8, 0x8au8,
             0x7au8, 0x36u8, 0xf7u8, 0x0au8, 0x90u8,
             0x70u8, 0x1cu8, 0x9du8, 0xb4u8, 0xd9u8]);
    }
}
<commit_msg>Added second hmac_sha1 test<commit_after>//! Full implementation of HMAC in accordance with [RFC 2104](http://tools.ietf.org/html/rfc2104)
//!
//!# Examples
//!
//!```
//!use rust_oauth::crypto::hmac;
//!let key = "key".as_bytes();
//!let msg = "The quick brown fox jumps over the lazy dog".as_bytes();
//!let hmac = hmac::hmac_sha1(msg, key);
//!
//!
//!

use std::ops::{BitXor};
use super::sha1;

// HMAC constants defined in RFC 2104

const BLOCKSIZE : uint = 64;
const IPAD : [u8, ..BLOCKSIZE] = [0x36u8, ..BLOCKSIZE];
const OPAD : [u8, ..BLOCKSIZE] = [0x5cu8, ..BLOCKSIZE];

struct U8BLOCK([u8, ..BLOCKSIZE]);

impl BitXor<[u8, ..BLOCKSIZE], [u8, ..BLOCKSIZE]> for U8BLOCK{
    fn bitxor(self, _rhs : [u8, ..BLOCKSIZE]) -> [u8, ..BLOCKSIZE]{
        let U8BLOCK(t) = self;
        let mut x = t;
        for i in range(0, BLOCKSIZE){
            x[i] = t[i] ^ _rhs[i];
        };
        x
    }
}

/// Generate the hmac using the hashing function, message, and key provided.
pub fn hmac_sha1(msg : &[u8], key : &[u8]) -> [u8, ..20]{
    let mut key_new : [u8, ..BLOCKSIZE] = [0u8, ..BLOCKSIZE];

    if key.len() > BLOCKSIZE{
        let hash = sha1::sha1(key);
        for x in range(0, hash.len()){
            key_new[x] = hash[x];
        }
    } else {
        for x in range(0, key.len()){
            key_new[x] = key[x];
        }
    }
    let mut v = Vec::new();
    v.push_all(&(U8BLOCK(key_new) ^ IPAD));
    v.push_all(msg);
    let temp : [u8, ..20] = sha1::sha1(v.as_slice());
    v = Vec::new();
    v.push_all(&(U8BLOCK(key_new) ^ OPAD));
    v.push_all(&temp);
    sha1::sha1(v.as_slice())

}

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

    #[test]
    fn hmac_test1(){
        let key = "key".as_bytes();
        let msg = "The quick brown fox jumps over the lazy dog".as_bytes();
        let h = hmac_sha1(msg, key);
        assert!(h ==
            [0xdeu8, 0x7cu8, 0x9bu8, 0x85u8, 0xb8u8,
             0xb7u8, 0x8au8, 0xa6u8, 0xbcu8, 0x8au8,
             0x7au8, 0x36u8, 0xf7u8, 0x0au8, 0x90u8,
             0x70u8, 0x1cu8, 0x9du8, 0xb4u8, 0xd9u8]);
    }

    #[test]
    fn hmac_test2(){
        let key = "".as_bytes();
        let msg = "".as_bytes();
        let h = hmac_sha1(msg, key);
        assert!(h ==
            [0xfbu8, 0xdbu8, 0x1du8, 0x1bu8, 0x18u8,
             0xaau8, 0x6cu8, 0x08u8, 0x32u8, 0x4bu8,
             0x7du8, 0x64u8, 0xb7u8, 0x1fu8, 0xb7u8,
             0x63u8, 0x70u8, 0x69u8, 0x0eu8, 0x1du8])
    }

}
<|endoftext|>