<commit_before>//! A library to parse and load configuration files.
//!
//! This library parses and loads configuration files in much the same way as C/C++'s
//! [libconfig](http://www.hyperrealm.com/libconfig/). At this time, it can only read and load
//! configurations, but future plans include a much richer user API to allow other forms of
//! interaction, such as manipulating values, writing the current configuration to a file, etc.
//!
//!# Getting started
//!
//! A configuration file consists of a group of settings. A setting is a key/value pair, where the
//! key is a string of the form `[a-zA-Z][-a-zA-Z0-9_]*`, and the value is anything represented by
//! `types::Value`. In a configuration file, setting/value pairs are written as
//! `setting_name = value;`. Possible values include primitive integer and floating point types,
//! strings, arrays, lists, etc.
//!
//! The library provides a bunch of methods to read the configuration data in the `reader` module.
//! The possibilities include reading from a string, from a file, or from anything that implements
//! the `Read` trait.
//!
//! As of now, every reader will first attempt to read the whole configuration into memory,
//! and only begins parsing once everything was read.
//!
//! In case of error, the parser returns a `config::error`.
//! On success, the parser returns a `Config`, which can then be used to browse the loaded data.
//!
//! Browsing is typically done with the `lookup_*` methods implemented by `Config`. The `lookup`
//! methods work with *paths*. Essentially, a path unambiguously describes the location of
//! a setting.
//!
//! For example, consider this input configuration file:
//!
//!```ignore
//! title = "My HTTP server";
//! listen_ports = [ 80, 443 ];
//! misc = {
//!     owner = "Chuck Norris";
//!     location = "CA";
//!     contact = {
//!         phone = "415-256-9999";
//!         // This is an array. Arrays start with `[` and end with `]`
//!         // Arrays are homogeneous and can only hold scalar data types.
//!         // See types::ScalarValue for further information
//!         emails = ["chuck@norris.com", "chuck.norris@gmail.com"];
//!     };
//! };
//!```
//!
//! At the top level, we have 3 settings: `title`, `listen_ports` and `misc`. `misc` is itself a
//! group of settings. Each value in this configuration is reachable by a unique path of settings
//! to follow. Each setting in a path is separated by `.`
//!
//! **Example**: The path `misc.contact.phone` identifies the setting with value `415-256-9999`.
//!
//! Array and list types are indexed using `[i]` in a path.
//!
//! **Example**: The path `listen_ports.[1]` identifies the setting with value `443`.
//!
//! **Example**: The path `misc.contact.emails.[0]` identifies the setting with value
//! `chuck@norris.com`
//!
//! Lists, as opposed to arrays, are heterogeneous and can store any data type, including other
//! lists. Here's a setting consisting of a heterogeneous list:
//!
//!```ignore
//! // This is a list. Lists start with `(` and end with `)`
//! // Lists are heterogeneous and can store any data type, including other lists
//! a_setting = ("a string", // The first element is a string
//!              ((1, 2, 3)), // The 2nd element is a list storing a list of 3 integers
//!              misc = { x = 4; y = 3; } // 3rd element: a group
//!             );
//!```
//!
//! Here are some valid paths for this example:
//!
//! `a_setting.[0]` - returns the string `a string`
//!
//! `a_setting.[1].[0].[2]` - returns the integer `3`
//!
//! `a_setting.[2].misc.x` - returns the integer `4`
//!
//! Adjacent string literals separated by whitespace, newlines and / or comments are automatically
//! concatenated.
//!
//! **Example**:
//!
//! ```ignore
//! "a"/* a comment */" string"    " liter"
//!
//! // This is a commment
//!
//!    "al"
//! ```
//!
//! is equivalent to:
//!
//! ```ignore
//! "a string literal"
//! ```
//!
//! See the integration tests (in the `tests/` directory) for sample use cases and more complex
//! examples.
//!
//!# Grammar
//!
//! This section describes the configuration input format. The starting rule is `conf`.
//!
//! ```text
//! conf -> __ settings_list __
//!
//! settings_list -> // empty
//!                | setting settings_list
//! setting -> __ name __ (":"|"=") __ value __ ";" __
//!
//! name -> [a-zA-Z][-a-zA-Z0-9_]*
//!
//! value -> scalar_value
//!        | array_value
//!        | list_value
//!        | group_value
//!
//! scalar_value -> boolean_scalar_value
//!               | floating64_scalar_value
//!               | floating32_scalar_value
//!               | integer64_scalar_value
//!               | integer32_scalar_value
//!               | str_scalar_value
//!
//! boolean_scalar_value -> [Tt][Rr][Uu][Ee]
//!                       | [Yy][Ee][Ss]
//!                       | [Ff][Aa][Ll][Ss][Ee]
//!                       | [Nn][Oo]
//!
//! floating64_scalar_value -> [+-]?([0-9]+\.[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?"L"
//!
//! floating32_scalar_value -> [+-]?([0-9]+\.[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?
//!
//! integer32_scalar_value -> [+-]?[0-9]+
//!
//! integer64_scalar_value -> [+-]?[0-9]+"L"
//!
//! str_scalar_value -> __ str_literal __
//!                   | __ str_literal __ str_scalar_value
//!
//! str_literal -> "\"" ([^\"\\]|(("\\r"|"\\n"|"\\t"|"\\\""|"\\\\")))* "\""
//!
//! array_value -> "["
//!                (bool_array |
//!                 flt64_array | flt32_array |
//!                 int64_array | int32_array |
//!                 str_array)
//!                "]"
//!              | "[" __ "]"
//!
//! bool_array -> __ boolean_scalar_value __
//!             | __ boolean_scalar_value __ "," __ bool_array
//!
//! flt64_array -> __ floating64_scalar_value __
//!              | __ floating64_scalar_value __ "," __ flt64_array
//!
//! flt32_array -> __ floating32_scalar_value __
//!              | __ floating32_scalar_value __ "," __ flt32_array
//
//! int64_array -> __ integer64_scalar_value __
//!              | __ integer64_scalar_value __ "," __ int64_array
//!
//! int32_array -> __ integer32_scalar_value __
//!              | __ integer32_scalar_value __ "," __ int32_array
//!
//! str_array -> __ str_scalar_value __
//!            | __ str_scalar_value __ "," __ str_array
//!
//! list_value -> "(" __ ")"
//!             | "(" list_elements ")"
//!
//! list_elements -> __ value __
//!                | __ value __ "," __ list_elements
//!
//! group_value -> "{" settings_list "}"
//!
//! __ -> // empty
//!     | whitespace __
//!     | eol __
//!     | comment __
//!
//! whitespace -> [\s\t]
//!
//! eol -> "\r\n"
//!      | "\n"
//!
//! comment -> single_line_comment
//!          | multi_line_comment
//!
//! single_line_comment -> ("//"|"#")[^\n]*"\n"?
//!
//! multi_line_comment -> "/*"([^*]|"*"[^/])*"*/"
//!
//! ```
//!

#![crate_name = "config"]
#![crate_type = "lib"]
#![warn(missing_docs)]

#[macro_use]
extern crate nom;

mod parser;

