<commit_before>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! Parse config files.
//!
//! # Usage
//!
//! Call the `parse` function on the input.

/*
 * TODO: add Cargo categories.
 * TODO: create a new method instead of using words and find/unwrap.
 * TODO: add the attribute #[special_command] in the Command derive macro.
 * TODO: auto-include files.
 * TODO: support set = without spaces around =.
 * TODO: Add array type.
 */

#![warn(missing_docs)]

pub mod error;
pub mod key;
#[macro_use]
mod macros;
#[doc(hidden)]
pub mod position;
pub mod settings;
mod string;

use std::collections::HashMap;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::marker::PhantomData;
use std::path::{Path, PathBuf};

use error::{Error, Result};
use error::ErrorType::{MissingArgument, NoCommand, Parse, UnknownCommand};
use key::{Key, parse_keys};
use position::Pos;
use string::{StrExt, check_ident, maybe_word, word, words};

use Command::*;
use Value::*;

/// Trait to specify the completion values for a type.
pub trait CompletionValues {
    /// Get the completion values for the type.
    fn completion_values() -> Vec<String>;
}

impl CompletionValues for bool {
    fn completion_values() -> Vec<String> {
        vec!["true".to_string(), "false".to_string()]
    }
}

impl CompletionValues for i64 {
    fn completion_values() -> Vec<String> {
        vec![]
    }
}

impl CompletionValues for String {
    fn completion_values() -> Vec<String> {
        vec![]
    }
}

/// The `EnumFromStr` trait is used to specify how to construct an enum value from a string.
pub trait EnumFromStr
    where Self: Sized
{
    /// Create the enum value from the `variant` string and an `argument` string.
    fn create(variant: &str, argument: &str) -> std::result::Result<Self, String>;

    /// Check wether the enum variant has an argument.
    fn has_argument(variant: &str) -> std::result::Result<bool, String>;
}

/// Tre `EnumMetaData` trait is used to get associated meta-data for the enum variants.
/// The meta-data is specified using the following attributes:
/// #[completion(hidden)]
/// #[special_command]
/// #[help(Command help)]
pub trait EnumMetaData {
    /// Get the metadata associated with the enum.
    fn get_metadata() -> HashMap<String, MetaData>;
}

/// Command/setting meta-data coming from the attributes.
/// See `EnumMetaData` to see the list of supported attributes.
#[derive(Debug)]
pub struct MetaData {
    /// Whether this command/setting should be shown in the completion or not.
    pub completion_hidden: bool,
    /// The help text associated with this command/setting.
    pub help_text: String,
    /// Whether this is a special command or not.
    /// This is not applicable to settings.
    pub is_special_command: bool,
}

/// Trait specifying the value completions for settings.
pub trait SettingCompletion {
    /// Get the value completions of all the setting.
    fn get_value_completions() -> HashMap<String, Vec<String>>;
}

/// The `Command` enum represents a command from a config file.
#[derive(Debug, PartialEq)]
pub enum Command<T> {
    /// A command from the application library.
    App(String),
    /// A custom command.
    Custom(T),
    /// A map command creates a new key mapping.
    Map {
        /// The action that will be executed when the `keys` are pressed.
        action: String,
        /// The key shortcut to trigger the action.
        keys: Vec<Key>,
        /// The mode in which this mapping is available.
        mode: String,
    },
    /// A set command sets a value to an option.
    Set(String, Value),
    /// An unmap command removes a key mapping.
    Unmap {
        /// The key shortcut to remove.
        keys: Vec<Key>,
        /// The mode in which this mapping is available.
        mode: String,
    },
}

/// The parsing configuration.
#[derive(Default)]
pub struct Config {
    /// The application library commands.
    pub application_commands: Vec<String>,
    /// The available mapping modes for the map command.
    pub mapping_modes: Vec<String>,
}

/// The config parser.
pub struct Parser<T> {
    column: usize,
    config: Config,
    include_path: PathBuf,
    line: usize,
    _phantom: PhantomData<T>,
}

impl<T: EnumFromStr> Parser<T> {
    /// Create a new parser without config.
    pub fn new() -> Self {
        Parser {
            column: 1,
            config: Config::default(),
            include_path: Path::new("./").to_path_buf(),
            line: 1,
            _phantom: PhantomData,
        }
    }

    /// Create a new parser with config.
    pub fn new_with_config(config: Config) -> Self {
        Parser {
            column: 1,
            config: config,
            include_path: Path::new("./").to_path_buf(),
            line: 1,
            _phantom: PhantomData,
        }
    }

    /// Check that we reached the end of the line.
    fn check_eol(&self, line: &str, index: usize) -> Result<()> {
        if line.len() > index {
            let rest = &line[index..];
            if let Some(word) = maybe_word(rest) {
                let index = rest.find(word).unwrap(); // NOTE: the line contains the word, hence unwrap.
                return Err(Box::new(Error::new(
                    Parse,
                    rest.to_string(),
                    "<end of line>".to_string(),
                    Pos::new(self.line, self.column + index),
                )));
            }
        }
        Ok(())
    }

    /// Parse a custom command or return an error if it does not exist.
    fn custom_command(&self, line: &str, word: &str, start_index: usize, index: usize) -> Result<Command<T>> {
        let args =
            if line.len() > start_index {
                line[start_index..].trim()
            }
            else if let Ok(true) = T::has_argument(word) {
                return Err(Box::new(self.missing_args(start_index)));
            }
            else {
                ""
            };
        if let Ok(command) = T::create(word, args) {
            Ok(Custom(command))
        }
        else if self.config.application_commands.contains(&word.to_string()) {
            Ok(App(word.to_string()))
        }
        else {
            Err(Box::new(Error::new(
                UnknownCommand,
                word.to_string(),
                "command or comment".to_string(),
                Pos::new(self.line, index + 1)
            )))
        }
    }

    /// Get the rest of the line, starting at `column`, returning an error if the column is greater
    /// than the line's length.
    fn get_rest<'a>(&self, line: &'a str, column: usize) -> Result<&'a str> {
        if line.len() > column {
            Ok(&line[column..])
        }
        else {
            Err(Box::new(self.missing_args(column)))
        }
    }

    /// Parse a line.
    fn line(&mut self, line: &str) -> Result<Vec<Command<T>>> {
        if let Some(word) = maybe_word(line) {
            // NOTE: the word is in the line, hence unwrap.
            let index = line.find(word).unwrap();
            let start_index = index + word.len() + 1;
            self.column = start_index + 1;

            let (start3, end3) = word.rsplit_at(3);
            let (start5, end5) = word.rsplit_at(5);
            if word.starts_with('#') {
                return Ok(vec![]);
            }

            if word == "include" {
                let rest = self.get_rest(line, start_index)?;
                self.include_command(rest)
            }
            else {
                let command =
                    if word == "set" {
                        let rest = self.get_rest(line, start_index)?;
                        self.set_command(rest)
                    }
                    else if end3 == "map" && self.config.mapping_modes.contains(&start3.to_string()) {
                        let rest = self.get_rest(line, start_index)?;
                        self.map_command(rest, start3)
                    }
                    else if end5 == "unmap" && self.config.mapping_modes.contains(&start5.to_string()) {
                        let rest = self.get_rest(line, start_index)?;
                        self.unmap_command(rest, start5)
                    }
                    else {
                        self.custom_command(line, word, start_index, index)
                    };
                command.map(|command| vec![command])
            }
        }
        else {
            Ok(vec![])
        }
    }

    /// Parse an include command.
    fn include_command(&mut self, line: &str) -> Result<Vec<Command<T>>> {
        let word = word(line);
        // NOTE: the line contains the word, hence unwrap.
        let index = line.find(word).unwrap();
        let after_index = index + word.len() + 1;
        self.column += after_index;
        self.check_eol(line, after_index)?;
        let path = Path::new(&self.include_path).join(word);
        let file = File::open(path)?;
        let buf_reader = BufReader::new(file);
        let commands = self.parse(buf_reader)?;
        Ok(commands)
    }

    /// Parse a map command.
    fn map_command(&self, line: &str, mode: &str) -> Result<Command<T>> {
        let word = word(line);

        // NOTE: the line contains the word, hence unwrap.
        let index = line.find(word).unwrap();

        let rest = &line[index + word.len() ..].trim();
        if !rest.is_empty() {
            Ok(Map {
                action: rest.to_string(),
                keys: parse_keys(word, self.line, self.column + index)?,
                mode: mode.to_string(),
            })
        }
        else {
            Err(Box::new(Error::new(
                Parse,
                "<end of line>".to_string(),
                "mapping action".to_string(),
                Pos::new(self.line, self.column + line.len())
            )))
        }
    }

    /// Get an missing arguments error.
    fn missing_args(&self, column: usize) -> Error {
        Error::new(
            MissingArgument,
            "<end of line>".to_string(),
            "command arguments".to_string(),
            Pos::new(self.line, column)
        )
    }

    /// Parse settings.
    pub fn parse<R: BufRead>(&mut self, input: R) -> Result<Vec<Command<T>>> {
        let mut commands = vec![];
        for (line_num, input_line) in input.lines().enumerate() {
            self.line = line_num + 1;
            let mut new_commands = self.line(&input_line?)?;
            commands.append(&mut new_commands);
        }
        Ok(commands)
    }

    /// Parse a single line of settings.
    pub fn parse_line(&mut self, line: &str) -> Result<Command<T>> {
        let mut commands = self.parse(line.as_bytes())?;
        match commands.pop() {
            Some(command) => Ok(command),
            None => Err(Box::new(Error::new(
                        NoCommand,
                        "comment or <end of line>".to_string(),
                        "command".to_string(),
                        Pos::new(self.line, self.column + line.len())
                    )))
        }
    }

    /// Parse a set command.
    fn set_command(&mut self, line: &str) -> Result<Command<T>> {
        if let Some(words) = words(line, 2) {
            // NOTE: the line contains the word, hence unwrap.
            let index = line.find(words[0]).unwrap();
            let identifier = check_ident(words[0].to_string(), &Pos::new(self.line, self.column + index))?;

            let operator = words[1];
            // NOTE: the operator is in the line, hence unwrap.
            let operator_index = line.find(operator).unwrap();
            if operator == "=" {
                let rest = &line[operator_index + 1..];
                self.column += operator_index + 1;
                Ok(Set(identifier.to_string(), self.value(rest)?))
            }
            else {
                Err(Box::new(Error::new(
                    Parse,
                    operator.to_string(),
                    "=".to_string(),
                    Pos::new(self.line, self.column + operator_index)
                )))
            }
        }
        else {
            Err(Box::new(Error::new(
                Parse,
                "<end of line>".to_string(),
                "=".to_string(),
                Pos::new(self.line, self.column + line.len()),
            )))
        }
    }

    /// Set the directory where the include command will look for files to include.
    pub fn set_include_path<P: AsRef<Path>>(&mut self, directory: P) {
        self.include_path = directory.as_ref().to_path_buf();
    }

    /// Parse an unmap command.
    fn unmap_command(&mut self, line: &str, mode: &str) -> Result<Command<T>> {
        let word = word(line);

        // NOTE: the line contains the word, hence unwrap.
        let index = line.find(word).unwrap();

        let after_index = index + word.len() + 1;
        self.column += after_index;
        self.check_eol(line, after_index)?;
        Ok(Unmap {
            keys: parse_keys(word, self.line, self.column + index)?,
            mode: mode.to_string(),
        })
    }

    /// Parse a value.
    fn value(&self, input: &str) -> Result<Value> {
        let string: String = input.chars().take_while(|&character| character != '#').collect();
        let string = string.trim();
        match string {
            "" => Err(Box::new(Error::new(
                      Parse,
                      "<end of line>".to_string(),
                      "value".to_string(),
                      Pos::new(self.line, self.column + string.len())
                  ))),
            "true" => Ok(Bool(true)),
            "false" => Ok(Bool(false)),
            _ => {
                if string.chars().all(|character| character.is_digit(10)) {
                    // NOTE: the string only contains digit, hence unwrap.
                    Ok(Int(string.parse().unwrap()))
                }
                else if string.chars().all(|character| character.is_digit(10) || character == '.') {
                    // NOTE: the string only contains digit or dot, hence unwrap.
                    Ok(Float(string.parse().unwrap()))
                }
                else {
                    Ok(Str(input.trim().to_string()))
                }
            },
        }
    }
}