pub mod types;
pub mod error;
pub mod reader;
<commit_msg>Update the lib documentation on how to inject env vars<commit_after>//! A library to parse and load configuration files.
//!
//! This library parses and loads configuration files in much the same way as C/C++'s
//! [libconfig](http://www.hyperrealm.com/libconfig/). At this time, it can only read and load
//! configurations, but future plans include a much richer user API to allow other forms of
//! interaction, such as manipulating values, writing the current configuration to a file, etc.
//!
//!# Getting started
//!
//! A configuration file consists of a group of settings. A setting is a key/value pair, where the
//! key is a string of the form `[a-zA-Z][-a-zA-Z0-9_]*`, and the value is anything represented by
//! `types::Value`. In a configuration file, setting/value pairs are written as
//! `setting_name = value;`. Possible values include primitive integer and floating point types,
//! strings, arrays, lists, etc.
//!
//! The library provides a bunch of methods to read the configuration data in the `reader` module.
//! The possibilities include reading from a string, from a file, or from anything that implements
//! the `Read` trait.
//!
//! As of now, every reader will first attempt to read the whole configuration into memory,
//! and only begins parsing once everything was read.
//!
//! In case of error, the parser returns a `config::error`.
//! On success, the parser returns a `Config`, which can then be used to browse the loaded data.
//!
//! Browsing is typically done with the `lookup_*` methods implemented by `Config`. The `lookup`
//! methods work with *paths*. Essentially, a path unambiguously describes the location of
//! a setting.
//!
//! For example, consider this input configuration file:
//!
//!```ignore
//! title = "My HTTP server";
//! listen_ports = [ 80, 443 ];
//! misc = {
//!     owner = "Chuck Norris";
//!     location = "CA";
//!     contact = {
//!         phone = "415-256-9999";
//!         // This is an array. Arrays start with `[` and end with `]`
//!         // Arrays are homogeneous and can only hold scalar data types.
//!         // See types::ScalarValue for further information
//!         emails = ["chuck@norris.com", "chuck.norris@gmail.com"];
//!     };
//! };
//!```
//!
//! At the top level, we have 3 settings: `title`, `listen_ports` and `misc`. `misc` is itself a
//! group of settings. Each value in this configuration is reachable by a unique path of settings
//! to follow. Each setting in a path is separated by `.`
//!
//! **Example**: The path `misc.contact.phone` identifies the setting with value `415-256-9999`.
//!
//! Array and list types are indexed using `[i]` in a path.
//!
//! **Example**: The path `listen_ports.[1]` identifies the setting with value `443`.
//!
//! **Example**: The path `misc.contact.emails.[0]` identifies the setting with value
//! `chuck@norris.com`
//!
//! Lists, as opposed to arrays, are heterogeneous and can store any data type, including other
//! lists. Here's a setting consisting of a heterogeneous list:
//!
//!```ignore
//! // This is a list. Lists start with `(` and end with `)`
//! // Lists are heterogeneous and can store any data type, including other lists
//! a_setting = ("a string", // The first element is a string
//!              ((1, 2, 3)), // The 2nd element is a list storing a list of 3 integers
//!              misc = { x = 4; y = 3; } // 3rd element: a group
//!             );
//!```
//!
//! Here are some valid paths for this example:
//!
//! `a_setting.[0]` - returns the string `a string`
//!
//! `a_setting.[1].[0].[2]` - returns the integer `3`
//!
//! `a_setting.[2].misc.x` - returns the integer `4`
//!
//! Adjacent string literals separated by whitespace, newlines and / or comments are automatically
//! concatenated.
//!
//! **Example**:
//!
//! ```ignore
//! "a"/* a comment */" string"    " liter"
//!
//! // This is a commment
//!
//!    "al"
//! ```
//!
//! is equivalent to:
//!
//! ```ignore
//! "a string literal"
//! ```
//!
//! See the integration tests (in the `tests/` directory) for sample use cases and more complex
//! examples.
//!
//!# Environment variables
//!
//! The crate has an ability to inject environment variables into the configuration file. That
//! becomes possible using special symtax:
//!
//!  * $"SOME_ENV_VAR_NAME"::bool for `ScalarValue::Boolean`
//!  * $"SOME_ENV_VAR_NAME"::str for `ScalarValue::Str`
//!  * $"SOME_ENV_VAR_NAME"::i32 for `ScalarValue::Integer32`
//!  * $"SOME_ENV_VAR_NAME"::i64 for `ScalarValue::Integer64`
//!  * $"SOME_ENV_VAR_NAME"::f32 for `ScalarValue::Floating32`
//!  * $"SOME_ENV_VAR_NAME"::f64 for `ScalarValue::Floating64`
//!
//!
//! **Example**:
//!
//! ```ignore
//! log = {
//!       // Inject (use) the value of the environment variable LOG_LEVEL
//!       level = $"LOG_LEVEL"::str;
//! }
//! ```
//!
//!# Grammar
//!
//! This section describes the configuration input format. The starting rule is `conf`.
//!
//! ```text
//! conf -> __ settings_list __
//!
//! settings_list -> // empty
//!                | setting settings_list
//! setting -> __ name __ (":"|"=") __ value __ ";" __
//!
//! name -> [a-zA-Z][-a-zA-Z0-9_]*
//!
//! value -> scalar_value
//!        | array_value
//!        | list_value
//!        | group_value
//!
//! scalar_value -> boolean_scalar_value
//!               | floating64_scalar_value
//!               | floating32_scalar_value
//!               | integer64_scalar_value
//!               | integer32_scalar_value
//!               | str_scalar_value
//!
//! boolean_scalar_value -> [Tt][Rr][Uu][Ee]
//!                       | [Yy][Ee][Ss]
//!                       | [Ff][Aa][Ll][Ss][Ee]
//!                       | [Nn][Oo]
//!
//! floating64_scalar_value -> [+-]?([0-9]+\.[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?"L"
//!
//! floating32_scalar_value -> [+-]?([0-9]+\.[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?
//!
//! integer32_scalar_value -> [+-]?[0-9]+
//!
//! integer64_scalar_value -> [+-]?[0-9]+"L"
//!
//! str_scalar_value -> __ str_literal __
//!                   | __ str_literal __ str_scalar_value
//!
//! str_literal -> "\"" ([^\"\\]|(("\\r"|"\\n"|"\\t"|"\\\""|"\\\\")))* "\""
//!
//! array_value -> "["
//!                (bool_array |
//!                 flt64_array | flt32_array |
//!                 int64_array | int32_array |
//!                 str_array)
//!                "]"
//!              | "[" __ "]"
//!
//! bool_array -> __ boolean_scalar_value __
//!             | __ boolean_scalar_value __ "," __ bool_array
//!
//! flt64_array -> __ floating64_scalar_value __
//!              | __ floating64_scalar_value __ "," __ flt64_array
//!
//! flt32_array -> __ floating32_scalar_value __
//!              | __ floating32_scalar_value __ "," __ flt32_array
//
//! int64_array -> __ integer64_scalar_value __
//!              | __ integer64_scalar_value __ "," __ int64_array
//!
//! int32_array -> __ integer32_scalar_value __
//!              | __ integer32_scalar_value __ "," __ int32_array
//!
//! str_array -> __ str_scalar_value __
//!            | __ str_scalar_value __ "," __ str_array
//!
//! list_value -> "(" __ ")"
//!             | "(" list_elements ")"
//!
//! list_elements -> __ value __
//!                | __ value __ "," __ list_elements
//!
//! group_value -> "{" settings_list "}"
//!
//! __ -> // empty
//!     | whitespace __
//!     | eol __
//!     | comment __
//!
//! whitespace -> [\s\t]
//!
//! eol -> "\r\n"
//!      | "\n"
//!
//! comment -> single_line_comment
//!          | multi_line_comment
//!
//! single_line_comment -> ("//"|"#")[^\n]*"\n"?
//!
//! multi_line_comment -> "/*"([^*]|"*"[^/])*"*/"
//!
//! ```
//!

#![crate_name = "config"]
#![crate_type = "lib"]
#![warn(missing_docs)]

#[macro_use]
extern crate nom;

mod parser;

pub mod types;
pub mod error;
pub mod reader;
<|endoftext|>


<commit_before>pub mod types;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Turn off Camel case warning on types<commit_after>#![allow(non_camel_case_types)]
pub mod types;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate failure;

extern crate itertools;

extern crate lazy_init;

extern crate petgraph;

mod error;
pub use error::{GraphError, ReadError};

mod features;
pub use features::Features;

mod graph;
pub(crate) use graph::BfsWithDepth;

mod proj;
pub use proj::{Deprojectivize, HeadProjectivizer, Projectivize};

#[cfg(test)]
pub(crate) use proj::{non_projective_edges, sentence_to_graph};

mod reader;
pub use reader::{ReadSentence, Reader, Sentences};

mod token;
pub use token::{Sentence, Token, TokenBuilder};

mod writer;
pub use writer::{PartitioningWriter, WriteSentence, Writer};

#[cfg(test)]
mod tests;

#[cfg(test)]
#[macro_use]
extern crate lazy_static;

#[cfg(test)]
#[macro_use]
extern crate maplit;

#[cfg(test)]
#[macro_use]
extern crate pretty_assertions;

#[cfg(test)]
#[macro_use]
extern crate quickcheck;
<commit_msg>Make DisplaySentence public.<commit_after>#[macro_use]
extern crate failure;

extern crate itertools;

extern crate lazy_init;

extern crate petgraph;

mod error;
pub use error::{GraphError, ReadError};

mod features;
pub use features::Features;

mod graph;
pub(crate) use graph::BfsWithDepth;

mod proj;
pub use proj::{Deprojectivize, HeadProjectivizer, Projectivize};

#[cfg(test)]
pub(crate) use proj::{non_projective_edges, sentence_to_graph};

mod reader;
pub use reader::{ReadSentence, Reader, Sentences};

mod token;
pub use token::{DisplaySentence, Sentence, Token, TokenBuilder};

mod writer;
pub use writer::{PartitioningWriter, WriteSentence, Writer};

#[cfg(test)]
mod tests;

#[cfg(test)]
#[macro_use]
extern crate lazy_static;

#[cfg(test)]
#[macro_use]
extern crate maplit;

#[cfg(test)]
#[macro_use]
extern crate pretty_assertions;

#[cfg(test)]
#[macro_use]
extern crate quickcheck;
<|endoftext|>


<commit_before>extern crate rand;
extern crate rayon;

use std::cmp::{self, Ordering};
use std::f32;
use rand::Rng;
use selection::tournament_selection_fast;
use mo::MultiObjective;
pub use self::domination::Dominate;
use domination::fast_non_dominated_sort;
use rayon::par_iter::*;
use std::convert::{AsRef, From};
use std::iter::FromIterator;

pub mod selection;
pub mod mo;
pub mod domination;

impl<T: MultiObjective> Dominate<T> for T {
    fn dominates(&self, other: &Self) -> bool {
        let mut less_cnt = 0;
        for i in 0..cmp::min(self.num_objectives(), other.num_objectives()) {
            match self.cmp_objective(other, i) {
                Ordering::Greater => {
                    return false;
                }
                Ordering::Less => {
                    less_cnt += 1;
                }
                Ordering::Equal => {}
            }
        }
        return less_cnt > 0;
    }
}

#[derive(Debug)]
pub struct SolutionRankDist {
    pub idx: usize,
    pub rank: u32,
    pub dist: f32,
}

impl PartialEq for SolutionRankDist {
    #[inline]
    fn eq(&self, other: &SolutionRankDist) -> bool {
        self.rank == other.rank && self.dist == other.dist
    }
}

// Implement the crowding-distance comparison operator.
impl PartialOrd for SolutionRankDist {
    #[inline]
    // compare on rank first (ASC), then on dist (DESC)
    fn partial_cmp(&self, other: &SolutionRankDist) -> Option<Ordering> {
        match self.rank.partial_cmp(&other.rank) {
            Some(Ordering::Equal) => {
                // first criterion equal, second criterion decides
                // reverse ordering
                self.dist.partial_cmp(&other.dist).map(|i| i.reverse())
            }
            other => other,
        }
    }
}

fn crowding_distance_assignment<P: MultiObjective>(solutions: &[P],
                                                   common_rank: u32,
                                                   individuals_idx: &[usize],
                                                   num_objectives: usize)
                                                   -> Vec<SolutionRankDist> {
    assert!(num_objectives > 0);

    let l = individuals_idx.len();
    let mut distance: Vec<f32> = (0..l).map(|_| 0.0).collect();
    let mut indices: Vec<usize> = (0..l).map(|i| i).collect();

    for m in 0..num_objectives {
        // sort using objective `m`
        indices.sort_by(|&a, &b| {
            solutions[individuals_idx[a]].cmp_objective(&solutions[individuals_idx[b]], m)
        });
        distance[indices[0]] = f32::INFINITY;
        distance[indices[l - 1]] = f32::INFINITY;

        let min_idx = individuals_idx[indices[0]];
        let max_idx = individuals_idx[indices[l - 1]];

        let dist_max_min = solutions[max_idx].dist_objective(&solutions[min_idx], m);
        if dist_max_min != 0.0 {
            let norm = num_objectives as f32 * dist_max_min;
            debug_assert!(norm != 0.0);
            for i in 1..(l - 1) {
                let next_idx = individuals_idx[indices[i + 1]];
                let prev_idx = individuals_idx[indices[i - 1]];
                distance[indices[i]] += solutions[next_idx]
                                            .dist_objective(&solutions[prev_idx], m) /
                                        norm;
            }
        }
    }

    return indices.iter()
                  .map(|&i| {
                      SolutionRankDist {
                          idx: individuals_idx[i],
                          rank: common_rank,
                          dist: distance[i],
                      }
                  })
                  .collect();
}

/// Select `n` out of the `solutions`, assigning rank and distance using the first `num_objectives`
/// objectives.
fn select_solutions<P: Dominate + MultiObjective>(solutions: &[P],
                                                  n: usize,
                                                  num_objectives: usize)
                                                  -> Vec<SolutionRankDist> {
    let mut selection = Vec::with_capacity(cmp::min(solutions.len(), n));

    let pareto_fronts = fast_non_dominated_sort(solutions, n);

    for (rank, front) in pareto_fronts.iter().enumerate() {
        if selection.len() >= n {
            break;
        }
        let missing: usize = n - selection.len();

        let mut solution_rank_dist = crowding_distance_assignment(solutions,
                                                                  rank as u32,
                                                                  &front[..],
                                                                  num_objectives);
        if solution_rank_dist.len() <= missing {
            // whole front fits into result.
            selection.extend(solution_rank_dist);
            assert!(selection.len() <= n);
        } else {
            // choose only best from this front, according to the crowding distance.
            solution_rank_dist.sort_by(|a, b| {
                debug_assert!(a.rank == b.rank);
                a.partial_cmp(b).unwrap()
            });
            selection.extend(solution_rank_dist.into_iter().take(missing));
            assert!(selection.len() == n);
            break;
        }
    }

    return selection;
}

/// An unrated Population of individuals.
pub struct UnratedPopulation<I>
    where I: Clone
{
    individuals: Vec<I>,
}

/// A rated Population of individuals, i.e.
/// each individual has a fitness assigned.
pub struct RatedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    individuals: Vec<I>,
    fitness: Vec<F>,
}

/// A selected (ranked) Population.
pub struct SelectedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    individuals: Vec<I>,
    fitness: Vec<F>,
    rank_dist: Vec<SolutionRankDist>,
}

impl<I> From<Vec<I>> for UnratedPopulation<I> where I: Clone
{
    fn from(v: Vec<I>) -> UnratedPopulation<I> {
        UnratedPopulation { individuals: v }
    }
}

impl<I> FromIterator<I> for UnratedPopulation<I> where I: Clone
{
    fn from_iter<T>(iterator: T) -> UnratedPopulation<I>
        where T: IntoIterator<Item = I>
    {
        UnratedPopulation { individuals: iterator.into_iter().collect() }
    }
}

impl<I> AsRef<[I]> for UnratedPopulation<I> where I: Clone
{
    fn as_ref(&self) -> &[I] {
        &self.individuals
    }
}

impl<I> UnratedPopulation<I> where I: Clone + Sync
{
    pub fn individuals(&self) -> &[I] {
        &self.individuals
    }

    pub fn new() -> UnratedPopulation<I> {
        UnratedPopulation { individuals: Vec::new() }
    }

    pub fn push(&mut self, ind: I) {
        self.individuals.push(ind);
    }

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

    /// Rate the individuals.
    pub fn rate<F, E>(self, eval: &E) -> RatedPopulation<I, F>
        where F: Dominate + MultiObjective + Clone,
              E: Fn(&I) -> F
    {
        let fitness = self.individuals.iter().map(eval).collect();
        RatedPopulation {
            individuals: self.individuals,
            fitness: fitness,
        }
    }

    /// Rate the individuals in parallel.
    pub fn rate_in_parallel<F, E>(self, eval: &E, weight: f64) -> RatedPopulation<I, F>
        where F: Dominate + MultiObjective + Clone + Send,
              E: Sync + Fn(&I) -> F
    {
        let mut fitness = Vec::new();
        self.individuals.into_par_iter().map(eval).weight(weight).collect_into(&mut fitness);
        assert!(fitness.len() == self.individuals.len());

        RatedPopulation {
            individuals: self.individuals,
            fitness: fitness,
        }
    }
}

impl<I, F> RatedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    pub fn select(self, population_size: usize, num_objectives: usize) -> SelectedPopulation<I, F> {
        // evaluate rank and crowding distance
        let rank_dist = select_solutions(&self.fitness, population_size, num_objectives);
        assert!(rank_dist.len() <= population_size);
        SelectedPopulation {
            individuals: self.individuals,
            fitness: self.fitness,
            rank_dist: rank_dist,
        }
    }

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

    pub fn fitness(&self) -> &[F] {
        &self.fitness
    }
}

impl<I, F> SelectedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    /// Generate an offspring population.
    pub fn reproduce<R, M>(&self,
                           rng: &mut R,
                           offspring_size: usize,
                           tournament_k: usize,
                           mate: &mut M)
                           -> UnratedPopulation<I>
        where R: Rng,
              M: FnMut(&mut R, &I, &I) -> I
    {
        assert!(self.individuals.len() == self.fitness.len());
        assert!(self.individuals.len() >= self.rank_dist.len());
        assert!(tournament_k > 0);

        let rank_dist = &self.rank_dist[..];

        // create `offspring_size` new offspring using k-tournament (
        // select the best individual out of k randomly choosen individuals)
        let offspring: Vec<I> =
            (0..offspring_size)
                .map(|_| {

                    // first parent. k candidates
                    let p1 = tournament_selection_fast(rng,
                                                       |i1, i2| rank_dist[i1] < rank_dist[i2],
                                                       rank_dist.len(),
                                                       tournament_k);

                    // second parent. k candidates
                    let p2 = tournament_selection_fast(rng,
                                                       |i1, i2| rank_dist[i1] < rank_dist[i2],
                                                       rank_dist.len(),
                                                       tournament_k);

                    // cross-over the two parents and produce one child (throw away
                    // second child XXX)

                    // The potentially dominating individual is gives as first
                    // parameter.
                    let (p1, p2) = if rank_dist[p1] < rank_dist[p2] {
                        (p1, p2)
                    } else if rank_dist[p2] < rank_dist[p1] {
                        (p2, p1)
                    } else {
                        (p1, p2)
                    };

                    mate(rng, &self.individuals[p1], &self.individuals[p2])
                })
                .collect();

        assert!(offspring.len() == offspring_size);

        UnratedPopulation { individuals: offspring }
    }

    pub fn len(&self) -> usize {
        // NOTE: the population and fitness arrays might still be larger.
        self.rank_dist.len()
    }

    /// Merging a selected population result in a rated population as the selection
    /// criteria is no longer met.
    pub fn merge(self, offspring: RatedPopulation<I, F>) -> RatedPopulation<I, F> {
        let mut new_ind = Vec::with_capacity(self.len() + offspring.len());
        let mut new_fit = Vec::with_capacity(self.len() + offspring.len());
        for rd in self.rank_dist.iter() {
            // XXX: Optimize. Avoid clone
            new_ind.push(self.individuals[rd.idx].clone());
            new_fit.push(self.fitness[rd.idx].clone());
        }

        new_ind.extend(offspring.individuals);
        new_fit.extend(offspring.fitness);

        assert!(new_ind.len() == new_fit.len());

        RatedPopulation {
            individuals: new_ind,
            fitness: new_fit,
        }
    }

    pub fn all_of_rank<C>(&self, rank: usize, f: &mut C)
        where C: FnMut(&I, &F)
    {
        for rd in self.rank_dist.iter() {
            if rd.rank as usize == rank {
                f(&self.individuals[rd.idx], &self.fitness[rd.idx]);
            }
        }
    }
}

#[test]
fn test_dominates() {
    use mo::MultiObjective2;

    let a = MultiObjective2::from((1.0f32, 0.1));
    let b = MultiObjective2::from((0.1f32, 0.1));
    let c = MultiObjective2::from((0.1f32, 1.0));

    assert_eq!(false, a.dominates(&a));
    assert_eq!(false, a.dominates(&b));
    assert_eq!(false, a.dominates(&c));

    assert_eq!(true, b.dominates(&a));
    assert_eq!(false, b.dominates(&b));
    assert_eq!(true, b.dominates(&c));

    assert_eq!(false, c.dominates(&a));
    assert_eq!(false, c.dominates(&b));
    assert_eq!(false, c.dominates(&c));
}

#[test]
fn test_abc() {
    use mo::MultiObjective2;

    let mut solutions: Vec<MultiObjective2<f32>> = Vec::new();
    solutions.push(MultiObjective2::from((1.0, 0.1)));
    solutions.push(MultiObjective2::from((0.1, 0.1)));
    solutions.push(MultiObjective2::from((0.1, 1.0)));
    solutions.push(MultiObjective2::from((0.5, 0.5)));
    solutions.push(MultiObjective2::from((0.5, 0.5)));

    println!("solutions: {:?}", solutions);
    let selection = select_solutions(&solutions[..], 5, 2);
    println!("selection: {:?}", selection);

    let fronts = fast_non_dominated_sort(&solutions[..], 10);
    println!("solutions: {:?}", solutions);
    println!("fronts: {:?}", fronts);

    for (rank, front) in fronts.iter().enumerate() {
        let distances = crowding_distance_assignment(&solutions[..], rank as u32, &front[..], 2);
        println!("front: {:?}", front);
        println!("distances: {:?}", distances);
    }
}
<commit_msg>FnMut -> Fn<commit_after>extern crate rand;
extern crate rayon;

use std::cmp::{self, Ordering};
use std::f32;
use rand::Rng;
use selection::tournament_selection_fast;
use mo::MultiObjective;
pub use self::domination::Dominate;
use domination::fast_non_dominated_sort;
use rayon::par_iter::*;
use std::convert::{AsRef, From};
use std::iter::FromIterator;

pub mod selection;
pub mod mo;
pub mod domination;

impl<T: MultiObjective> Dominate<T> for T {
    fn dominates(&self, other: &Self) -> bool {
        let mut less_cnt = 0;
        for i in 0..cmp::min(self.num_objectives(), other.num_objectives()) {
            match self.cmp_objective(other, i) {
                Ordering::Greater => {
                    return false;
                }
                Ordering::Less => {
                    less_cnt += 1;
                }
                Ordering::Equal => {}
            }
        }
        return less_cnt > 0;
    }
}

#[derive(Debug)]
pub struct SolutionRankDist {
    pub idx: usize,
    pub rank: u32,
    pub dist: f32,
}

impl PartialEq for SolutionRankDist {
    #[inline]
    fn eq(&self, other: &SolutionRankDist) -> bool {
        self.rank == other.rank && self.dist == other.dist
    }
}

// Implement the crowding-distance comparison operator.
impl PartialOrd for SolutionRankDist {
    #[inline]
    // compare on rank first (ASC), then on dist (DESC)
    fn partial_cmp(&self, other: &SolutionRankDist) -> Option<Ordering> {
        match self.rank.partial_cmp(&other.rank) {
            Some(Ordering::Equal) => {
                // first criterion equal, second criterion decides
                // reverse ordering
                self.dist.partial_cmp(&other.dist).map(|i| i.reverse())
            }
            other => other,
        }
    }
}

fn crowding_distance_assignment<P: MultiObjective>(solutions: &[P],
                                                   common_rank: u32,
                                                   individuals_idx: &[usize],
                                                   num_objectives: usize)
                                                   -> Vec<SolutionRankDist> {
    assert!(num_objectives > 0);

    let l = individuals_idx.len();
    let mut distance: Vec<f32> = (0..l).map(|_| 0.0).collect();
    let mut indices: Vec<usize> = (0..l).map(|i| i).collect();

    for m in 0..num_objectives {
        // sort using objective `m`
        indices.sort_by(|&a, &b| {
            solutions[individuals_idx[a]].cmp_objective(&solutions[individuals_idx[b]], m)
        });
        distance[indices[0]] = f32::INFINITY;
        distance[indices[l - 1]] = f32::INFINITY;

        let min_idx = individuals_idx[indices[0]];
        let max_idx = individuals_idx[indices[l - 1]];

        let dist_max_min = solutions[max_idx].dist_objective(&solutions[min_idx], m);
        if dist_max_min != 0.0 {
            let norm = num_objectives as f32 * dist_max_min;
            debug_assert!(norm != 0.0);
            for i in 1..(l - 1) {
                let next_idx = individuals_idx[indices[i + 1]];
                let prev_idx = individuals_idx[indices[i - 1]];
                distance[indices[i]] += solutions[next_idx]
                                            .dist_objective(&solutions[prev_idx], m) /
                                        norm;
            }
        }
    }

    return indices.iter()
                  .map(|&i| {
                      SolutionRankDist {
                          idx: individuals_idx[i],
                          rank: common_rank,
                          dist: distance[i],
                      }
                  })
                  .collect();
}