/// The `Value` enum represents a value along with its type.
#[derive(Debug, PartialEq)]
pub enum Value {
    /// Boolean value.
    Bool(bool),
    /// Floating-point value.
    Float(f64),
    /// Integer value.
    Int(i64),
    /// String value.
    Str(String),
}

impl Value {
    /// Get a string representation of the value.
    pub fn to_type(&self) -> &str {
        match *self {
            Bool(_) => "bool",
            Float(_) => "float",
            Int(_) => "int",
            Str(_) => "string",
        }
    }
}
<commit_msg>Switch to &str for the mapping modes<commit_after>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! Parse config files.
//!
//! # Usage
//!
//! Call the `parse` function on the input.

/*
 * TODO: add Cargo categories.
 * TODO: create a new method instead of using words and find/unwrap.
 * TODO: add the attribute #[special_command] in the Command derive macro.
 * TODO: auto-include files.
 * TODO: support set = without spaces around =.
 * TODO: Add array type.
 */

#![warn(missing_docs)]

pub mod error;
pub mod key;
#[macro_use]
mod macros;
#[doc(hidden)]
pub mod position;
pub mod settings;
mod string;

use std::collections::HashMap;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::marker::PhantomData;
use std::path::{Path, PathBuf};

use error::{Error, Result};
use error::ErrorType::{MissingArgument, NoCommand, Parse, UnknownCommand};
use key::{Key, parse_keys};
use position::Pos;
use string::{StrExt, check_ident, maybe_word, word, words};

use Command::*;
use Value::*;

/// Trait to specify the completion values for a type.
pub trait CompletionValues {
    /// Get the completion values for the type.
    fn completion_values() -> Vec<String>;
}

impl CompletionValues for bool {
    fn completion_values() -> Vec<String> {
        vec!["true".to_string(), "false".to_string()]
    }
}

impl CompletionValues for i64 {
    fn completion_values() -> Vec<String> {
        vec![]
    }
}

impl CompletionValues for String {
    fn completion_values() -> Vec<String> {
        vec![]
    }
}

/// The `EnumFromStr` trait is used to specify how to construct an enum value from a string.
pub trait EnumFromStr
    where Self: Sized
{
    /// Create the enum value from the `variant` string and an `argument` string.
    fn create(variant: &str, argument: &str) -> std::result::Result<Self, String>;

    /// Check wether the enum variant has an argument.
    fn has_argument(variant: &str) -> std::result::Result<bool, String>;
}

/// Tre `EnumMetaData` trait is used to get associated meta-data for the enum variants.
/// The meta-data is specified using the following attributes:
/// #[completion(hidden)]
/// #[special_command]
/// #[help(Command help)]
pub trait EnumMetaData {
    /// Get the metadata associated with the enum.
    fn get_metadata() -> HashMap<String, MetaData>;
}

/// Command/setting meta-data coming from the attributes.
/// See `EnumMetaData` to see the list of supported attributes.
#[derive(Debug)]
pub struct MetaData {
    /// Whether this command/setting should be shown in the completion or not.
    pub completion_hidden: bool,
    /// The help text associated with this command/setting.
    pub help_text: String,
    /// Whether this is a special command or not.
    /// This is not applicable to settings.
    pub is_special_command: bool,
}

/// Trait specifying the value completions for settings.
pub trait SettingCompletion {
    /// Get the value completions of all the setting.
    fn get_value_completions() -> HashMap<String, Vec<String>>;
}

/// The `Command` enum represents a command from a config file.
#[derive(Debug, PartialEq)]
pub enum Command<T> {
    /// A command from the application library.
    App(String),
    /// A custom command.
    Custom(T),
    /// A map command creates a new key mapping.
    Map {
        /// The action that will be executed when the `keys` are pressed.
        action: String,
        /// The key shortcut to trigger the action.
        keys: Vec<Key>,
        /// The mode in which this mapping is available.
        mode: String,
    },
    /// A set command sets a value to an option.
    Set(String, Value),
    /// An unmap command removes a key mapping.
    Unmap {
        /// The key shortcut to remove.
        keys: Vec<Key>,
        /// The mode in which this mapping is available.
        mode: String,
    },
}

/// The parsing configuration.
#[derive(Default)]
pub struct Config {
    /// The application library commands.
    pub application_commands: Vec<String>,
    /// The available mapping modes for the map command.
    pub mapping_modes: Vec<&'static str>,
}

/// The config parser.
pub struct Parser<T> {
    column: usize,
    config: Config,
    include_path: PathBuf,
    line: usize,
    _phantom: PhantomData<T>,
}

impl<T: EnumFromStr> Parser<T> {
    /// Create a new parser without config.
    pub fn new() -> Self {
        Parser {
            column: 1,
            config: Config::default(),
            include_path: Path::new("./").to_path_buf(),
            line: 1,
            _phantom: PhantomData,
        }
    }

    /// Create a new parser with config.
    pub fn new_with_config(config: Config) -> Self {
        Parser {
            column: 1,
            config: config,
            include_path: Path::new("./").to_path_buf(),
            line: 1,
            _phantom: PhantomData,
        }
    }

    /// Check that we reached the end of the line.
    fn check_eol(&self, line: &str, index: usize) -> Result<()> {
        if line.len() > index {
            let rest = &line[index..];
            if let Some(word) = maybe_word(rest) {
                let index = rest.find(word).unwrap(); // NOTE: the line contains the word, hence unwrap.
                return Err(Box::new(Error::new(
                    Parse,
                    rest.to_string(),
                    "<end of line>".to_string(),
                    Pos::new(self.line, self.column + index),
                )));
            }
        }
        Ok(())
    }

    /// Parse a custom command or return an error if it does not exist.
    fn custom_command(&self, line: &str, word: &str, start_index: usize, index: usize) -> Result<Command<T>> {
        let args =
            if line.len() > start_index {
                line[start_index..].trim()
            }
            else if let Ok(true) = T::has_argument(word) {
                return Err(Box::new(self.missing_args(start_index)));
            }
            else {
                ""
            };
        if let Ok(command) = T::create(word, args) {
            Ok(Custom(command))
        }
        else if self.config.application_commands.contains(&word.to_string()) {
            Ok(App(word.to_string()))
        }
        else {
            Err(Box::new(Error::new(
                UnknownCommand,
                word.to_string(),
                "command or comment".to_string(),
                Pos::new(self.line, index + 1)
            )))
        }
    }

    /// Get the rest of the line, starting at `column`, returning an error if the column is greater
    /// than the line's length.
    fn get_rest<'a>(&self, line: &'a str, column: usize) -> Result<&'a str> {
        if line.len() > column {
            Ok(&line[column..])
        }
        else {
            Err(Box::new(self.missing_args(column)))
        }
    }

    /// Parse a line.
    fn line(&mut self, line: &str) -> Result<Vec<Command<T>>> {
        if let Some(word) = maybe_word(line) {
            // NOTE: the word is in the line, hence unwrap.
            let index = line.find(word).unwrap();
            let start_index = index + word.len() + 1;
            self.column = start_index + 1;

            let (start3, end3) = word.rsplit_at(3);
            let (start5, end5) = word.rsplit_at(5);
            if word.starts_with('#') {
                return Ok(vec![]);
            }

            if word == "include" {
                let rest = self.get_rest(line, start_index)?;
                self.include_command(rest)
            }
            else {
                let command =
                    if word == "set" {
                        let rest = self.get_rest(line, start_index)?;
                        self.set_command(rest)
                    }
                    else if end3 == "map" && self.config.mapping_modes.contains(&start3) {
                        let rest = self.get_rest(line, start_index)?;
                        self.map_command(rest, start3)
                    }
                    else if end5 == "unmap" && self.config.mapping_modes.contains(&start5) {
                        let rest = self.get_rest(line, start_index)?;
                        self.unmap_command(rest, start5)
                    }
                    else {
                        self.custom_command(line, word, start_index, index)
                    };
                command.map(|command| vec![command])
            }
        }
        else {
            Ok(vec![])
        }
    }

    /// Parse an include command.
    fn include_command(&mut self, line: &str) -> Result<Vec<Command<T>>> {
        let word = word(line);
        // NOTE: the line contains the word, hence unwrap.
        let index = line.find(word).unwrap();
        let after_index = index + word.len() + 1;
        self.column += after_index;
        self.check_eol(line, after_index)?;
        let path = Path::new(&self.include_path).join(word);
        let file = File::open(path)?;
        let buf_reader = BufReader::new(file);
        let commands = self.parse(buf_reader)?;
        Ok(commands)
    }

    /// Parse a map command.
    fn map_command(&self, line: &str, mode: &str) -> Result<Command<T>> {
        let word = word(line);

        // NOTE: the line contains the word, hence unwrap.
        let index = line.find(word).unwrap();

        let rest = &line[index + word.len() ..].trim();
        if !rest.is_empty() {
            Ok(Map {
                action: rest.to_string(),
                keys: parse_keys(word, self.line, self.column + index)?,
                mode: mode.to_string(),
            })
        }
        else {
            Err(Box::new(Error::new(
                Parse,
                "<end of line>".to_string(),
                "mapping action".to_string(),
                Pos::new(self.line, self.column + line.len())
            )))
        }
    }

    /// Get an missing arguments error.
    fn missing_args(&self, column: usize) -> Error {
        Error::new(
            MissingArgument,
            "<end of line>".to_string(),
            "command arguments".to_string(),
            Pos::new(self.line, column)
        )
    }

    /// Parse settings.
    pub fn parse<R: BufRead>(&mut self, input: R) -> Result<Vec<Command<T>>> {
        let mut commands = vec![];
        for (line_num, input_line) in input.lines().enumerate() {
            self.line = line_num + 1;
            let mut new_commands = self.line(&input_line?)?;
            commands.append(&mut new_commands);
        }
        Ok(commands)
    }

    /// Parse a single line of settings.
    pub fn parse_line(&mut self, line: &str) -> Result<Command<T>> {
        let mut commands = self.parse(line.as_bytes())?;
        match commands.pop() {
            Some(command) => Ok(command),
            None => Err(Box::new(Error::new(
                        NoCommand,
                        "comment or <end of line>".to_string(),
                        "command".to_string(),
                        Pos::new(self.line, self.column + line.len())
                    )))
        }
    }

    /// Parse a set command.
    fn set_command(&mut self, line: &str) -> Result<Command<T>> {
        if let Some(words) = words(line, 2) {
            // NOTE: the line contains the word, hence unwrap.
            let index = line.find(words[0]).unwrap();
            let identifier = check_ident(words[0].to_string(), &Pos::new(self.line, self.column + index))?;

            let operator = words[1];
            // NOTE: the operator is in the line, hence unwrap.
            let operator_index = line.find(operator).unwrap();
            if operator == "=" {
                let rest = &line[operator_index + 1..];
                self.column += operator_index + 1;
                Ok(Set(identifier.to_string(), self.value(rest)?))
            }
            else {
                Err(Box::new(Error::new(
                    Parse,
                    operator.to_string(),
                    "=".to_string(),
                    Pos::new(self.line, self.column + operator_index)
                )))
            }
        }
        else {
            Err(Box::new(Error::new(
                Parse,
                "<end of line>".to_string(),
                "=".to_string(),
                Pos::new(self.line, self.column + line.len()),
            )))
        }
    }

    /// Set the directory where the include command will look for files to include.
    pub fn set_include_path<P: AsRef<Path>>(&mut self, directory: P) {
        self.include_path = directory.as_ref().to_path_buf();
    }

    /// Parse an unmap command.
    fn unmap_command(&mut self, line: &str, mode: &str) -> Result<Command<T>> {
        let word = word(line);

        // NOTE: the line contains the word, hence unwrap.
        let index = line.find(word).unwrap();

        let after_index = index + word.len() + 1;
        self.column += after_index;
        self.check_eol(line, after_index)?;
        Ok(Unmap {
            keys: parse_keys(word, self.line, self.column + index)?,
            mode: mode.to_string(),
        })
    }

    /// Parse a value.
    fn value(&self, input: &str) -> Result<Value> {
        let string: String = input.chars().take_while(|&character| character != '#').collect();
        let string = string.trim();
        match string {
            "" => Err(Box::new(Error::new(
                      Parse,
                      "<end of line>".to_string(),
                      "value".to_string(),
                      Pos::new(self.line, self.column + string.len())
                  ))),
            "true" => Ok(Bool(true)),
            "false" => Ok(Bool(false)),
            _ => {
                if string.chars().all(|character| character.is_digit(10)) {
                    // NOTE: the string only contains digit, hence unwrap.
                    Ok(Int(string.parse().unwrap()))
                }
                else if string.chars().all(|character| character.is_digit(10) || character == '.') {
                    // NOTE: the string only contains digit or dot, hence unwrap.
                    Ok(Float(string.parse().unwrap()))
                }
                else {
                    Ok(Str(input.trim().to_string()))
                }
            },
        }
    }
}

/// The `Value` enum represents a value along with its type.
#[derive(Debug, PartialEq)]
pub enum Value {
    /// Boolean value.
    Bool(bool),
    /// Floating-point value.
    Float(f64),
    /// Integer value.
    Int(i64),
    /// String value.
    Str(String),
}

impl Value {
    /// Get a string representation of the value.
    pub fn to_type(&self) -> &str {
        match *self {
            Bool(_) => "bool",
            Float(_) => "float",
            Int(_) => "int",
            Str(_) => "string",
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>add Core definition<commit_after>use std::io::Read;

/// Core is a trait that defines the standard UARC bus interface with a core for emulation purposes.
/// Interacting with the core is synchronous and thread-safe. Beware of deadlock.
///
/// W is a word type for passing information along the bus
pub trait Core<W> {
    /// The privilege/address is for the core sending.
    fn stream<R: Read>(&mut self, privilege: u8, address: u32, src: &mut R);
    /// The privilege/address is for the core receiving.
    fn incept<R: Read>(&mut self, privilege: u8, address: u32, src: &mut R);
    /// The privilege/address is for the core sending.
    fn send(&mut self, privilege: u8, address: u32, value: W);
    /// This wont complete until it suceeds.
    /// The privilege/address is for the core sending.
    fn kill(&mut self, privilege: u8, address: u32);
    /// This only can determine if the core was running or not, but it is not synchronous.
    fn is_running(&self) -> bool;
}
<|endoftext|>


<commit_before>
use std::str;
use parser::{Node, Children, Data};

#[macro_escape]
mod macros;

// TODO: figure out how to write this as a function on Node; the borrow checker
// was extra painful the last time you tried.
macro_rules! node_children( ( $node:expr ) => ( {
  match $node.contents {
    Children( ref nodes ) => nodes,
    _ => fail!( "No children in node." )
  } } ) )

pub fn codeForNode( node: &Node ) -> ~str {
  match node.name {
    "Definition" => wrapChildrenOutput( ~"rule!( ", node, ~")\n" ),
    "Expression" => expressionOutput( node ),
    "Sequence" => sequenceOutput( node ),
    "Literal" => literalOutput( node ),
    "Class" => classOutput( node ),
    "Spacing" => ~" ",
    "EndOfLine" => ~"",
    "SLASH" => ~", ",
    "OPEN" => ~"",
    "CLOSE" => ~"",
    _ => codeForNodeContents( node )
  }
}

fn codeForNodeContents( node: &Node ) -> ~str {
  match node.contents {
    Children( ref children ) => {
      // TODO: use StrBuf here somehow when it's merged in
      children.iter().map( codeForNode ).collect::<Vec<~str>>().concat()
    }
    Data( data ) => str::from_utf8( data ).unwrap().to_owned(),
  }
}

fn wrapChildrenOutput( before: ~str, node: &Node, after: ~str ) -> ~str {
  [ before, codeForNodeContents( node ), after ].concat()
}

fn expressionOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 {
    codeForNodeContents( node )
  } else {
    wrapChildrenOutput( ~"or!( ", node , ~") " )
  }
}

fn sequenceOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 {
    codeForNodeContents( node )
  } else {
    let mut output = StrBuf::from_str( "seq!( " );
    for i in range( 0, children.len() ) {
      output.push_str( codeForNodeContents( children.get( i ) ) );
      if i != children.len() -1 {
        output.push_str( ", " );
      }
    }
    output.push_str( ")" );
    output.into_owned()
  }
}

fn literalOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "lit" )
}

fn classOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "class" )
}

fn stringBasedRule( node: &Node, rule_name: &str ) -> ~str {
  // TODO: unescape chars
  let content = codeForNodeContents( node ).trim().to_owned();

  [ rule_name.to_owned(),
    ~"!( r\"",
    content.slice_chars( 1, content.len() - 1 ).replace( r#"""#, r#"\""# ),
    ~"\" )" ].concat()
}
<commit_msg>Spacing improvements for generated code<commit_after>
use std::str;
use parser::{Node, Children, Data};

#[macro_escape]
mod macros;

// TODO: figure out how to write this as a function on Node; the borrow checker
// was extra painful the last time you tried.
macro_rules! node_children( ( $node:expr ) => ( {
  match $node.contents {
    Children( ref nodes ) => nodes,
    _ => fail!( "No children in node." )
  } } ) )

pub fn codeForNode( node: &Node ) -> ~str {
  match node.name {
    "Definition" => wrapChildrenOutput( ~"rule!( ", node, ~" )\n" ),
    "Expression" => expressionOutput( node ),
    "Sequence" => sequenceOutput( node ),
    "Literal" => literalOutput( node ),
    "Class" => classOutput( node ),
    "Spacing" => ~"",
    "EndOfLine" => ~"",
    "LEFTARROW" => ~" <- ",
    "SLASH" => ~", ",
    "OPEN" => ~"",
    "CLOSE" => ~"",
    _ => codeForNodeContents( node )
  }
}

fn codeForNodeContents( node: &Node ) -> ~str {
  match node.contents {
    Children( ref children ) => {
      // TODO: use StrBuf here somehow when it's merged in
      children.iter().map( codeForNode ).collect::<Vec<~str>>().concat()
    }
    Data( data ) => str::from_utf8( data ).unwrap().to_owned(),
  }
}

fn wrapChildrenOutput( before: ~str, node: &Node, after: ~str ) -> ~str {
  [ before, codeForNodeContents( node ), after ].concat()
}

fn expressionOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 {
    codeForNodeContents( node )
  } else {
    wrapChildrenOutput( ~"or!( ", node , ~" )" )
  }
}

fn sequenceOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 {
    codeForNodeContents( node )
  } else {
    let mut output = StrBuf::from_str( "seq!( " );
    for i in range( 0, children.len() ) {
      output.push_str( codeForNodeContents( children.get( i ) ) );
      if i != children.len() -1 {
        output.push_str( ", " );
      }
    }
    output.push_str( " )" );
    output.into_owned()
  }
}

fn literalOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "lit" )
}

fn classOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "class" )
}