/// Select `n` out of the `solutions`, assigning rank and distance using the first `num_objectives`
/// objectives.
fn select_solutions<P: Dominate + MultiObjective>(solutions: &[P],
                                                  n: usize,
                                                  num_objectives: usize)
                                                  -> Vec<SolutionRankDist> {
    let mut selection = Vec::with_capacity(cmp::min(solutions.len(), n));

    let pareto_fronts = fast_non_dominated_sort(solutions, n);

    for (rank, front) in pareto_fronts.iter().enumerate() {
        if selection.len() >= n {
            break;
        }
        let missing: usize = n - selection.len();

        let mut solution_rank_dist = crowding_distance_assignment(solutions,
                                                                  rank as u32,
                                                                  &front[..],
                                                                  num_objectives);
        if solution_rank_dist.len() <= missing {
            // whole front fits into result.
            selection.extend(solution_rank_dist);
            assert!(selection.len() <= n);
        } else {
            // choose only best from this front, according to the crowding distance.
            solution_rank_dist.sort_by(|a, b| {
                debug_assert!(a.rank == b.rank);
                a.partial_cmp(b).unwrap()
            });
            selection.extend(solution_rank_dist.into_iter().take(missing));
            assert!(selection.len() == n);
            break;
        }
    }

    return selection;
}

/// An unrated Population of individuals.
pub struct UnratedPopulation<I>
    where I: Clone
{
    individuals: Vec<I>,
}

/// A rated Population of individuals, i.e.
/// each individual has a fitness assigned.
pub struct RatedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    individuals: Vec<I>,
    fitness: Vec<F>,
}

/// A selected (ranked) Population.
pub struct SelectedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    individuals: Vec<I>,
    fitness: Vec<F>,
    rank_dist: Vec<SolutionRankDist>,
}

impl<I> From<Vec<I>> for UnratedPopulation<I> where I: Clone
{
    fn from(v: Vec<I>) -> UnratedPopulation<I> {
        UnratedPopulation { individuals: v }
    }
}

impl<I> FromIterator<I> for UnratedPopulation<I> where I: Clone
{
    fn from_iter<T>(iterator: T) -> UnratedPopulation<I>
        where T: IntoIterator<Item = I>
    {
        UnratedPopulation { individuals: iterator.into_iter().collect() }
    }
}

impl<I> AsRef<[I]> for UnratedPopulation<I> where I: Clone
{
    fn as_ref(&self) -> &[I] {
        &self.individuals
    }
}

impl<I> UnratedPopulation<I> where I: Clone + Sync
{
    pub fn individuals(&self) -> &[I] {
        &self.individuals
    }

    pub fn new() -> UnratedPopulation<I> {
        UnratedPopulation { individuals: Vec::new() }
    }

    pub fn push(&mut self, ind: I) {
        self.individuals.push(ind);
    }

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

    /// Rate the individuals.
    pub fn rate<F, E>(self, eval: &E) -> RatedPopulation<I, F>
        where F: Dominate + MultiObjective + Clone,
              E: Fn(&I) -> F
    {
        let fitness = self.individuals.iter().map(eval).collect();
        RatedPopulation {
            individuals: self.individuals,
            fitness: fitness,
        }
    }

    /// Rate the individuals in parallel.
    pub fn rate_in_parallel<F, E>(self, eval: &E, weight: f64) -> RatedPopulation<I, F>
        where F: Dominate + MultiObjective + Clone + Send,
              E: Sync + Fn(&I) -> F
    {
        let mut fitness = Vec::new();
        self.individuals.into_par_iter().map(eval).weight(weight).collect_into(&mut fitness);
        assert!(fitness.len() == self.individuals.len());

        RatedPopulation {
            individuals: self.individuals,
            fitness: fitness,
        }
    }
}

impl<I, F> RatedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    pub fn select(self, population_size: usize, num_objectives: usize) -> SelectedPopulation<I, F> {
        // evaluate rank and crowding distance
        let rank_dist = select_solutions(&self.fitness, population_size, num_objectives);
        assert!(rank_dist.len() <= population_size);
        SelectedPopulation {
            individuals: self.individuals,
            fitness: self.fitness,
            rank_dist: rank_dist,
        }
    }

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

    pub fn fitness(&self) -> &[F] {
        &self.fitness
    }
}

impl<I, F> SelectedPopulation<I, F>
    where I: Clone,
          F: Dominate + MultiObjective + Clone
{
    /// Generate an offspring population.
    pub fn reproduce<R, M>(&self,
                           rng: &mut R,
                           offspring_size: usize,
                           tournament_k: usize,
                           mate: &M)
                           -> UnratedPopulation<I>
        where R: Rng,
              M: Fn(&mut R, &I, &I) -> I
    {
        assert!(self.individuals.len() == self.fitness.len());
        assert!(self.individuals.len() >= self.rank_dist.len());
        assert!(tournament_k > 0);

        let rank_dist = &self.rank_dist[..];

        // create `offspring_size` new offspring using k-tournament (
        // select the best individual out of k randomly choosen individuals)
        let offspring: Vec<I> =
            (0..offspring_size)
                .map(|_| {

                    // first parent. k candidates
                    let p1 = tournament_selection_fast(rng,
                                                       |i1, i2| rank_dist[i1] < rank_dist[i2],
                                                       rank_dist.len(),
                                                       tournament_k);

                    // second parent. k candidates
                    let p2 = tournament_selection_fast(rng,
                                                       |i1, i2| rank_dist[i1] < rank_dist[i2],
                                                       rank_dist.len(),
                                                       tournament_k);

                    // cross-over the two parents and produce one child (throw away
                    // second child XXX)

                    // The potentially dominating individual is gives as first
                    // parameter.
                    let (p1, p2) = if rank_dist[p1] < rank_dist[p2] {
                        (p1, p2)
                    } else if rank_dist[p2] < rank_dist[p1] {
                        (p2, p1)
                    } else {
                        (p1, p2)
                    };

                    mate(rng, &self.individuals[p1], &self.individuals[p2])
                })
                .collect();

        assert!(offspring.len() == offspring_size);

        UnratedPopulation { individuals: offspring }
    }

    pub fn len(&self) -> usize {
        // NOTE: the population and fitness arrays might still be larger.
        self.rank_dist.len()
    }

    /// Merging a selected population result in a rated population as the selection
    /// criteria is no longer met.
    pub fn merge(self, offspring: RatedPopulation<I, F>) -> RatedPopulation<I, F> {
        let mut new_ind = Vec::with_capacity(self.len() + offspring.len());
        let mut new_fit = Vec::with_capacity(self.len() + offspring.len());
        for rd in self.rank_dist.iter() {
            // XXX: Optimize. Avoid clone
            new_ind.push(self.individuals[rd.idx].clone());
            new_fit.push(self.fitness[rd.idx].clone());
        }

        new_ind.extend(offspring.individuals);
        new_fit.extend(offspring.fitness);

        assert!(new_ind.len() == new_fit.len());

        RatedPopulation {
            individuals: new_ind,
            fitness: new_fit,
        }
    }

    pub fn all_of_rank<C>(&self, rank: usize, f: &mut C)
        where C: FnMut(&I, &F)
    {
        for rd in self.rank_dist.iter() {
            if rd.rank as usize == rank {
                f(&self.individuals[rd.idx], &self.fitness[rd.idx]);
            }
        }
    }
}

#[test]
fn test_dominates() {
    use mo::MultiObjective2;

    let a = MultiObjective2::from((1.0f32, 0.1));
    let b = MultiObjective2::from((0.1f32, 0.1));
    let c = MultiObjective2::from((0.1f32, 1.0));

    assert_eq!(false, a.dominates(&a));
    assert_eq!(false, a.dominates(&b));
    assert_eq!(false, a.dominates(&c));

    assert_eq!(true, b.dominates(&a));
    assert_eq!(false, b.dominates(&b));
    assert_eq!(true, b.dominates(&c));

    assert_eq!(false, c.dominates(&a));
    assert_eq!(false, c.dominates(&b));
    assert_eq!(false, c.dominates(&c));
}

#[test]
fn test_abc() {
    use mo::MultiObjective2;

    let mut solutions: Vec<MultiObjective2<f32>> = Vec::new();
    solutions.push(MultiObjective2::from((1.0, 0.1)));
    solutions.push(MultiObjective2::from((0.1, 0.1)));
    solutions.push(MultiObjective2::from((0.1, 1.0)));
    solutions.push(MultiObjective2::from((0.5, 0.5)));
    solutions.push(MultiObjective2::from((0.5, 0.5)));

    println!("solutions: {:?}", solutions);
    let selection = select_solutions(&solutions[..], 5, 2);
    println!("selection: {:?}", selection);

    let fronts = fast_non_dominated_sort(&solutions[..], 10);
    println!("solutions: {:?}", solutions);
    println!("fronts: {:?}", fronts);

    for (rank, front) in fronts.iter().enumerate() {
        let distances = crowding_distance_assignment(&solutions[..], rank as u32, &front[..], 2);
        println!("front: {:?}", front);
        println!("distances: {:?}", distances);
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Doug Goldstein
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A simple logger to provide symantics similar to what is expected
//! of most UNIX utilities by logging to stderr and the higher the
//! verbosity the higher the log level. Additionally it supports the
//! ability to provide timestamps at different granularities.
//!
//! ## Simple Use Case
//!
//! ```rust
//! #[macro_use]
//! extern crate log;
//! extern crate stderrlog;
//!
//! fn main() {
//!     stderrlog::new().module(module_path!()).init().unwrap();
//!
//!     info!("starting up");
//!
//!     // ...
//! }
//! ```
//!
//! ## docopt Example
//!
//! ```rust
//! extern crate docopt;
//! #[macro_use]
//! extern crate log;
//! extern crate rustc_serialize;
//! extern crate stderrlog;
//!
//! use docopt::Docopt;
//!
//! const USAGE: &'static str = "
//! Usage: program [-q] [-v...]
//! ";
//!
//! #[derive(Debug, RustcDecodable)]
//! struct Args {
//!     flag_q: bool,
//!     flag_v: usize,
//! }
//!
//! fn main() {
//!     let args: Args = Docopt::new(USAGE)
//!                             .and_then(|d| d.decode())
//!                             .unwrap_or_else(|e| e.exit());
//!
//!     stderrlog::new()
//!             .module(module_path!())
//!             .quiet(args.flag_q)
//!             .timestamp(stderrlog::Timestamp::Second)
//!             .verbosity(args.flag_v)
//!             .init()
//!             .unwrap();
//!     trace!("trace message");
//!     debug!("debug message");
//!     info!("info message");
//!     warn!("warn message");
//!     error!("error message");
//!
//!     // ...
//! }
//! ```
//!
//! # clap Example
//!
//! ```
//! #[macro_use]
//! extern crate clap;
//! #[macro_use]
//! extern crate log;
//! extern crate stderrlog;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let m = App::new("stderrlog example")
//!         .version(crate_version!())
//!         .arg(Arg::with_name("verbosity")
//!              .short("v")
//!              .multiple(true)
//!              .help("Increase message verbosity"))
//!         .arg(Arg::with_name("quiet")
//!              .short("q")
//!              .help("Silence all output"))
//!         .arg(Arg::with_name("timestamp")
//!              .short("t")
//!              .help("prepend log lines with a timestamp")
//!              .takes_value(true)
//!              .possible_values(&["none", "sec", "ms", "ns"]))
//!         .get_matches();
//!
//!     let verbose = m.occurrences_of("verbosity") as usize;
//!     let quiet = m.is_present("quiet");
//!     let ts = match m.value_of("timestamp") {
//!         Some("ns") => stderrlog::Timestamp::Nanosecond,
//!         Some("ms") => stderrlog::Timestamp::Microsecond,
//!         Some("sec") => stderrlog::Timestamp::Second,
//!         Some("none") | None => stderrlog::Timestamp::Off,
//!         Some(_) => clap::Error {
//!             message: "invalid value for 'timestamp'".into(),
//!             kind: clap::ErrorKind::InvalidValue,
//!             info: None,
//!         }.exit(),
//!     };
//!
//!     stderrlog::new()
//!         .module(module_path!())
//!         .quiet(quiet)
//!         .verbosity(verbose)
//!         .timestamp(ts)
//!         .init()
//!         .unwrap();
//!     trace!("trace message");
//!     debug!("debug message");
//!     info!("info message");
//!     warn!("warn message");
//!     error!("error message");
//! }
//! ```
//!
//! ### Compatibility Policy
//!
//! `stderrlog` is serious about backwards compat. `stderrlog`
//! pins the minimum required version of Rust in the CI build.
//! Bumping the minimum version of Rust is a minor breaking
//! change and requires a minor version to be bumped.
//!
//! The minimum supported Rust version for this release is 1.16.0.
//!
//! ### Module Level Logging
//!
//! `stderrlog` has the ability to limit the components which can log.
//! Many crates use [log](https://docs.rs/log/*/log/) but you may not
//! want their output in your application. For example
//! [hyper](https://docs.rs/hyper/*/hyper/) makes heavy use of log but
//! when your application receives `-vvvvv` to enable the `trace!()`
//! messages you don't want the output of `hyper`'s `trace!()` level.
//!
//! To support this `stderrlog` includes a `module()` method allowing
//! you to specify the modules that are allowed to log. The examples
//! above use the `module_path!()` macro to enable logging only for
//! the binary itself but none of its dependencies. To enable logging
//! from extra crates just add another call to `module()` with the
//! name of the crate. To enable logging for only a module within
//! that crate specifiy `crate::module` to `module()`. crates and
//! modules will be named the same way would would include them in
//! source code with `use` (e.g. `some-crate` would be `some_crate`).
//!
//! For a good example of how the module level logging works see the
//! large-example project under examples, you'll want to run the
//! following binaries to see all the examples:
//! - cargo run --bin large-example --
//! - cargo run --bin another --
//! - cargo run --bin yet --

extern crate chrono;
extern crate log;
extern crate termcolor;
extern crate thread_local;

use chrono::Local;
use log::{LogLevel, LogLevelFilter, LogMetadata};
use std::cell::RefCell;
use std::io::{self, Write};
use std::fmt;
use termcolor::{Color, ColorSpec, StandardStream, WriteColor};
use thread_local::CachedThreadLocal;

pub use termcolor::ColorChoice;

/// State of the timestampping in the logger.
#[derive(Clone, Copy, Debug)]
pub enum Timestamp {
    /// Disable timestamping of log messages
    Off,
    /// Timestamp with second granularity
    Second,
    /// Timestamp with microsecond granularity
    Microsecond,
    /// Timestamp with nanosecond granularity
    Nanosecond,
}

/// Data specific to this logger
pub struct StdErrLog {
    verbosity: LogLevelFilter,
    quiet: bool,
    timestamp: Timestamp,
    modules: Vec<String>,
    writer: CachedThreadLocal<RefCell<io::LineWriter<StandardStream>>>,
    color_choice: ColorChoice,
}

impl fmt::Debug for StdErrLog {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("StdErrLog")
            .field("verbosity", &self.verbosity)
            .field("quiet", &self.quiet)
            .field("timestamp", &self.timestamp)
            .field("modules", &self.modules)
            .field("writer", &"stderr")
            .field("color_choice", &self.color_choice)
            .finish()
    }
}

impl Clone for StdErrLog {
    fn clone(&self) -> StdErrLog {
        StdErrLog {
            modules: self.modules.clone(),
            writer: CachedThreadLocal::new(),
            .. *self
        }
    }
}

impl log::Log for StdErrLog {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.log_level_filter() && self.includes_module(metadata.target())
    }

    fn log(&self, record: &log::LogRecord) {

        // if logging isn't enabled for this level do a quick out
        if !self.enabled(record.metadata()) {
            return;
        }

        let writer =
            self.writer.get_or(|| Box::new(RefCell::new(io::LineWriter::new(StandardStream::stderr(self.color_choice)))));
        let mut writer = writer.borrow_mut();
        let color = match record.metadata().level() {
            LogLevel::Error => Color::Red,
            LogLevel::Warn => Color::Magenta,
            LogLevel::Info => Color::Yellow,
            LogLevel::Debug => Color::Cyan,
            LogLevel::Trace => Color::Blue,
        };
        {
            writer.get_mut().set_color(ColorSpec::new().set_fg(Some(color))).expect("failed to set color");
        }
        match self.timestamp {
            Timestamp::Second => {
                let fmt = "%Y-%m-%dT%H:%M:%S%:z";
                let _ = write!(writer, "{} - ", Local::now().format(fmt));
            },
            Timestamp::Microsecond => {
                let fmt = "%Y-%m-%dT%H:%M:%S%.6f%:z";
                let _ = write!(writer, "{} - ", Local::now().format(fmt));
            },
            Timestamp::Nanosecond => {
                let fmt = "%Y-%m-%dT%H:%M:%S%.9f%:z";
                let _ = write!(writer, "{} - ", Local::now().format(fmt));
            },
            Timestamp::Off => {},
        }
        let _ = writeln!(writer, "{} - {}", record.level(), record.args());
        {
            writer.get_mut().reset().expect("failed to reset the color");
        }
    }
}

impl StdErrLog {
    /// creates a new stderr logger
    pub fn new() -> StdErrLog {
        StdErrLog {
            verbosity: LogLevelFilter::Error,
            quiet: false,
            timestamp: Timestamp::Off,
            modules: Vec::new(),
            writer: CachedThreadLocal::new(),
            color_choice: ColorChoice::Auto,
        }
    }

    /// Sets the verbosity level of messages that will be displayed
    pub fn verbosity(&mut self, verbosity: usize) -> &mut StdErrLog {
        let log_lvl = match verbosity {
            0 => LogLevelFilter::Error,
            1 => LogLevelFilter::Warn,
            2 => LogLevelFilter::Info,
            3 => LogLevelFilter::Debug,
            _ => LogLevelFilter::Trace,
        };

        self.verbosity = log_lvl;
        self
    }

    /// silence all output, no matter the value of verbosity
    pub fn quiet(&mut self, quiet: bool) -> &mut StdErrLog {
        self.quiet = quiet;
        self
    }

    /// Enables or disables the use of timestamps in log messages
    pub fn timestamp(&mut self, timestamp: Timestamp) -> &mut StdErrLog {
        self.timestamp = timestamp;
        self
    }

    /// Enables or disables the use of color in log messages
    pub fn color(&mut self, choice: ColorChoice) -> &mut StdErrLog {
        self.color_choice = choice;
        self
    }

    /// specify a module to allow to log to stderr
    pub fn module<T: Into<String>>(&mut self, module: T) -> &mut StdErrLog {
        self._module(module.into())
    }

    fn _module(&mut self, module: String) -> &mut StdErrLog {
        // If Ok, the module was already found
        if let Err(i) = self.modules.binary_search(&module) {
            // If a super-module of the current module already exists, don't insert this module
            if i == 0 || !is_submodule(&self.modules[i - 1], &module) {
                // Remove any submodules of the module we're inserting
                let submodule_count = self.modules[i..]
                    .iter()
                    .take_while(|possible_submodule|
                        is_submodule(&module, possible_submodule)
                    )
                    .count();
                self.modules.drain(i..i+submodule_count);
                self.modules.insert(i, module);
            }
        }
        self
    }

    /// specifiy modules to allow to log to stderr
    pub fn modules<T: Into<String>, I: IntoIterator<Item = T>>(&mut self,
                                                               modules: I)
                                                               -> &mut StdErrLog {
        for module in modules {
            self.module(module);
        }
        self
    }

    fn log_level_filter(&self) -> LogLevelFilter {
        if self.quiet {
            LogLevelFilter::Off
        } else {
            self.verbosity
        }
    }

    fn includes_module(&self, module_path: &str) -> bool {
        // If modules is empty, include all module paths
        if self.modules.is_empty() {
            return true;
        }
        // if a prefix of module_path is in `self.modules`, it must
        // be located at the first location before
        // where module_path would be.
        match self.modules.binary_search_by(|module| module.as_str().cmp(&module_path)) {
            Ok(_) => {
                // Found exact module: return true
                true
            }
            Err(0) => {
                // if there's no item which would be located before module_path, no prefix is there
                false
            }
            Err(i) => {
                is_submodule(&self.modules[i - 1], module_path)
            }
        }
    }

    /// sets the the logger as active
    pub fn init(&self) -> Result<(), log::SetLoggerError> {
        log::set_logger(|max_log_level| {
                            max_log_level.set(self.log_level_filter());

                            Box::new(self.clone())
                        })
    }
}

impl Default for StdErrLog {
    fn default() -> Self {
        StdErrLog::new()
    }
}

/// creates a new stderr logger
pub fn new() -> StdErrLog {
    StdErrLog::new()
}