fn stringBasedRule( node: &Node, rule_name: &str ) -> ~str {
  // TODO: unescape chars
  let content = codeForNodeContents( node ).trim().to_owned();

  [ rule_name.to_owned(),
    ~"!( r\"",
    content.slice_chars( 1, content.len() - 1 ).replace( r#"""#, r#"\""# ),
    ~"\" )" ].concat()
}
<|endoftext|>


<commit_before>//! An implementation of Google Protobuf's Variable-Length Integers

/// The maximum number of bytes used by a 32-bit Varint
pub const VARINT_32_MAX_BYTES: u8 = 5;

/// The maximum number of bytes used by a 32-bit Varint
pub const VARINT_64_MAX_BYTES: u8 = 10;

/// Checks to see if the most signifigant bit exists in the specified byte
pub fn most_signifigant_bit_exists(input: u8) -> bool {
    input & 0b10000000 != 0
}

/// A struct defining a variable-length integer
#[derive(Clone, Debug)]
pub struct Varint {

    /// The internal data representation
    pub data: Vec<u8>

}

impl Varint {

    /// Gets the number of bytes currently contained by this Varint
    pub fn number_of_bytes(&self) -> usize {
        self.data.len()
    }

}

/// Gets the number of bytes required to store an unsigned value in a Varint
pub fn unsigned_varint_bytes_required(input: usize) -> u8 {

    let mut value: u64 = input as u64;

    let mut returnable: u8 = 0;

    if value == 0 {
        return 1;
    }

    while value >= 1 {

        value >>= 7;

        returnable += 1;
    }

    returnable

}

///Encodes an unsigned value as a Varint.
pub fn encode_unsigned_varint(input: usize) -> Varint {

    let mut returnable: Varint = Varint { data: Vec::<u8>::new() };

    let mut value: u64 = input as u64;

    if value == 0 {
        returnable.data.push(0);
        return returnable;
    } else {

        while value >= 1 {
            let mut next_byte: u8 = (value & 0b01111111) as u8;

            value >>= 7;

            if value >= 1 {
                next_byte |= 0b10000000;
            }

            returnable.data.push(next_byte);
        }

        return returnable;
    }

}

#[cfg(test)]
mod test {

    use super::*;

    #[test]
    fn test_varint_bytes_required() {
        let mut abc: usize = 0;

        assert_eq!(1, unsigned_varint_bytes_required(abc));

        abc = 120;

        assert_eq!(1, unsigned_varint_bytes_required(abc));

        abc = 128;

        assert_eq!(2, unsigned_varint_bytes_required(abc));

        abc = 300;

        assert_eq!(2, unsigned_varint_bytes_required(abc));

        abc = 0b000111111101010110101100;

        assert_eq!(3, unsigned_varint_bytes_required(abc));

        abc = 0b011111111101010110101100;

        assert_eq!(4, unsigned_varint_bytes_required(abc));

        abc = 4147110142;

        assert_eq!(5, unsigned_varint_bytes_required(abc));
    }

    #[test]
    fn test_new_varint_has_no_bytes() {

        let abc: Varint = Varint { data: Vec::<u8>::new() };

        assert_eq!(0, abc.number_of_bytes());

    }

    #[test]
    fn test_most_signifigant_bit() {
        let mut value: u8 = 1;

        assert!(most_signifigant_bit_exists(value) == false);

        value = 120;

        assert!(most_signifigant_bit_exists(value) == false);

        value = 128;

        assert!(most_signifigant_bit_exists(value) == true);

        value = 129;

        assert!(most_signifigant_bit_exists(value) == true);
    }

}<commit_msg>Implement and test zigzagging<commit_after>//! An implementation of Google Protobuf's Variable-Length Integers

/// The maximum number of bytes used by a 32-bit Varint
pub const VARINT_32_MAX_BYTES: u8 = 5;

/// The maximum number of bytes used by a 32-bit Varint
pub const VARINT_64_MAX_BYTES: u8 = 10;

/// Checks to see if the most signifigant bit exists in the specified byte
pub fn most_signifigant_bit_exists(input: u8) -> bool {
    input & 0b10000000 != 0
}

/// A struct defining a variable-length integer
#[derive(Clone, Debug)]
pub struct Varint {

    /// The internal data representation
    pub data: Vec<u8>

}

impl Varint {

    /// Gets the number of bytes currently contained by this Varint
    pub fn number_of_bytes(&self) -> usize {
        self.data.len()
    }

}

/// Transforms a signed int to an unsigned int via zig-zag transformation
pub fn zigzag_signed_int(input: i32) -> u32 {
    ((input << 1) ^ (input >> 31)) as u32
}

/// Transforms a signed long to an unsigned long via zig-zag transformation
pub fn zigzag_signed_long(input: i64) -> u64 {
    ((input << 1) ^ (input >> 63)) as u64
}

/// Transforms an unsigned int to a signed int via zig-zag transformation
pub fn zigzag_unsigned_int(input: u32) -> i32 {
    ((input >> 1) as i32) ^ (-((input & 1) as i32))
}

/// Transforms an unsignigned long to a signed long via zig-zag transformation
pub fn zigzag_unsigned_long(input: u64) -> i64 {
    ((input >> 1) as i64) ^ (-((input & 1) as i64))
}

/// Encodes a signed i32 as a Varint
pub fn encode_signed_varint32(input: i32) -> Varint {
    encode_unsigned_varint32(zigzag_signed_int(input))
}

/// Encodes a signed i64 as a Varint
pub fn encode_signed_varint64(input: i64) -> Varint {
    encode_unsigned_varint64(zigzag_signed_long(input))
}

/// Encodes an unsigned u32 as a Varint.
pub fn encode_unsigned_varint32(input: u32) -> Varint {

    let mut returnable: Varint = Varint { data: Vec::<u8>::new() };

    let mut value: u32 = input;

    if value == 0 {
        returnable.data.push(0);
        return returnable;
    } else {

        while value >= 1 {
            let mut next_byte: u8 = (value & 0b01111111) as u8;

            value >>= 7;

            if value >= 1 {
                next_byte |= 0b10000000;
            }

            returnable.data.push(next_byte);
        }

        return returnable;
    }

}

/// Encodes an unsigned u64 as a Varint.
pub fn encode_unsigned_varint64(input: u64) -> Varint {

    let mut returnable: Varint = Varint { data: Vec::<u8>::new() };

    let mut value: u64 = input;

    if value == 0 {
        returnable.data.push(0);
        return returnable;
    } else {

        while value >= 1 {
            let mut next_byte: u8 = (value & 0b01111111) as u8;

            value >>= 7;

            if value >= 1 {
                next_byte |= 0b10000000;
            }

            returnable.data.push(next_byte);
        }

        return returnable;
    }

}

#[cfg(test)]
mod test {

    use super::*;

    #[test]
    fn test_zigzag_signed_value() {
        let mut signed: i32 = 0;

        assert_eq!(signed, zigzag_signed_int(signed) as i32);

        signed = -1;

        assert_eq!(1, zigzag_signed_int(signed));

        signed = 1;

        assert_eq!(2, zigzag_signed_int(signed));

        signed = -2;

        assert_eq!(3, zigzag_signed_int(signed));

        let mut signed: i64 = 9223372036854775806;

        assert_eq!(18446744073709551612, zigzag_signed_long(signed));

        signed = -9223372036854775808;

        assert_eq!(18446744073709551615, zigzag_signed_long(signed));
    }

    #[test]
    fn test_new_varint_has_no_bytes() {

        let abc: Varint = Varint { data: Vec::<u8>::new() };

        assert_eq!(0, abc.number_of_bytes());

    }

    #[test]
    fn test_most_signifigant_bit() {
        let mut value: u8 = 1;

        assert!(most_signifigant_bit_exists(value) == false);

        value = 120;

        assert!(most_signifigant_bit_exists(value) == false);

        value = 128;

        assert!(most_signifigant_bit_exists(value) == true);

        value = 129;

        assert!(most_signifigant_bit_exists(value) == true);
    }

}<|endoftext|>


<commit_before>extern crate hyper;
extern crate url;
extern crate regex;

pub mod server;
pub mod response;
pub mod request;
pub mod middleware;
pub mod router;
pub mod matcher;
<commit_msg>top level module docs<commit_after>extern crate hyper;
extern crate url;
extern crate regex;

/// Boron app server methods and utilities
pub mod server;

/// HTTP response representation in Boron
pub mod response;

/// HTTP request representation in Boron
pub mod request;

/// Traits to implement middleware types
pub mod middleware;

/// Router logic to dispatch requests
pub mod router;
mod matcher;
<|endoftext|>


<commit_before>#![feature(specialization)]
#![feature(alloc, heap_api, allocator_api)]
#![feature(conservative_impl_trait)]
#![feature(cfg_target_feature)]
#![feature(asm)]
#![feature(step_by,iterator_step_by)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![allow(inline_always)]
#![allow(too_many_arguments)]
#![allow(many_single_char_names)]

extern crate core;
extern crate typenum;
extern crate libc;

pub mod matrix;
pub mod composables;
pub mod thread_comm;
pub mod kern;
pub mod util;
<commit_msg>Supress unknown lint warnings<commit_after>#![feature(specialization)]
#![feature(alloc, heap_api, allocator_api)]
#![feature(conservative_impl_trait)]
#![feature(cfg_target_feature)]
#![feature(asm)]
#![feature(step_by,iterator_step_by)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![allow(unknown_lints)]
#![allow(inline_always)]
#![allow(too_many_arguments)]
#![allow(many_single_char_names)]

extern crate core;
extern crate typenum;
extern crate libc;

pub mod matrix;
pub mod composables;
pub mod thread_comm;
pub mod kern;
pub mod util;
<|endoftext|>


<commit_before>// Hound -- A WAV encoding and decoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Hound, a WAV encoding and decoding library.
//!
//! TODO: Add some introductory text here.
//!
//! Examples
//! ========
//!
//! The following example renders a 440 Hz sine wave, and stores it as as a
//! mono wav file with a sample rate of 44.1 kHz and 16 bits per sample.
//!
//! ```
//! use std::f32::consts::PI;
//! use std::i16;
//! use hound;
//!
//! let spec = hound::WavSpec {
//!     channels: 1,
//!     sample_rate: 44100,
//!     bits_per_sample: 16
//! };
//! let mut writer = hound::WavWriter::create("sine.wav", spec).unwrap();
//! for t in (0 .. 44100).map(|x| x as f32 / 44100.0) {
//!     let sample = (t * 440.0 * 2.0 * PI).sin();
//!     let amplitude = i16::MAX as f32;
//!     writer.write_sample((sample * amplitude) as i16).unwrap();
//! }
//! writer.finalize().unwrap();
//! ```
//!
//! The following example computes the RMS (root mean square) of an audio file.
//!
//! ```
//! use hound;
//!
//! let mut reader = hound::WavReader::open("testsamples/pop.wav").unwrap();
//! let (sqr_sum, n) = reader.samples::<i16>()
//!                          .fold((0_f64, 0_u32), |(sqr_sum, n), s| {
//!     let sample = s.unwrap() as f64;
//!     (sqr_sum + sample * sample, n + 1)
//! });
//! println!("RMS is {}", (sqr_sum / n as f64).sqrt());
//! ```

#![warn(missing_docs)]

use std::error;
use std::fmt;
use std::io;
use std::io::Write;
use std::result;
use read::ReadExt;
use write::WriteExt;

mod read;
mod write;

pub use read::{WavReader, WavSamples};
pub use write::WavWriter;

/// A type that can be used to represent audio samples.
pub trait Sample {
    /// Writes the audio sample to the WAVE data chunk.
    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()>;

    /// Reads the audio sample from the WAVE data chunk.
    fn read<R: io::Read>(reader: &mut R, bytes: u16, bits: u16) -> Result<Self>;
}

/// Converts an unsigned integer in the range 0-255 to a signed one in the range -128-127.
///
/// Presumably, the designers of the WAVE format did not like consistency. For
/// all bit depths except 8, samples are stored as little-endian _signed_
/// integers. However, an 8-bit sample is instead stored as an _unsigned_
/// integer. Hound abstracts away this idiosyncrasy by providing only signed
/// sample types.
fn signed_from_u8(x: u8) -> i8 {
    (x as i16 - 128) as i8
}

/// Converts a signed integer in the range -128-127 to an unsigned one in the range 0-255.
fn u8_from_signed(x: i8) -> u8 {
    (x as i16 + 128) as u8
}

#[test]
fn u8_sign_conversion_is_bijective() {
    for x in (0 .. 255) {
        assert_eq!(x, u8_from_signed(signed_from_u8(x)));
    }
    for x in (-128 .. 127) {
        assert_eq!(x, signed_from_u8(u8_from_signed(x)));
    }
}

impl Sample for i8 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
        match bits {
            8 => Ok(try!(writer.write_u8(u8_from_signed(self as i8)))),
            16 => Ok(try!(writer.write_le_i16(self as i16))),
            24 => Ok(try!(writer.write_le_i24(self as i32))),
            32 => Ok(try!(writer.write_le_i32(self as i32))),
            _ => Err(Error::Unsupported)
        }
    }

    fn read<R: io::Read>(reader: &mut R, bytes: u16, bits: u16) -> Result<i8> {
        match (bytes, bits) {
            (1, 8) => Ok(try!(reader.read_u8().map(signed_from_u8))),
            // TODO: add a genric decoder for any bit depth.
            // TODO: differentiate between too wide and unsupported.
            _ => Err(Error::TooWide)
        }
    }
}