fn is_submodule(parent: &str, possible_child: &str) -> bool {
    // Treat as bytes, because we'll be doing slicing, and we only care about ':' chars
    let parent = parent.as_bytes();
    let possible_child = possible_child.as_bytes();

    // a longer module path cannot be a parent of a shorter module path
    if parent.len() > possible_child.len() {
        return false;
    }

    // If the path up to the parent isn't the same as the child,
    if parent != &possible_child[..parent.len()] {
        return false;
    }

    // Either the path is exactly the same, or the sub module should have a "::" after
    // the length of the parent path. This prevents things like 'a::bad' being considered
    // a submodule of 'a::b'
    parent.len() == possible_child.len() ||
        possible_child.get(parent.len()..parent.len() + 2) == Some(b"::")
}

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

    #[test]
    fn submodule() {
        assert!(is_submodule("a", "a::b::c::d"));
        assert!(is_submodule("a::b::c", "a::b::c::d"));
        assert!(is_submodule("a::b::c", "a::b::c"));
        assert!(!is_submodule("a::b::c", "a::bad::c"));
        assert!(!is_submodule("a::b::c", "a::b::cab"));
        assert!(!is_submodule("a::b::c", "a::b::cab::d"));
        assert!(!is_submodule("a::b::c", "a::b"));
        assert!(!is_submodule("a::b::c", "a::bad"));
    }

    #[test]
    fn test_default_level() {
        extern crate log;

        super::new().module(module_path!()).init().unwrap();

        assert_eq!(log::LogLevel::Error, log::max_log_level())
    }
}
<commit_msg>add information about compat with log<commit_after>// Copyright 2016 Doug Goldstein
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A simple logger to provide symantics similar to what is expected
//! of most UNIX utilities by logging to stderr and the higher the
//! verbosity the higher the log level. Additionally it supports the
//! ability to provide timestamps at different granularities.
//!
//! ## Simple Use Case
//!
//! ```rust
//! #[macro_use]
//! extern crate log;
//! extern crate stderrlog;
//!
//! fn main() {
//!     stderrlog::new().module(module_path!()).init().unwrap();
//!
//!     info!("starting up");
//!
//!     // ...
//! }
//! ```
//!
//! ## docopt Example
//!
//! ```rust
//! extern crate docopt;
//! #[macro_use]
//! extern crate log;
//! extern crate rustc_serialize;
//! extern crate stderrlog;
//!
//! use docopt::Docopt;
//!
//! const USAGE: &'static str = "
//! Usage: program [-q] [-v...]
//! ";
//!
//! #[derive(Debug, RustcDecodable)]
//! struct Args {
//!     flag_q: bool,
//!     flag_v: usize,
//! }
//!
//! fn main() {
//!     let args: Args = Docopt::new(USAGE)
//!                             .and_then(|d| d.decode())
//!                             .unwrap_or_else(|e| e.exit());
//!
//!     stderrlog::new()
//!             .module(module_path!())
//!             .quiet(args.flag_q)
//!             .timestamp(stderrlog::Timestamp::Second)
//!             .verbosity(args.flag_v)
//!             .init()
//!             .unwrap();
//!     trace!("trace message");
//!     debug!("debug message");
//!     info!("info message");
//!     warn!("warn message");
//!     error!("error message");
//!
//!     // ...
//! }
//! ```
//!
//! # clap Example
//!
//! ```
//! #[macro_use]
//! extern crate clap;
//! #[macro_use]
//! extern crate log;
//! extern crate stderrlog;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let m = App::new("stderrlog example")
//!         .version(crate_version!())
//!         .arg(Arg::with_name("verbosity")
//!              .short("v")
//!              .multiple(true)
//!              .help("Increase message verbosity"))
//!         .arg(Arg::with_name("quiet")
//!              .short("q")
//!              .help("Silence all output"))
//!         .arg(Arg::with_name("timestamp")
//!              .short("t")
//!              .help("prepend log lines with a timestamp")
//!              .takes_value(true)
//!              .possible_values(&["none", "sec", "ms", "ns"]))
//!         .get_matches();
//!
//!     let verbose = m.occurrences_of("verbosity") as usize;
//!     let quiet = m.is_present("quiet");
//!     let ts = match m.value_of("timestamp") {
//!         Some("ns") => stderrlog::Timestamp::Nanosecond,
//!         Some("ms") => stderrlog::Timestamp::Microsecond,
//!         Some("sec") => stderrlog::Timestamp::Second,
//!         Some("none") | None => stderrlog::Timestamp::Off,
//!         Some(_) => clap::Error {
//!             message: "invalid value for 'timestamp'".into(),
//!             kind: clap::ErrorKind::InvalidValue,
//!             info: None,
//!         }.exit(),
//!     };
//!
//!     stderrlog::new()
//!         .module(module_path!())
//!         .quiet(quiet)
//!         .verbosity(verbose)
//!         .timestamp(ts)
//!         .init()
//!         .unwrap();
//!     trace!("trace message");
//!     debug!("debug message");
//!     info!("info message");
//!     warn!("warn message");
//!     error!("error message");
//! }
//! ```
//! ### `log` Compatibility
//!
//! The 0.3.x versions of `stderrlog` aim to provide compatibility with
//! applications using `log` 0.3.x
//!
//! ### Rust Compatibility
//!
//! `stderrlog` is serious about backwards compat. `stderrlog`
//! pins the minimum required version of Rust in the CI build.
//! Bumping the minimum version of Rust is a minor breaking
//! change and requires a minor version to be bumped.
//!
//! The minimum supported Rust version for this release is 1.16.0.
//!
//! ### Module Level Logging
//!
//! `stderrlog` has the ability to limit the components which can log.
//! Many crates use [log](https://docs.rs/log/*/log/) but you may not
//! want their output in your application. For example
//! [hyper](https://docs.rs/hyper/*/hyper/) makes heavy use of log but
//! when your application receives `-vvvvv` to enable the `trace!()`
//! messages you don't want the output of `hyper`'s `trace!()` level.
//!
//! To support this `stderrlog` includes a `module()` method allowing
//! you to specify the modules that are allowed to log. The examples
//! above use the `module_path!()` macro to enable logging only for
//! the binary itself but none of its dependencies. To enable logging
//! from extra crates just add another call to `module()` with the
//! name of the crate. To enable logging for only a module within
//! that crate specifiy `crate::module` to `module()`. crates and
//! modules will be named the same way would would include them in
//! source code with `use` (e.g. `some-crate` would be `some_crate`).
//!
//! For a good example of how the module level logging works see the
//! large-example project under examples, you'll want to run the
//! following binaries to see all the examples:
//! - cargo run --bin large-example --
//! - cargo run --bin another --
//! - cargo run --bin yet --

extern crate chrono;
extern crate log;
extern crate termcolor;
extern crate thread_local;

use chrono::Local;
use log::{LogLevel, LogLevelFilter, LogMetadata};
use std::cell::RefCell;
use std::io::{self, Write};
use std::fmt;
use termcolor::{Color, ColorSpec, StandardStream, WriteColor};
use thread_local::CachedThreadLocal;

pub use termcolor::ColorChoice;

/// State of the timestampping in the logger.
#[derive(Clone, Copy, Debug)]
pub enum Timestamp {
    /// Disable timestamping of log messages
    Off,
    /// Timestamp with second granularity
    Second,
    /// Timestamp with microsecond granularity
    Microsecond,
    /// Timestamp with nanosecond granularity
    Nanosecond,
}

/// Data specific to this logger
pub struct StdErrLog {
    verbosity: LogLevelFilter,
    quiet: bool,
    timestamp: Timestamp,
    modules: Vec<String>,
    writer: CachedThreadLocal<RefCell<io::LineWriter<StandardStream>>>,
    color_choice: ColorChoice,
}

impl fmt::Debug for StdErrLog {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("StdErrLog")
            .field("verbosity", &self.verbosity)
            .field("quiet", &self.quiet)
            .field("timestamp", &self.timestamp)
            .field("modules", &self.modules)
            .field("writer", &"stderr")
            .field("color_choice", &self.color_choice)
            .finish()
    }
}

impl Clone for StdErrLog {
    fn clone(&self) -> StdErrLog {
        StdErrLog {
            modules: self.modules.clone(),
            writer: CachedThreadLocal::new(),
            .. *self
        }
    }
}

impl log::Log for StdErrLog {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.log_level_filter() && self.includes_module(metadata.target())
    }

    fn log(&self, record: &log::LogRecord) {

        // if logging isn't enabled for this level do a quick out
        if !self.enabled(record.metadata()) {
            return;
        }

        let writer =
            self.writer.get_or(|| Box::new(RefCell::new(io::LineWriter::new(StandardStream::stderr(self.color_choice)))));
        let mut writer = writer.borrow_mut();
        let color = match record.metadata().level() {
            LogLevel::Error => Color::Red,
            LogLevel::Warn => Color::Magenta,
            LogLevel::Info => Color::Yellow,
            LogLevel::Debug => Color::Cyan,
            LogLevel::Trace => Color::Blue,
        };
        {
            writer.get_mut().set_color(ColorSpec::new().set_fg(Some(color))).expect("failed to set color");
        }
        match self.timestamp {
            Timestamp::Second => {
                let fmt = "%Y-%m-%dT%H:%M:%S%:z";
                let _ = write!(writer, "{} - ", Local::now().format(fmt));
            },
            Timestamp::Microsecond => {
                let fmt = "%Y-%m-%dT%H:%M:%S%.6f%:z";
                let _ = write!(writer, "{} - ", Local::now().format(fmt));
            },
            Timestamp::Nanosecond => {
                let fmt = "%Y-%m-%dT%H:%M:%S%.9f%:z";
                let _ = write!(writer, "{} - ", Local::now().format(fmt));
            },
            Timestamp::Off => {},
        }
        let _ = writeln!(writer, "{} - {}", record.level(), record.args());
        {
            writer.get_mut().reset().expect("failed to reset the color");
        }
    }
}

impl StdErrLog {
    /// creates a new stderr logger
    pub fn new() -> StdErrLog {
        StdErrLog {
            verbosity: LogLevelFilter::Error,
            quiet: false,
            timestamp: Timestamp::Off,
            modules: Vec::new(),
            writer: CachedThreadLocal::new(),
            color_choice: ColorChoice::Auto,
        }
    }

    /// Sets the verbosity level of messages that will be displayed
    pub fn verbosity(&mut self, verbosity: usize) -> &mut StdErrLog {
        let log_lvl = match verbosity {
            0 => LogLevelFilter::Error,
            1 => LogLevelFilter::Warn,
            2 => LogLevelFilter::Info,
            3 => LogLevelFilter::Debug,
            _ => LogLevelFilter::Trace,
        };

        self.verbosity = log_lvl;
        self
    }

    /// silence all output, no matter the value of verbosity
    pub fn quiet(&mut self, quiet: bool) -> &mut StdErrLog {
        self.quiet = quiet;
        self
    }

    /// Enables or disables the use of timestamps in log messages
    pub fn timestamp(&mut self, timestamp: Timestamp) -> &mut StdErrLog {
        self.timestamp = timestamp;
        self
    }

    /// Enables or disables the use of color in log messages
    pub fn color(&mut self, choice: ColorChoice) -> &mut StdErrLog {
        self.color_choice = choice;
        self
    }

    /// specify a module to allow to log to stderr
    pub fn module<T: Into<String>>(&mut self, module: T) -> &mut StdErrLog {
        self._module(module.into())
    }

    fn _module(&mut self, module: String) -> &mut StdErrLog {
        // If Ok, the module was already found
        if let Err(i) = self.modules.binary_search(&module) {
            // If a super-module of the current module already exists, don't insert this module
            if i == 0 || !is_submodule(&self.modules[i - 1], &module) {
                // Remove any submodules of the module we're inserting
                let submodule_count = self.modules[i..]
                    .iter()
                    .take_while(|possible_submodule|
                        is_submodule(&module, possible_submodule)
                    )
                    .count();
                self.modules.drain(i..i+submodule_count);
                self.modules.insert(i, module);
            }
        }
        self
    }

    /// specifiy modules to allow to log to stderr
    pub fn modules<T: Into<String>, I: IntoIterator<Item = T>>(&mut self,
                                                               modules: I)
                                                               -> &mut StdErrLog {
        for module in modules {
            self.module(module);
        }
        self
    }

    fn log_level_filter(&self) -> LogLevelFilter {
        if self.quiet {
            LogLevelFilter::Off
        } else {
            self.verbosity
        }
    }

    fn includes_module(&self, module_path: &str) -> bool {
        // If modules is empty, include all module paths
        if self.modules.is_empty() {
            return true;
        }
        // if a prefix of module_path is in `self.modules`, it must
        // be located at the first location before
        // where module_path would be.
        match self.modules.binary_search_by(|module| module.as_str().cmp(&module_path)) {
            Ok(_) => {
                // Found exact module: return true
                true
            }
            Err(0) => {
                // if there's no item which would be located before module_path, no prefix is there
                false
            }
            Err(i) => {
                is_submodule(&self.modules[i - 1], module_path)
            }
        }
    }

    /// sets the the logger as active
    pub fn init(&self) -> Result<(), log::SetLoggerError> {
        log::set_logger(|max_log_level| {
                            max_log_level.set(self.log_level_filter());

                            Box::new(self.clone())
                        })
    }
}

impl Default for StdErrLog {
    fn default() -> Self {
        StdErrLog::new()
    }
}

/// creates a new stderr logger
pub fn new() -> StdErrLog {
    StdErrLog::new()
}

fn is_submodule(parent: &str, possible_child: &str) -> bool {
    // Treat as bytes, because we'll be doing slicing, and we only care about ':' chars
    let parent = parent.as_bytes();
    let possible_child = possible_child.as_bytes();

    // a longer module path cannot be a parent of a shorter module path
    if parent.len() > possible_child.len() {
        return false;
    }

    // If the path up to the parent isn't the same as the child,
    if parent != &possible_child[..parent.len()] {
        return false;
    }

    // Either the path is exactly the same, or the sub module should have a "::" after
    // the length of the parent path. This prevents things like 'a::bad' being considered
    // a submodule of 'a::b'
    parent.len() == possible_child.len() ||
        possible_child.get(parent.len()..parent.len() + 2) == Some(b"::")
}

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

    #[test]
    fn submodule() {
        assert!(is_submodule("a", "a::b::c::d"));
        assert!(is_submodule("a::b::c", "a::b::c::d"));
        assert!(is_submodule("a::b::c", "a::b::c"));
        assert!(!is_submodule("a::b::c", "a::bad::c"));
        assert!(!is_submodule("a::b::c", "a::b::cab"));
        assert!(!is_submodule("a::b::c", "a::b::cab::d"));
        assert!(!is_submodule("a::b::c", "a::b"));
        assert!(!is_submodule("a::b::c", "a::bad"));
    }

    #[test]
    fn test_default_level() {
        extern crate log;

        super::new().module(module_path!()).init().unwrap();

        assert_eq!(log::LogLevel::Error, log::max_log_level())
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![doc(html_root_url = "https://dabo.guru/rust/throw/throw/")]
//! Throw!
//! ------
//!
//! Throw is a new experimental rust error handling library, meant to assist and build on existing
//! error handling systems.
//!
//! Throw exports two structs, `throw::ErrorPoint` and `throw::Error`. `throw::Error` stores a
//! single `original_error` variable which it is created from, and then a list of `ErrorPoint`s
//! which starts out with the original point of creation with `throw!()`, and is added to every
//! time you propagate the error upwards with `up!()`.
//!
//! *Throw does not replace existing error handling systems*. The `throw::Error` type has a type
//! parameter `E` which represents an internal error type stored. `throw::Error` just wraps your
//! error type and stores ErrorPoints alongside it.
//!
//! Throw helps you better keep track of your errors. Instead of seeing a generic "No such file or
//! directory" message, you get a stack trace of functions which propagated the error as well.
//!
//! Instead of:
//!
//! ```text
//! IO Error: failed to lookup address information: Name or service not known
//! ```
//!
//! Get:
//!
//! ```text
//! Error: IO Error: failed to lookup address information: Name or service not known
//!     at 79:17 in zaldinar::startup (src/startup.rs)
//!     at 104:4 in zaldinar::startup (src/startup.rs)
//!     at 28:17 in zaldinar_irclib (/home/daboross/Projects/Rust/zaldinar/zaldinar-irclib/src/lib.rs)
//! ```
//!
//! ---
//!
//! Using throw!
//! ---
//!
//! The main way you use throw is through two macros, `throw!()` and `up!()`. `throw!()` is used
//! when you have a regular (non-throw) result coming from some library function that you want to
//! propagate upwards in case of an error. `up!()` is used when you have an error which was
//! created using `throw!()` in a sub-function which you want to add an error point to and
//! propagate upwards.
//!
//! Here's an example of throw in action:
//!
//! ```rust
//! #[macro_use]
//! extern crate throw;
//!
//! use std::io::prelude::*;
//! use std::io;
//! use std::fs::File;
//!
//! fn read_log() -> Result<String, throw::Error<io::Error>> {
//!     let mut file = throw!(File::open("some_file.log"));
//!     let mut buf = String::new();
//!     throw!(file.read_to_string(&mut buf));
//!     Ok((buf))
//! }
//!
//! fn do_things() -> Result<(), throw::Error<io::Error>> {
//!     let log_contents = up!(read_log());
//!     println!("Log contents: {}", log_contents);
//!
//!     Ok(())
//! }
//!
//! fn main() {
//!     let result = do_things();
//!     if let Err(e) = result {
//! #       /*
//!         panic!("{}", e);
//! #       */
//! #       let err = e.to_string();
//! #       assert!(err.starts_with("Error: No such file or directory (os error 2)\
//! #       \n\tat 16:23 in rust_out (") && err.find(")\n\tat 9:19 in rust_out (").is_some());
//!     }
//! }
//! ```
//!
//! This simple program behaves exactly as if `Result<_, io::Error>` directly when it functions
//! correctly. When the program encounters is when throw really shines.  This will result in an
//! error message:
//!
//! ```text
//! Error: No such file or directory (os error 2)
//!    at 16:23 in main (src/main.rs)
//!    at 9:19 in main (src/main.rs)
//! ```
//!
//! These stack traces are stored inside throw::Error, and are recorded automatically when
//! `throw!()` or `up!()` returns an Err value.
//!
//! In each `at` line, the `16:23` represents `line_num:column_num`, the `main` represents the
//! module path (for example `my_program::sub_module`), and `src/main.rs` represents the path of
//! the file in which `throw!()` was used in.
//!
//! ---
//!
//! Throwing directly from a function is also supported, using `throw_new!()`:
//!
//! ```
//! # #[macro_use]
//! # extern crate throw;
//! fn possibly_fails() -> Result<(), throw::Error<&'static str>> {
//!     if true {
//!         // throw_new!() will always return directly
//!         throw_new!("oops");
//!     }
//!
//!     Ok(())
//! }
//!
//! fn main() {
//! #   /*
//!     possibly_fails().unwrap()
//! #   */
//! #   assert!(possibly_fails().unwrap_err().to_string().starts_with("Error: oops\
//! #   \n\tat 6:8 in rust_out ("))
//! }
//! ```
//!
//! ```text
//! called `Result::unwrap()` on an `Err` value: Error: "oops"
//!    at 6:8 in main (src/main.rs)
//! ```
//!
//! `throw_new!()` differs from `throw!()` in that it takes a parameter directly to pass to a
//! `throw::Error`, rather than a `Result<>` to match on. `throw_new!()` will always return
//! directly from the function.

use std::fmt;

/// Result alias for a result containing a throw::Error.
pub type Result<T, E> = std::result::Result<T, Error<E>>;

/// Represents a location at which an error was thrown via throw!()
pub struct ErrorPoint {
    line: u32,
    column: u32,
    module_path: &'static str,
    file: &'static str,
}

impl ErrorPoint {
    /// The line throw!() occurred at, retrieved by line!()
    #[inline]
    pub fn line(&self) -> u32 {
        self.line
    }

    /// The column throw!() occurred at, retrieved by column!()
    #[inline]
    pub fn column(&self) -> u32 {
        self.column
    }

    /// The module throw!() occurred in, retrieved by module_path!()
    #[inline]
    pub fn module_path(&self) -> &'static str {
        self.module_path
    }

    /// The file throw!() occurred in, retrieved by file!()
    #[inline]
    pub fn file(&self) -> &'static str {
        self.file
    }

    #[doc(hidden)]
    pub fn __construct(line: u32,
                       column: u32,
                       module_path: &'static str,
                       file: &'static str)
                       -> ErrorPoint {
        ErrorPoint {
            line: line,
            column: column,
            module_path: module_path,
            file: file,
        }
    }
}

/// Represents an error. Stores an original error of type E, and any number of ErrorPoints at
/// which the error was propagated.
pub struct Error<E> {
    points: Vec<ErrorPoint>,
    err: E,
}

impl<E> Error<E> {
    /// Creates a new Error with no ErrorPoints
    pub fn new(err: E) -> Error<E> {
        Error {
            points: Vec::new(),
            err: err,
        }
    }

    /// For macro use only
    #[doc(hidden)]
    pub fn __push_point(&mut self, point: ErrorPoint) {
        self.points.push(point);
    }

    /// Gets all ErrorPoints where this Error was thrown. These are in reverse order, with the
    /// first time it was thrown first and the latest time it was thrown last.
    #[inline]
    pub fn points(&self) -> &[ErrorPoint] {
        &self.points
    }

    /// Gets the original error which this Error was constructed with.
    #[deprecated="use `err` instead."]
    #[inline]
    pub fn original_error(&self) -> &E {
        self.err()
    }

    /// Gets the original error which this Error was constructed with.
    #[inline]
    pub fn err(&self) -> &E {
        &self.err
    }

    /// Move the original error out.
    #[deprecated="use `into_err` instead."]
    #[inline]
    pub fn into_origin(self) -> E {
        self.into_err()
    }

    /// transform the inner err to expected err.
    #[inline]
    pub fn into_err<N>(self) -> N
        where E: Into<N>
    {
        self.err.into()
    }