impl Sample for i16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
        match bits {
            // TODO: do a bounds check on the downcast, or disallow writing
            // wider types than the bits per sample in the spec beforehand.
            8 => Ok(try!(writer.write_u8(u8_from_signed(self as i8)))),
            16 => Ok(try!(writer.write_le_i16(self))),
            24 => Ok(try!(writer.write_le_i24(self as i32))),
            32 => Ok(try!(writer.write_le_i32(self as i32))),
            _ => Err(Error::Unsupported)
        }
    }

    fn read<R: io::Read>(reader: &mut R, bytes: u16, bits: u16) -> Result<i16> {
        match (bytes, bits) {
            (1, 8) => Ok(try!(reader.read_u8().map(signed_from_u8).map(|x| x as i16))),
            (2, 16) => Ok(try!(reader.read_le_i16())),
            // TODO: add a generic decoder for any bit depth.
            // TODO: differentiate between too wide and unsupported.
            _ => Err(Error::TooWide)
        }
    }
}

impl Sample for i32 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
        match bits {
            // TODO: do a bounds check on the downcast, or disallow writing
            // wider types than the bits per sample in the spec beforehand.
            8 => Ok(try!(writer.write_u8(u8_from_signed(self as i8)))),
            16 => Ok(try!(writer.write_le_i16(self as i16))),
            24 => Ok(try!(writer.write_le_i24(self))),
            32 => Ok(try!(writer.write_le_i32(self))),
            _ => Err(Error::Unsupported)
        }
    }

    fn read<R: io::Read>(reader: &mut R, bytes: u16, bits: u16) -> Result<i32> {
        match (bytes, bits) {
            (1, 8) => Ok(try!(reader.read_u8().map(signed_from_u8).map(|x| x as i32))),
            (2, 16) => Ok(try!(reader.read_le_i16().map(|x| x as i32))),
            (3, 24) => Ok(try!(reader.read_le_i24())),
            (4, 32) => Ok(try!(reader.read_le_i32())),
            // TODO: add a generic decoder for any bit depth.
            // TODO: differentiate between too wide and unsupported.
            _ => Err(Error::TooWide)
        }
    }
}

/// Specifies properties of the audio data.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct WavSpec {
    /// The number of channels.
    pub channels: u16,

    /// The number of samples per second.
    ///
    /// A common value is 44100, this is 44.1 kHz which is used for CD audio.
    pub sample_rate: u32,

    /// The number of bits per sample.
    ///
    /// A common value is 16 bits per sample, which is used for CD audio.
    pub bits_per_sample: u16
}

/// The error type for operations on `WavReader` and `WavWriter`.
#[derive(Debug)]
pub enum Error {
    /// An IO error occured in the underlying reader or writer.
    IoError(io::Error),
    /// Ill-formed WAVE data was encountered.
    FormatError(&'static str),
    /// The sample has more bits than the data type of the sample iterator.
    TooWide,
    /// The number of samples written is not a multiple of the number of channels.
    UnfinishedSample,
    /// The format is not supported.
    Unsupported
}

impl fmt::Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter)
           -> result::Result<(), fmt::Error> {
        match *self {
            Error::IoError(ref err) => err.fmt(formatter),
            Error::FormatError(reason) => {
                try!(formatter.write_str("Ill-formed WAVE file: "));
                formatter.write_str(reason)
            },
            Error::TooWide => {
                formatter.write_str("The sample has more bits than the data type of the sample iterator.")
            },
            Error::UnfinishedSample => {
                formatter.write_str("The number of samples written is not a multiple of the number of channels.")
            },
            Error::Unsupported => {
                formatter.write_str("The wave format of the file is not supported.")
            }
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::IoError(ref err) => err.description(),
            Error::FormatError(reason) => reason,
            Error::TooWide => "the sample has more bits than the data type of the sample iterator",
            Error::UnfinishedSample => "the number of samples written is not a multiple of the number of channels",
            Error::Unsupported => "the wave format of the file is not supported"
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::IoError(ref err) => Some(err),
            Error::FormatError(_) => None,
            Error::TooWide => None,
            Error::UnfinishedSample => None,
            Error::Unsupported => None
        }
    }
}

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

/// A type for results generated by Hound where the error type is hard-wired.
pub type Result<T> = result::Result<T, Error>;

#[test]
fn write_read_i16_is_lossless() {
    let mut buffer = io::Cursor::new(Vec::new());
    let write_spec = WavSpec {
        channels: 2,
        sample_rate: 44100,
        bits_per_sample: 16
    };

    {
        let mut writer = WavWriter::new(&mut buffer, write_spec);
        for s in (-1024_i16 .. 1024) {
            writer.write_sample(s).unwrap();
        }
        writer.finalize().unwrap();
    }

    {
        buffer.set_position(0);
        let mut reader = WavReader::new(&mut buffer).unwrap();
        assert_eq!(&write_spec, reader.spec());
        for (expected, read) in (-1024_i16 .. 1024).zip(reader.samples()) {
            assert_eq!(expected, read.unwrap());
        }
    }
}

#[test]
fn write_read_i8_is_lossless() {
    let mut buffer = io::Cursor::new(Vec::new());
    let write_spec = WavSpec {
        channels: 16,
        sample_rate: 48000,
        bits_per_sample: 8
    };

    // Write `i8` samples.
    {
        let mut writer = WavWriter::new(&mut buffer, write_spec);
        // Iterate over i16 because we cannot specify the upper bound otherwise.
        for s in (-128_i16 .. 127 + 1) {
            writer.write_sample(s as i8).unwrap();
        }
        writer.finalize().unwrap();
    }

    // Then read them into `i16`.
    {
        buffer.set_position(0);
        let mut reader = WavReader::new(&mut buffer).unwrap();
        assert_eq!(&write_spec, reader.spec());
        for (expected, read) in (-128_i16 .. 127 + 1).zip(reader.samples()) {
            assert_eq!(expected, read.unwrap());
        }
    }
}

#[test]
fn write_read_i24_is_lossless() {
    let mut buffer = io::Cursor::new(Vec::new());
    let write_spec = WavSpec {
        channels: 16,
        sample_rate: 96000,
        bits_per_sample: 24
    };

    // Write `i32` samples, but with at most 24 bits per sample.
    {
        let mut writer = WavWriter::new(&mut buffer, write_spec);
        for s in (-128_i32 .. 127 + 1) {
            writer.write_sample(s * 256 * 256).unwrap();
        }
        writer.finalize().unwrap();
    }

    // Then read them into `i32`. This should extend the sign in the correct
    // manner.
    {
        buffer.set_position(0);
        let mut reader = WavReader::new(&mut buffer).unwrap();
        assert_eq!(&write_spec, reader.spec());
        for (expected, read) in (-128_i32 .. 127 + 1).map(|x| x * 256 * 256)
                                                     .zip(reader.samples()) {
            assert_eq!(expected, read.unwrap());
        }
    }
}
<commit_msg>add a bounds check when writing samples<commit_after>// Hound -- A WAV encoding and decoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Hound, a WAV encoding and decoding library.
//!
//! TODO: Add some introductory text here.
//!
//! Examples
//! ========
//!
//! The following example renders a 440 Hz sine wave, and stores it as as a
//! mono wav file with a sample rate of 44.1 kHz and 16 bits per sample.
//!
//! ```
//! use std::f32::consts::PI;
//! use std::i16;
//! use hound;
//!
//! let spec = hound::WavSpec {
//!     channels: 1,
//!     sample_rate: 44100,
//!     bits_per_sample: 16
//! };
//! let mut writer = hound::WavWriter::create("sine.wav", spec).unwrap();
//! for t in (0 .. 44100).map(|x| x as f32 / 44100.0) {
//!     let sample = (t * 440.0 * 2.0 * PI).sin();
//!     let amplitude = i16::MAX as f32;
//!     writer.write_sample((sample * amplitude) as i16).unwrap();
//! }
//! writer.finalize().unwrap();
//! ```
//!
//! The following example computes the RMS (root mean square) of an audio file.
//!
//! ```
//! use hound;
//!
//! let mut reader = hound::WavReader::open("testsamples/pop.wav").unwrap();
//! let (sqr_sum, n) = reader.samples::<i16>()
//!                          .fold((0_f64, 0_u32), |(sqr_sum, n), s| {
//!     let sample = s.unwrap() as f64;
//!     (sqr_sum + sample * sample, n + 1)
//! });
//! println!("RMS is {}", (sqr_sum / n as f64).sqrt());
//! ```

#![warn(missing_docs)]

use std::error;
use std::fmt;
use std::io;
use std::io::Write;
use std::result;
use read::ReadExt;
use write::WriteExt;

mod read;
mod write;

pub use read::{WavReader, WavSamples};
pub use write::WavWriter;

/// A type that can be used to represent audio samples.
pub trait Sample {
    /// Writes the audio sample to the WAVE data chunk.
    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()>;

    /// Reads the audio sample from the WAVE data chunk.
    fn read<R: io::Read>(reader: &mut R, bytes: u16, bits: u16) -> Result<Self>;
}

/// Converts an unsigned integer in the range 0-255 to a signed one in the range -128-127.
///
/// Presumably, the designers of the WAVE format did not like consistency. For
/// all bit depths except 8, samples are stored as little-endian _signed_
/// integers. However, an 8-bit sample is instead stored as an _unsigned_
/// integer. Hound abstracts away this idiosyncrasy by providing only signed
/// sample types.
fn signed_from_u8(x: u8) -> i8 {
    (x as i16 - 128) as i8
}

/// Converts a signed integer in the range -128-127 to an unsigned one in the range 0-255.
fn u8_from_signed(x: i8) -> u8 {
    (x as i16 + 128) as u8
}

#[test]
fn u8_sign_conversion_is_bijective() {
    for x in (0 .. 255) {
        assert_eq!(x, u8_from_signed(signed_from_u8(x)));
    }
    for x in (-128 .. 127) {
        assert_eq!(x, signed_from_u8(u8_from_signed(x)));
    }
}

/// Tries to cast the sample to an 8-bit signed integer, returning an error on overflow.
fn narrow_to_i8(x: i32) -> Result<i8> {
    use std::i8;
    if x < i8::MIN as i32 || x > i8::MAX as i32 {
        Err(Error::TooWide)
    } else {
        Ok(x as i8)
    }
}

#[test]
fn verify_narrow_to_i8() {
    assert!(narrow_to_i8(127).is_ok());
    assert!(narrow_to_i8(128).is_err());
    assert!(narrow_to_i8(-128).is_ok());
    assert!(narrow_to_i8(-129).is_err());
}

/// Tries to cast the sample to a 16-bit signed integer, returning an error on overflow.
fn narrow_to_i16(x: i32) -> Result<i16> {
    use std::i16;
    if x < i16::MIN as i32 || x > i16::MAX as i32 {
        Err(Error::TooWide)
    } else {
        Ok(x as i16)
    }
}

#[test]
fn verify_narrow_to_i16() {
    assert!(narrow_to_i16(32767).is_ok());
    assert!(narrow_to_i16(32768).is_err());
    assert!(narrow_to_i16(-32768).is_ok());
    assert!(narrow_to_i16(-32769).is_err());
}

/// Tries to cast the sample to a 24-bit signed integer, returning an error on overflow.
fn narrow_to_i24(x: i32) -> Result<i32> {
    if x < -(1 << 23) || x > (1 << 23) - 1 {
        Err(Error::TooWide)
    } else {
        Ok(x)
    }
}

#[test]
fn verify_narrow_to_i24() {
    assert!(narrow_to_i24(8_388_607).is_ok());
    assert!(narrow_to_i24(8_388_608).is_err());
    assert!(narrow_to_i24(-8_388_608).is_ok());
    assert!(narrow_to_i24(-8_388_609).is_err());
}

impl Sample for i8 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
        match bits {
            8 => Ok(try!(writer.write_u8(u8_from_signed(self)))),
            16 => Ok(try!(writer.write_le_i16(self as i16))),
            24 => Ok(try!(writer.write_le_i24(self as i32))),
            32 => Ok(try!(writer.write_le_i32(self as i32))),
            _ => Err(Error::Unsupported)
        }
    }

    fn read<R: io::Read>(reader: &mut R, bytes: u16, bits: u16) -> Result<i8> {
        match (bytes, bits) {
            (1, 8) => Ok(try!(reader.read_u8().map(signed_from_u8))),
            // TODO: add a genric decoder for any bit depth.
            // TODO: differentiate between too wide and unsupported.
            _ => Err(Error::TooWide)
        }
    }
}

impl Sample for i16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
        match bits {
            8 => Ok(try!(writer.write_u8(u8_from_signed(try!(narrow_to_i8(self as i32)))))),
            16 => Ok(try!(writer.write_le_i16(self))),
            24 => Ok(try!(writer.write_le_i24(self as i32))),
            32 => Ok(try!(writer.write_le_i32(self as i32))),
            _ => Err(Error::Unsupported)
        }
    }

    fn read<R: io::Read>(reader: &mut R, bytes: u16, bits: u16) -> Result<i16> {
        match (bytes, bits) {
            (1, 8) => Ok(try!(reader.read_u8().map(signed_from_u8).map(|x| x as i16))),
            (2, 16) => Ok(try!(reader.read_le_i16())),
            // TODO: add a generic decoder for any bit depth.
            // TODO: differentiate between too wide and unsupported.
            _ => Err(Error::TooWide)
        }
    }
}

impl Sample for i32 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
        match bits {
            // TODO: do a bounds check on the downcast, or disallow writing
            // wider types than the bits per sample in the spec beforehand.
            8 => Ok(try!(writer.write_u8(u8_from_signed(try!(narrow_to_i8(self)))))),
            16 => Ok(try!(writer.write_le_i16(try!(narrow_to_i16(self))))),
            24 => Ok(try!(writer.write_le_i24(try!(narrow_to_i24(self))))),
            32 => Ok(try!(writer.write_le_i32(self))),
            _ => Err(Error::Unsupported)
        }
    }

    fn read<R: io::Read>(reader: &mut R, bytes: u16, bits: u16) -> Result<i32> {
        match (bytes, bits) {
            (1, 8) => Ok(try!(reader.read_u8().map(signed_from_u8).map(|x| x as i32))),
            (2, 16) => Ok(try!(reader.read_le_i16().map(|x| x as i32))),
            (3, 24) => Ok(try!(reader.read_le_i24())),
            (4, 32) => Ok(try!(reader.read_le_i32())),
            // TODO: add a generic decoder for any bit depth.
            // TODO: differentiate between too wide and unsupported.
            _ => Err(Error::TooWide)
        }
    }
}

/// Specifies properties of the audio data.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct WavSpec {
    /// The number of channels.
    pub channels: u16,

    /// The number of samples per second.
    ///
    /// A common value is 44100, this is 44.1 kHz which is used for CD audio.
    pub sample_rate: u32,

    /// The number of bits per sample.
    ///
    /// A common value is 16 bits per sample, which is used for CD audio.
    pub bits_per_sample: u16
}

/// The error type for operations on `WavReader` and `WavWriter`.
#[derive(Debug)]
pub enum Error {
    /// An IO error occured in the underlying reader or writer.
    IoError(io::Error),
    /// Ill-formed WAVE data was encountered.
    FormatError(&'static str),
    /// The sample has more bits than the destination type.
    ///
    /// When iterating using the `samples` iterator, this means that the
    /// destination type (produced by the iterator) is not wide enough to hold
    /// the sample. When writing, this means that the sample cannot be written,
    /// because it requires more bits than the bits per sample specified.
    TooWide,
    /// The number of samples written is not a multiple of the number of channels.
    UnfinishedSample,
    /// The format is not supported.
    Unsupported
}

impl fmt::Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter)
           -> result::Result<(), fmt::Error> {
        match *self {
            Error::IoError(ref err) => err.fmt(formatter),
            Error::FormatError(reason) => {
                try!(formatter.write_str("Ill-formed WAVE file: "));
                formatter.write_str(reason)
            },
            Error::TooWide => {
                formatter.write_str("The sample has more bits than the destination type.")
            },
            Error::UnfinishedSample => {
                formatter.write_str("The number of samples written is not a multiple of the number of channels.")
            },
            Error::Unsupported => {
                formatter.write_str("The wave format of the file is not supported.")
            }
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::IoError(ref err) => err.description(),
            Error::FormatError(reason) => reason,
            Error::TooWide => "the sample has more bits than the destination type",
            Error::UnfinishedSample => "the number of samples written is not a multiple of the number of channels",
            Error::Unsupported => "the wave format of the file is not supported"
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::IoError(ref err) => Some(err),
            Error::FormatError(_) => None,
            Error::TooWide => None,
            Error::UnfinishedSample => None,
            Error::Unsupported => None
        }
    }
}

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

/// A type for results generated by Hound where the error type is hard-wired.
pub type Result<T> = result::Result<T, Error>;

#[test]
fn write_read_i16_is_lossless() {
    let mut buffer = io::Cursor::new(Vec::new());
    let write_spec = WavSpec {
        channels: 2,
        sample_rate: 44100,
        bits_per_sample: 16
    };

    {
        let mut writer = WavWriter::new(&mut buffer, write_spec);
        for s in (-1024_i16 .. 1024) {
            writer.write_sample(s).unwrap();
        }
        writer.finalize().unwrap();
    }

    {
        buffer.set_position(0);
        let mut reader = WavReader::new(&mut buffer).unwrap();
        assert_eq!(&write_spec, reader.spec());
        for (expected, read) in (-1024_i16 .. 1024).zip(reader.samples()) {
            assert_eq!(expected, read.unwrap());
        }
    }
}

#[test]
fn write_read_i8_is_lossless() {
    let mut buffer = io::Cursor::new(Vec::new());
    let write_spec = WavSpec {
        channels: 16,
        sample_rate: 48000,
        bits_per_sample: 8
    };

    // Write `i8` samples.
    {
        let mut writer = WavWriter::new(&mut buffer, write_spec);
        // Iterate over i16 because we cannot specify the upper bound otherwise.
        for s in (-128_i16 .. 127 + 1) {
            writer.write_sample(s as i8).unwrap();
        }
        writer.finalize().unwrap();
    }

    // Then read them into `i16`.
    {
        buffer.set_position(0);
        let mut reader = WavReader::new(&mut buffer).unwrap();
        assert_eq!(&write_spec, reader.spec());
        for (expected, read) in (-128_i16 .. 127 + 1).zip(reader.samples()) {
            assert_eq!(expected, read.unwrap());
        }
    }
}