    /// Transforms this Error<OldError> into Error<NewError>. This isn't implemented as an Into or
    /// From implementation because it would conflict with the blanket implementations in stdlib.
    pub fn transform<NE>(self) -> Error<NE>
        where E: Into<NE>
    {
        Error {
            points: self.points,
            err: self.err.into(),
        }
    }
}

impl<E> fmt::Display for Error<E>
    where E: fmt::Display
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
        try!(write!(fmt, "Error: {}", self.err));
        for point in self.points.iter().rev() {
            try!(write!(fmt,
                        "\n\tat {}:{} in {} ({})",
                        point.line(),
                        point.column(),
                        point.module_path(),
                        point.file()));
        }

        Ok(())
    }
}

impl<E> fmt::Debug for Error<E>
    where E: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
        try!(write!(fmt, "Error: {:?}", self.err));
        for point in self.points.iter().rev() {
            try!(write!(fmt,
                        "\n\tat {}:{} in {} ({})",
                        point.line(),
                        point.column(),
                        point.module_path(),
                        point.file()));
        }

        Ok(())
    }
}

#[macro_export]
macro_rules! up {
    ($e:expr) => (
        match $e {
            Ok(v) => v,
            Err(e) => {
                // re-assignment for a better error message if up!() is used incorrectly
                return as_err!(e.transform());
            },
        }
    );
}

#[macro_export]
macro_rules! as_err {
    ($e:expr) => ({
        let mut e = $e;
        e.__push_point($crate::ErrorPoint::__construct(
            line!(),
            column!(),
            module_path!(),
            file!(),
        ));
        Err(e)
    })
}

#[macro_export]
macro_rules! throw {
    ($e:expr) => (
        match $e {
            Ok(v) => v,
            Err(e) => throw_new!(e),
        }
    );
}

#[macro_export]
macro_rules! throw_new {
    ($e:expr) => ({
        return as_err!($crate::Error::new($e.into()));
    })
}
<commit_msg>Fix overly specific error message tests which are prone to break between rust versions.<commit_after>#![deny(missing_docs)]
#![doc(html_root_url = "https://dabo.guru/rust/throw/throw/")]
//! Throw!
//! ------
//!
//! Throw is a new experimental rust error handling library, meant to assist and build on existing
//! error handling systems.
//!
//! Throw exports two structs, `throw::ErrorPoint` and `throw::Error`. `throw::Error` stores a
//! single `original_error` variable which it is created from, and then a list of `ErrorPoint`s
//! which starts out with the original point of creation with `throw!()`, and is added to every
//! time you propagate the error upwards with `up!()`.
//!
//! *Throw does not replace existing error handling systems*. The `throw::Error` type has a type
//! parameter `E` which represents an internal error type stored. `throw::Error` just wraps your
//! error type and stores ErrorPoints alongside it.
//!
//! Throw helps you better keep track of your errors. Instead of seeing a generic "No such file or
//! directory" message, you get a stack trace of functions which propagated the error as well.
//!
//! Instead of:
//!
//! ```text
//! IO Error: failed to lookup address information: Name or service not known
//! ```
//!
//! Get:
//!
//! ```text
//! Error: IO Error: failed to lookup address information: Name or service not known
//!     at 79:17 in zaldinar::startup (src/startup.rs)
//!     at 104:4 in zaldinar::startup (src/startup.rs)
//!     at 28:17 in zaldinar_irclib (/home/daboross/Projects/Rust/zaldinar/zaldinar-irclib/src/lib.rs)
//! ```
//!
//! ---
//!
//! Using throw!
//! ---
//!
//! The main way you use throw is through two macros, `throw!()` and `up!()`. `throw!()` is used
//! when you have a regular (non-throw) result coming from some library function that you want to
//! propagate upwards in case of an error. `up!()` is used when you have an error which was
//! created using `throw!()` in a sub-function which you want to add an error point to and
//! propagate upwards.
//!
//! Here's an example of throw in action:
//!
//! ```rust
//! #[macro_use]
//! extern crate throw;
//!
//! use std::io::prelude::*;
//! use std::io;
//! use std::fs::File;
//!
//! fn read_log() -> Result<String, throw::Error<io::Error>> {
//!     let mut file = throw!(File::open("some_file.log"));
//!     let mut buf = String::new();
//!     throw!(file.read_to_string(&mut buf));
//!     Ok((buf))
//! }
//!
//! fn do_things() -> Result<(), throw::Error<io::Error>> {
//!     let log_contents = up!(read_log());
//!     println!("Log contents: {}", log_contents);
//!
//!     Ok(())
//! }
//!
//! fn main() {
//!     let result = do_things();
//!     if let Err(e) = result {
//! #       /*
//!         panic!("{}", e);
//! #       */
//! #       let err = e.to_string();
//! #       assert!(err.starts_with("Error: No such file or directory (os error 2)\
//! #       \n\tat "), "mangled error message: {}", err);
//!     }
//! }
//! ```
//!
//! This simple program behaves exactly as if `Result<_, io::Error>` directly when it functions
//! correctly. When the program encounters is when throw really shines.  This will result in an
//! error message:
//!
//! ```text
//! Error: No such file or directory (os error 2)
//!    at 16:23 in main (src/main.rs)
//!    at 9:19 in main (src/main.rs)
//! ```
//!
//! These stack traces are stored inside throw::Error, and are recorded automatically when
//! `throw!()` or `up!()` returns an Err value.
//!
//! In each `at` line, the `16:23` represents `line_num:column_num`, the `main` represents the
//! module path (for example `my_program::sub_module`), and `src/main.rs` represents the path of
//! the file in which `throw!()` was used in.
//!
//! ---
//!
//! Throwing directly from a function is also supported, using `throw_new!()`:
//!
//! ```
//! # #[macro_use]
//! # extern crate throw;
//! fn possibly_fails() -> Result<(), throw::Error<&'static str>> {
//!     if true {
//!         // throw_new!() will always return directly
//!         throw_new!("oops");
//!     }
//!
//!     Ok(())
//! }
//!
//! fn main() {
//! #   /*
//!     possibly_fails().unwrap()
//! #   */
//! #   let err = possibly_fails().unwrap_err().to_string();
//! #   assert!(err.starts_with("Error: oops\n\tat "), "mangled error message: {}",  err);
//! }
//! ```
//!
//! ```text
//! called `Result::unwrap()` on an `Err` value: Error: "oops"
//!    at 6:8 in main (src/main.rs)
//! ```
//!
//! `throw_new!()` differs from `throw!()` in that it takes a parameter directly to pass to a
//! `throw::Error`, rather than a `Result<>` to match on. `throw_new!()` will always return
//! directly from the function.

use std::fmt;

/// Result alias for a result containing a throw::Error.
pub type Result<T, E> = std::result::Result<T, Error<E>>;

/// Represents a location at which an error was thrown via throw!()
pub struct ErrorPoint {
    line: u32,
    column: u32,
    module_path: &'static str,
    file: &'static str,
}

impl ErrorPoint {
    /// The line throw!() occurred at, retrieved by line!()
    #[inline]
    pub fn line(&self) -> u32 {
        self.line
    }

    /// The column throw!() occurred at, retrieved by column!()
    #[inline]
    pub fn column(&self) -> u32 {
        self.column
    }

    /// The module throw!() occurred in, retrieved by module_path!()
    #[inline]
    pub fn module_path(&self) -> &'static str {
        self.module_path
    }

    /// The file throw!() occurred in, retrieved by file!()
    #[inline]
    pub fn file(&self) -> &'static str {
        self.file
    }

    #[doc(hidden)]
    pub fn __construct(line: u32,
                       column: u32,
                       module_path: &'static str,
                       file: &'static str)
                       -> ErrorPoint {
        ErrorPoint {
            line: line,
            column: column,
            module_path: module_path,
            file: file,
        }
    }
}

/// Represents an error. Stores an original error of type E, and any number of ErrorPoints at
/// which the error was propagated.
pub struct Error<E> {
    points: Vec<ErrorPoint>,
    err: E,
}

impl<E> Error<E> {
    /// Creates a new Error with no ErrorPoints
    pub fn new(err: E) -> Error<E> {
        Error {
            points: Vec::new(),
            err: err,
        }
    }

    /// For macro use only
    #[doc(hidden)]
    pub fn __push_point(&mut self, point: ErrorPoint) {
        self.points.push(point);
    }

    /// Gets all ErrorPoints where this Error was thrown. These are in reverse order, with the
    /// first time it was thrown first and the latest time it was thrown last.
    #[inline]
    pub fn points(&self) -> &[ErrorPoint] {
        &self.points
    }

    /// Gets the original error which this Error was constructed with.
    #[deprecated="use `err` instead."]
    #[inline]
    pub fn original_error(&self) -> &E {
        self.err()
    }

    /// Gets the original error which this Error was constructed with.
    #[inline]
    pub fn err(&self) -> &E {
        &self.err
    }

    /// Move the original error out.
    #[deprecated="use `into_err` instead."]
    #[inline]
    pub fn into_origin(self) -> E {
        self.into_err()
    }

    /// transform the inner err to expected err.
    #[inline]
    pub fn into_err<N>(self) -> N
        where E: Into<N>
    {
        self.err.into()
    }

    /// Transforms this Error<OldError> into Error<NewError>. This isn't implemented as an Into or
    /// From implementation because it would conflict with the blanket implementations in stdlib.
    pub fn transform<NE>(self) -> Error<NE>
        where E: Into<NE>
    {
        Error {
            points: self.points,
            err: self.err.into(),
        }
    }
}

impl<E> fmt::Display for Error<E>
    where E: fmt::Display
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
        try!(write!(fmt, "Error: {}", self.err));
        for point in self.points.iter().rev() {
            try!(write!(fmt,
                        "\n\tat {}:{} in {} ({})",
                        point.line(),
                        point.column(),
                        point.module_path(),
                        point.file()));
        }

        Ok(())
    }
}

impl<E> fmt::Debug for Error<E>
    where E: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
        try!(write!(fmt, "Error: {:?}", self.err));
        for point in self.points.iter().rev() {
            try!(write!(fmt,
                        "\n\tat {}:{} in {} ({})",
                        point.line(),
                        point.column(),
                        point.module_path(),
                        point.file()));
        }

        Ok(())
    }
}

#[macro_export]
macro_rules! up {
    ($e:expr) => (
        match $e {
            Ok(v) => v,
            Err(e) => {
                // re-assignment for a better error message if up!() is used incorrectly
                return as_err!(e.transform());
            },
        }
    );
}

#[macro_export]
macro_rules! as_err {
    ($e:expr) => ({
        let mut e = $e;
        e.__push_point($crate::ErrorPoint::__construct(
            line!(),
            column!(),
            module_path!(),
            file!(),
        ));
        Err(e)
    })
}

#[macro_export]
macro_rules! throw {
    ($e:expr) => (
        match $e {
            Ok(v) => v,
            Err(e) => throw_new!(e),
        }
    );
}

#[macro_export]
macro_rules! throw_new {
    ($e:expr) => ({
        return as_err!($crate::Error::new($e.into()));
    })
}
<|endoftext|>