#[test]
fn write_read_i24_is_lossless() {
    let mut buffer = io::Cursor::new(Vec::new());
    let write_spec = WavSpec {
        channels: 16,
        sample_rate: 96000,
        bits_per_sample: 24
    };

    // Write `i32` samples, but with at most 24 bits per sample.
    {
        let mut writer = WavWriter::new(&mut buffer, write_spec);
        for s in (-128_i32 .. 127 + 1) {
            writer.write_sample(s * 256 * 256).unwrap();
        }
        writer.finalize().unwrap();
    }

    // Then read them into `i32`. This should extend the sign in the correct
    // manner.
    {
        buffer.set_position(0);
        let mut reader = WavReader::new(&mut buffer).unwrap();
        assert_eq!(&write_spec, reader.spec());
        for (expected, read) in (-128_i32 .. 127 + 1).map(|x| x * 256 * 256)
                                                     .zip(reader.samples()) {
            assert_eq!(expected, read.unwrap());
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Kyle Mayes
//
// 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.

//! A micro-benchmarking library.
//!
//! # Overview
//!
//! `microbench` uses linear regression to estimate the execution time of code segments. For
//! example, the following table might represent data collected by `microbench` about a code
//! segment.
//!
//! | Iterations | Time (ns) |
//! |------------|-----------|
//! | 1          | 19        |
//! | 2          | 25        |
//! | 3          | 37        |
//! | 4          | 47        |
//! | 5          | 56        |
//!
//! `microbench` of course takes many more than 5 samples and the number of iterations grows
//! geometrically rather than linearly, but the idea remains the same. After collecting data like
//! this, `microbench` uses ordinary least squares (OLS) linear regression to estimate the actual
//! execution time of the code segment. Using OLS with the above data would yield an estimated
//! execution time of `9.6` nanoseconds with a goodness of fit (R²) of `0.992`.
//!
//! # Example
//!
//! ```
//! use microbench::{self, Options};
//!
//! fn fibonacci_iterative(n: u64) -> u64 {
//!     let (mut x, mut y, mut z) = (0, 1, 1);
//!     for _ in 0..n { x = y; y = z; z = x + y; }
//!     x
//! }
//!
//! fn fibonacci_recursive(n: u64) -> u64 {
//!     if n < 2 {
//!         n
//!     } else {
//!         fibonacci_recursive(n - 2) + fibonacci_recursive(n - 1)
//!     }
//! }
//!
//! let options = Options::default();
//! microbench::bench(&options, "iterative_16", || fibonacci_iterative(16));
//! microbench::bench(&options, "recursive_16", || fibonacci_recursive(16)); panic!("");
//! ```
//!
//! Example output:
//!
//! ```console
//! iterative_16 (5.0s) ...                  281.733 ns/iter (0.998 R²)
//! recursive_16 (5.0s) ...                9_407.020 ns/iter (0.997 R²)
//! ```

#![cfg_attr(feature="nightly", feature(test))]

#![warn(missing_copy_implementations, missing_debug_implementations, missing_docs)]

#[cfg(feature="nightly")]
extern crate test;

mod utility;
pub mod statistics;
pub mod time;

use std::cmp;
use std::mem;
use std::time::{Duration};

use time::{Nanoseconds, Stopwatch};

//================================================
// Structs
//================================================

// Analysis ______________________________________

/// A statistical analysis of a set of timing data.
#[derive(Copy, Clone, Debug)]
pub struct Analysis {
    /// The y-intercept of the linear regression estimator.
    pub alpha: Nanoseconds<f64>,
    /// The slope of the linear regression estimator.
    pub beta: Nanoseconds<f64>,
    /// The goodness of fit of the linear regression estimator.
    pub r2: f64,
}

// Bytes _________________________________________

/// A number of bytes.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Bytes(pub u64);

impl Bytes {
    //- Constructors -----------------------------

    /// Constructs a new `Bytes` with the supplied number of kibibytes (2¹⁰ bytes).
    pub fn kibibytes(kibibytes: u64) -> Self {
        Bytes(kibibytes * 1024)
    }

    /// Constructs a new `Bytes` with the supplied number of mebibytes (2²⁰ bytes).
    pub fn mebibytes(mebibytes: u64) -> Self {
        Bytes(mebibytes * 1024 * 1024)
    }

    /// Constructs a new `Bytes` with the supplied number of gibibytes (2³⁰ bytes).
    pub fn gibibytes(gibibytes: u64) -> Self {
        Bytes(gibibytes * 1024 * 1024 * 1024)
    }
}

// GeometricSequence _____________________________

/// Generates unique values from a geometric sequence.
#[derive(Copy, Clone, Debug)]
pub struct GeometricSequence {
    current: f64,
    factor: f64,
}

impl GeometricSequence {
    //- Constructors -----------------------------

    /// Constructs a new `GeometricSequence`.
    pub fn new(start: u64, factor: f64) -> Self {
        GeometricSequence { current: start as f64, factor: factor }
    }
}

impl Iterator for GeometricSequence {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        let start = self.current as u64;
        while self.current as u64 == start { self.current *= self.factor; }
        Some(start)
    }
}

// Measurement ___________________________________

/// A measurement of the execution time of a function.
#[derive(Copy, Clone, Debug)]
pub struct Measurement {
    /// The number of times the function was executed.
    pub iterations: u64,
    /// The amount of time that elapsed while executing the function.
    pub elapsed: Nanoseconds<u64>,
}

// Options _______________________________________

/// Benchmarking options.
#[derive(Copy, Clone, Debug)]
pub struct Options {
    factor: f64,
    memory: Bytes,
    time: Nanoseconds<u64>,
}

impl Options {
    //- Consumers --------------------------------

    /// Sets the geometric growth factor for benchmark sample iterations.
    ///
    /// **Default:** `1.01`
    pub fn factor(mut self, factor: f64) -> Self {
        self.factor = factor;
        self
    }

    /// Sets the maximum amount of memory a benchmark will allocate.
    ///
    /// **Default:** `Bytes::mebibytes(512)`
    pub fn memory(mut self, memory: Bytes) -> Self {
        self.memory = memory;
        self
    }

    /// Sets the maximum amount of time a benchmark will run for.
    ///
    /// **Default:** `Duration::new(5, 0)`
    pub fn time(mut self, time: Duration) -> Self {
        self.time = time.into();
        self
    }
}

impl Default for Options {
    fn default() -> Options {
        Options { factor: 1.01, memory: Bytes::mebibytes(512), time: Duration::new(5, 0).into() }
    }
}

//================================================
// Functions
//================================================

fn bench_impl<F>(name: &str, f: F) where F: FnOnce() -> Vec<Measurement> {
    let stopwatch = Stopwatch::new();
    let measurements = f();
    let analysis = analyze(&measurements);
    let prefix = format!("{} ({}) ...", name, stopwatch.elapsed());
    if measurements.len() < 2 || analysis.beta.0 < 0.0 {
        println!("{:<32} {:>15}", prefix, "           not enough measurements");
    } else {
        let beta = utility::thousands(analysis.beta.0, '_');
        println!("{:<32} {:>15} ns/iter ({:.3} R²)", prefix, beta, analysis.r2);
    }
}

const ITERATIONS: u64 = 1_000_000_000_000_000;

fn measure_impl<F>(
    options: &Options, mut f: F
) -> Vec<Measurement> where F: FnMut(u64) -> Option<Nanoseconds<u64>> {
    let mut measurements = vec![];
    let mut sequence = GeometricSequence::new(1, options.factor).take_while(|i| *i <= ITERATIONS);
    let stopwatch = Stopwatch::new();
    while stopwatch.elapsed() < options.time {
        if let Some(iterations) = sequence.next() {
            if let Some(elapsed) = f(iterations) {
                measurements.push(Measurement { iterations: iterations, elapsed: elapsed });
            } else {
                break;
            }
        } else {
            break;
        }
    }
    measurements
}

/// Analyzes the supplied timing data and returns the resulting analysis.
pub fn analyze(measurements: &[Measurement]) -> Analysis {
    let data = measurements.iter()
        .map(|m| (m.iterations as f64, m.elapsed.0 as f64))
        .collect::<Vec<_>>();
    let (alpha, beta, r2) = statistics::regression(&data);
    Analysis { alpha: Nanoseconds(alpha), beta: Nanoseconds(beta), r2: r2 }
}

/// Benchmarks the supplied function and prints the results.
pub fn bench<T, F>(options: &Options, name: &str, f: F) where F: FnMut() -> T {
    bench_impl(name, move || measure(options, f));
}

/// Benchmarks the supplied function ignoring drop time and prints the results.
///
/// See [`measure_drop`](fn.measure_drop.html) for more information.
pub fn bench_drop<T, F>(options: &Options, name: &str, f: F) where F: FnMut() -> T {
    bench_impl(name, move || measure_drop(options, f));
}

/// Benchmarks the supplied function ignoring setup time and prints the results.
///
/// See [`measure_setup`](fn.measure_setup.html) for more information.
pub fn bench_setup<I, S, T, F>(
    options: &Options, name: &str, setup: S, f: F
) where S: FnMut() -> I, F: FnMut(I) -> T {
    bench_impl(name, move || measure_setup(options, setup, f));
}

/// Measures the execution time of the supplied function.
pub fn measure<T, F>(options: &Options, mut f: F) -> Vec<Measurement> where F: FnMut() -> T {
    measure_impl(options, |iterations| {
        let stopwatch = Stopwatch::new();
        for _ in 0..iterations { retain(f()); }
        Some(stopwatch.elapsed())
    })
}

/// Measures the execution time of the supplied function ignoring drop time.
///
/// This function does not include the time it takes to drop the values returned by the supplied
/// function in the measurements. This can be useful when you want to exclude the running time of a
/// slow implementation of `Drop` from your benchmark. However, it should be noted that this
/// function introduces a very small amount of overhead which will be reflected in the measurements
/// (typically of the order of a few nanoseconds).
///
/// **Warning:** This function can potentially allocate very large amounts of memory. The `memory`
/// option controls the maximum this function is allowed to allocate.
pub fn measure_drop<T, F>(options: &Options, mut f: F) -> Vec<Measurement> where F: FnMut() -> T {
    measure_impl(options, |iterations| {
        if options.memory < Bytes(iterations * cmp::max(1, mem::size_of::<T>() as u64)) {
            return None;
        }
        let mut outputs = Vec::with_capacity(iterations as usize);
        let stopwatch = Stopwatch::new();
        for _ in 0..iterations { outputs.push(f()); }
        let elapsed = stopwatch.elapsed();
        mem::drop(outputs);
        Some(elapsed)
    })
}

/// Measures the execution time of the supplied function ignoring setup time.
///
/// This function does not include the time it takes to execute the setup function in the
/// measurements. This can be useful when you want to exclude the running time of some non-trivial
/// setup which is needed for every execution of the supplied function. However, it should be noted
/// that this function introduces a very small amount of overhead which will be reflected in the
/// measurements (typically of the order of a few nanoseconds).
///
/// **Warning:** This function can potentially allocate very large amounts of memory. The `memory`
/// option controls the maximum this function is allowed to allocate.
pub fn measure_setup<I, S, T, F>(
    options: &Options, mut setup: S, mut f: F
) -> Vec<Measurement> where S: FnMut() -> I, F: FnMut(I) -> T {
    measure_impl(options, |iterations| {
        if options.memory < Bytes(iterations * cmp::max(1, mem::size_of::<I>() as u64)) {
            return None;
        }
        let inputs = retain((0..iterations).map(|_| setup()).collect::<Vec<_>>());
        let stopwatch = Stopwatch::new();
        for input in inputs { retain(f(input)); }
        Some(stopwatch.elapsed())
    })
}

/// A function that prevents the optimizer from eliminating the supplied value.
///
/// This function may not operate correctly or may have poor performance on the stable and beta
/// channels of Rust. If you are using a nightly release of Rust, enable the `nightly` crate feature
/// to enable a superior implementation of this function.
pub fn retain<T>(value: T) -> T {
    utility::black_box(value)
}
<commit_msg>Fix test failure<commit_after>// Copyright 2016 Kyle Mayes
//
// 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.

//! A micro-benchmarking library.
//!
//! # Overview
//!
//! `microbench` uses linear regression to estimate the execution time of code segments. For
//! example, the following table might represent data collected by `microbench` about a code
//! segment.
//!
//! | Iterations | Time (ns) |
//! |------------|-----------|
//! | 1          | 19        |
//! | 2          | 25        |
//! | 3          | 37        |
//! | 4          | 47        |
//! | 5          | 56        |
//!
//! `microbench` of course takes many more than 5 samples and the number of iterations grows
//! geometrically rather than linearly, but the idea remains the same. After collecting data like
//! this, `microbench` uses ordinary least squares (OLS) linear regression to estimate the actual
//! execution time of the code segment. Using OLS with the above data would yield an estimated
//! execution time of `9.6` nanoseconds with a goodness of fit (R²) of `0.992`.
//!
//! # Example
//!
//! ```
//! use microbench::{self, Options};
//!
//! fn fibonacci_iterative(n: u64) -> u64 {
//!     let (mut x, mut y, mut z) = (0, 1, 1);
//!     for _ in 0..n { x = y; y = z; z = x + y; }
//!     x
//! }
//!
//! fn fibonacci_recursive(n: u64) -> u64 {
//!     if n < 2 {
//!         n
//!     } else {
//!         fibonacci_recursive(n - 2) + fibonacci_recursive(n - 1)
//!     }
//! }
//!
//! let options = Options::default();
//! microbench::bench(&options, "iterative_16", || fibonacci_iterative(16));
//! microbench::bench(&options, "recursive_16", || fibonacci_recursive(16));
//! ```
//!
//! Example output:
//!
//! ```console
//! iterative_16 (5.0s) ...                  281.733 ns/iter (0.998 R²)
//! recursive_16 (5.0s) ...                9_407.020 ns/iter (0.997 R²)
//! ```

#![cfg_attr(feature="nightly", feature(test))]

#![warn(missing_copy_implementations, missing_debug_implementations, missing_docs)]

#[cfg(feature="nightly")]
extern crate test;

mod utility;
pub mod statistics;
pub mod time;

use std::cmp;
use std::mem;
use std::time::{Duration};

use time::{Nanoseconds, Stopwatch};

//================================================
// Structs
//================================================

// Analysis ______________________________________

/// A statistical analysis of a set of timing data.
#[derive(Copy, Clone, Debug)]
pub struct Analysis {
    /// The y-intercept of the linear regression estimator.
    pub alpha: Nanoseconds<f64>,
    /// The slope of the linear regression estimator.
    pub beta: Nanoseconds<f64>,
    /// The goodness of fit of the linear regression estimator.
    pub r2: f64,
}

// Bytes _________________________________________

/// A number of bytes.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Bytes(pub u64);

impl Bytes {
    //- Constructors -----------------------------

    /// Constructs a new `Bytes` with the supplied number of kibibytes (2¹⁰ bytes).
    pub fn kibibytes(kibibytes: u64) -> Self {
        Bytes(kibibytes * 1024)
    }

    /// Constructs a new `Bytes` with the supplied number of mebibytes (2²⁰ bytes).
    pub fn mebibytes(mebibytes: u64) -> Self {
        Bytes(mebibytes * 1024 * 1024)
    }

    /// Constructs a new `Bytes` with the supplied number of gibibytes (2³⁰ bytes).
    pub fn gibibytes(gibibytes: u64) -> Self {
        Bytes(gibibytes * 1024 * 1024 * 1024)
    }
}

// GeometricSequence _____________________________

/// Generates unique values from a geometric sequence.
#[derive(Copy, Clone, Debug)]
pub struct GeometricSequence {
    current: f64,
    factor: f64,
}

impl GeometricSequence {
    //- Constructors -----------------------------

    /// Constructs a new `GeometricSequence`.
    pub fn new(start: u64, factor: f64) -> Self {
        GeometricSequence { current: start as f64, factor: factor }
    }
}

impl Iterator for GeometricSequence {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        let start = self.current as u64;
        while self.current as u64 == start { self.current *= self.factor; }
        Some(start)
    }
}

// Measurement ___________________________________

/// A measurement of the execution time of a function.
#[derive(Copy, Clone, Debug)]
pub struct Measurement {
    /// The number of times the function was executed.
    pub iterations: u64,
    /// The amount of time that elapsed while executing the function.
    pub elapsed: Nanoseconds<u64>,
}

// Options _______________________________________

/// Benchmarking options.
#[derive(Copy, Clone, Debug)]
pub struct Options {
    factor: f64,
    memory: Bytes,
    time: Nanoseconds<u64>,
}

impl Options {
    //- Consumers --------------------------------

    /// Sets the geometric growth factor for benchmark sample iterations.
    ///
    /// **Default:** `1.01`
    pub fn factor(mut self, factor: f64) -> Self {
        self.factor = factor;
        self
    }

    /// Sets the maximum amount of memory a benchmark will allocate.
    ///
    /// **Default:** `Bytes::mebibytes(512)`
    pub fn memory(mut self, memory: Bytes) -> Self {
        self.memory = memory;
        self
    }

    /// Sets the maximum amount of time a benchmark will run for.
    ///
    /// **Default:** `Duration::new(5, 0)`
    pub fn time(mut self, time: Duration) -> Self {
        self.time = time.into();
        self
    }
}

impl Default for Options {
    fn default() -> Options {
        Options { factor: 1.01, memory: Bytes::mebibytes(512), time: Duration::new(5, 0).into() }
    }
}

//================================================
// Functions
//================================================

fn bench_impl<F>(name: &str, f: F) where F: FnOnce() -> Vec<Measurement> {
    let stopwatch = Stopwatch::new();
    let measurements = f();
    let analysis = analyze(&measurements);
    let prefix = format!("{} ({}) ...", name, stopwatch.elapsed());
    if measurements.len() < 2 || analysis.beta.0 < 0.0 {
        println!("{:<32} {:>15}", prefix, "           not enough measurements");
    } else {
        let beta = utility::thousands(analysis.beta.0, '_');
        println!("{:<32} {:>15} ns/iter ({:.3} R²)", prefix, beta, analysis.r2);
    }
}

const ITERATIONS: u64 = 1_000_000_000_000_000;

fn measure_impl<F>(
    options: &Options, mut f: F
) -> Vec<Measurement> where F: FnMut(u64) -> Option<Nanoseconds<u64>> {
    let mut measurements = vec![];
    let mut sequence = GeometricSequence::new(1, options.factor).take_while(|i| *i <= ITERATIONS);
    let stopwatch = Stopwatch::new();
    while stopwatch.elapsed() < options.time {
        if let Some(iterations) = sequence.next() {
            if let Some(elapsed) = f(iterations) {
                measurements.push(Measurement { iterations: iterations, elapsed: elapsed });
            } else {
                break;
            }
        } else {
            break;
        }
    }
    measurements
}

/// Analyzes the supplied timing data and returns the resulting analysis.
pub fn analyze(measurements: &[Measurement]) -> Analysis {
    let data = measurements.iter()
        .map(|m| (m.iterations as f64, m.elapsed.0 as f64))
        .collect::<Vec<_>>();
    let (alpha, beta, r2) = statistics::regression(&data);
    Analysis { alpha: Nanoseconds(alpha), beta: Nanoseconds(beta), r2: r2 }
}

/// Benchmarks the supplied function and prints the results.
pub fn bench<T, F>(options: &Options, name: &str, f: F) where F: FnMut() -> T {
    bench_impl(name, move || measure(options, f));
}

/// Benchmarks the supplied function ignoring drop time and prints the results.
///
/// See [`measure_drop`](fn.measure_drop.html) for more information.
pub fn bench_drop<T, F>(options: &Options, name: &str, f: F) where F: FnMut() -> T {
    bench_impl(name, move || measure_drop(options, f));
}

/// Benchmarks the supplied function ignoring setup time and prints the results.
///
/// See [`measure_setup`](fn.measure_setup.html) for more information.
pub fn bench_setup<I, S, T, F>(
    options: &Options, name: &str, setup: S, f: F
) where S: FnMut() -> I, F: FnMut(I) -> T {
    bench_impl(name, move || measure_setup(options, setup, f));
}

/// Measures the execution time of the supplied function.
pub fn measure<T, F>(options: &Options, mut f: F) -> Vec<Measurement> where F: FnMut() -> T {
    measure_impl(options, |iterations| {
        let stopwatch = Stopwatch::new();
        for _ in 0..iterations { retain(f()); }
        Some(stopwatch.elapsed())
    })
}

/// Measures the execution time of the supplied function ignoring drop time.
///
/// This function does not include the time it takes to drop the values returned by the supplied
/// function in the measurements. This can be useful when you want to exclude the running time of a
/// slow implementation of `Drop` from your benchmark. However, it should be noted that this
/// function introduces a very small amount of overhead which will be reflected in the measurements
/// (typically of the order of a few nanoseconds).
///
/// **Warning:** This function can potentially allocate very large amounts of memory. The `memory`
/// option controls the maximum this function is allowed to allocate.
pub fn measure_drop<T, F>(options: &Options, mut f: F) -> Vec<Measurement> where F: FnMut() -> T {
    measure_impl(options, |iterations| {
        if options.memory < Bytes(iterations * cmp::max(1, mem::size_of::<T>() as u64)) {
            return None;
        }
        let mut outputs = Vec::with_capacity(iterations as usize);
        let stopwatch = Stopwatch::new();
        for _ in 0..iterations { outputs.push(f()); }
        let elapsed = stopwatch.elapsed();
        mem::drop(outputs);
        Some(elapsed)
    })
}

/// Measures the execution time of the supplied function ignoring setup time.
///
/// This function does not include the time it takes to execute the setup function in the
/// measurements. This can be useful when you want to exclude the running time of some non-trivial
/// setup which is needed for every execution of the supplied function. However, it should be noted
/// that this function introduces a very small amount of overhead which will be reflected in the
/// measurements (typically of the order of a few nanoseconds).
///
/// **Warning:** This function can potentially allocate very large amounts of memory. The `memory`
/// option controls the maximum this function is allowed to allocate.
pub fn measure_setup<I, S, T, F>(
    options: &Options, mut setup: S, mut f: F
) -> Vec<Measurement> where S: FnMut() -> I, F: FnMut(I) -> T {
    measure_impl(options, |iterations| {
        if options.memory < Bytes(iterations * cmp::max(1, mem::size_of::<I>() as u64)) {
            return None;
        }
        let inputs = retain((0..iterations).map(|_| setup()).collect::<Vec<_>>());
        let stopwatch = Stopwatch::new();
        for input in inputs { retain(f(input)); }
        Some(stopwatch.elapsed())
    })
}

/// A function that prevents the optimizer from eliminating the supplied value.
///
/// This function may not operate correctly or may have poor performance on the stable and beta
/// channels of Rust. If you are using a nightly release of Rust, enable the `nightly` crate feature
/// to enable a superior implementation of this function.
pub fn retain<T>(value: T) -> T {
    utility::black_box(value)
}
<|endoftext|>