<commit_before>extern crate dns_lookup;
#[macro_use]
extern crate lazy_static;
extern crate params;
extern crate regex;
extern crate rustc_serialize;
extern crate url;

use params::{Map, Value};
use std::collections::BTreeMap;

mod validators {
    pub mod accepted;
    pub mod active_url;
    pub mod alpha;
    pub mod alpha_dash;
    pub mod alpha_numeric;
    pub mod array;
    pub mod between;
    pub mod boolean;
    pub mod confirmed;
    pub mod different;
    pub mod digits;
    pub mod digits_between;
    pub mod distinct;
    pub mod email;
    pub mod filled;
    pub mod in_const;
    pub mod in_array;
    pub mod integer;
    pub mod ip_address;
    pub mod json;
    pub mod max;
    pub mod min;
    pub mod numeric;
    pub mod present;
    pub mod regex;
    pub mod required;
    pub mod same;
    pub mod size;
    pub mod string;
    pub mod url;
}

#[derive(Debug,Clone)]
pub enum Rule {
    /// The field under validation must be `yes`, `on`, `1`, or `true`.
    /// This is useful for validating "Terms of Service" acceptance.
    ///
    /// On success, will transform the input to a boolean `true`.
    Accepted,
    /// The field under validation, if present, must be an active domain name.
    ActiveUrl,
    /// The field under validation must be entirely alphabetic characters.
    ///
    /// This validator accepts Latin and international (Unicode) input.
    Alpha,
    /// The field under validation may have alpha-numeric characters,
    /// as well as dashes and underscores.
    ///
    /// This validator accepts Latin and international (Unicode) input.
    AlphaDash,
    /// The field under validation must be entirely alpha-numeric characters.
    ///
    /// This validator accepts Latin and international (Unicode) input.
    AlphaNumeric,
    /// The field under validation, if present, must be an array.
    Array,
    /// The field under validation, if present, must have a size between the given min and max.
    /// Strings, numerics, and files are evaluated in the same fashion as the `Size` rule.
    Between(isize, isize),
    /// The field under validation, if present, must be able to be cast as a boolean.
    /// Accepted input are `true`, `false`, `1`, `0`, `"1"`, and `"0"`.
    ///
    /// On success, will transform the input to a boolean `true` or `false`.
    Boolean,
    /// The field under validation must have a matching field of `foo_confirmation`.
    /// For example, if the field under validation is `password`,
    /// a matching `password_confirmation` field must be present in the input.
    Confirmed,
    /// The field under validation must have a different value than `field`.
    Different(&'static str),
    /// The field under validation, if present,
    /// must be numeric and must have an exact length of value.
    ///
    /// For negative numbers, the negative sign is not counted as a digit.
    /// For floating point numbers, the number of digits preceeding the decimal place
    /// is counted.
    ///
    /// On success, will transform string input to a numeric type.
    Digits(usize),
    /// The field under validation, if present, must have a length between the given min and max.
    ///
    /// On success, will transform string input to a numeric type.
    DigitsBetween(usize, usize),
    /// When working with arrays, the field under validation must not have any duplicate values
    /// if it is present.
    Distinct,
    /// The field under validation, if present, must be formatted as an e-mail address.
    Email,
    /// The field under validation must not be empty when it is present.
    Filled,
    /// The field under validation, if present, must be included in the given list of values.
    In(Vec<Value>),
    /// The field under validation, if present, must exist in `anotherfield`'s values.
    InArray(&'static str),
    /// The field under validation, if present, must be an integer.
    ///
    /// On success, will transform string input to a numeric type.
    Integer,
    /// The field under validation, if present, must be an IP address.
    ///
    /// Accepts both IPv4 and IPv6 addresses.
    IpAddress,
    /// The field under validation, if present, must be a valid JSON string.
    Json,
    /// The field under validation, if present, must be less than or equal to a maximum value.
    /// Strings, numerics, and files are evaluated in the same fashion as the `Size` rule.
    Max(isize),
    /// The field under validation, if present, must have a minimum value.
    /// Strings, numerics, and files are evaluated in the same fashion as the `Size` rule.
    Min(isize),
    /// The field under validation must not be included in the given list of values.
    NotIn(Vec<Value>),
    /// The field under validation must not exist in `anotherfield`'s values.
    NotInArray(&'static str),
    /// The field under validation, if present, must be numeric.
    ///
    /// On success, will transform string input to a numeric type.
    Numeric,
    /// The field under validation must be present in the input data but can be empty.
    Present,
    /// The field under validation, if present, must match the given regular expression.
    ///
    /// On success, will transform input to a string.
    Regex(&'static str),
    /// The field under validation must be present in the input data and not empty.
    /// A field is considered "empty" if one of the following conditions are true:
    ///
    /// The value is null.
    ///
    /// The value is an empty string.
    ///
    /// The value is an empty array or empty object.
    Required,
    /// The field under validation must be present if the `anotherfield` field
    /// is equal to any `value`.
    RequiredIf(&'static str, Value),
    /// The field under validation must be present unless the `anotherfield` field
    /// is equal to any `value`.
    RequiredUnless(&'static str, Value),
    /// The field under validation must be present only if
    /// any of the other specified fields are present.
    RequiredWith(Vec<&'static str>),
    /// The field under validation must be present only if
    /// all of the other specified fields are present.
    RequiredWithAll(Vec<&'static str>),
    /// The field under validation must be present only when
    /// any of the other specified fields are not present.
    RequiredWithout(Vec<&'static str>),
    /// The field under validation must be present only when
    /// all of the other specified fields are not present.
    RequiredWithoutAll(Vec<&'static str>),
    /// The given field must match the field under validation.
    Same(&'static str),
    /// The field under validation must have a size matching the given value.
    ///
    /// For string data, value corresponds to the number of characters.
    ///
    /// For numeric data, value corresponds to a given integer value.
    ///
    /// For files, size corresponds to the file size in kilobytes.
    Size(isize),
    /// The field under validation, if present, must be a string.
    String,
    /// The field under validation, if present, must be formatted as a valid URL,
    /// but does not need to resolve to a real website. The URL must contain the scheme
    /// or else it will fail validation. For example, `http://google.com` will
    /// pass validation, but `google.com` will fail validation.
    Url,
}

pub fn validate(rules: BTreeMap<&str, Vec<Rule>>,
                values: Map)
                -> Result<Map, BTreeMap<&str, Vec<String>>> {
    let mut new_values = values;
    let mut errors = BTreeMap::new();

    for (field, ruleset) in &rules {
        let mut current_errors = Vec::new();
        for rule in ruleset {
            let result = match *rule {
                Rule::Accepted => validators::accepted::validate_accepted(&new_values, field),
                Rule::ActiveUrl => validators::active_url::validate_active_url(&new_values, field),
                Rule::Alpha => validators::alpha::validate_alpha(&new_values, field),
                Rule::AlphaDash => validators::alpha_dash::validate_alpha_dash(&new_values, field),
                Rule::AlphaNumeric => {
                    validators::alpha_numeric::validate_alpha_numeric(&new_values, field)
                }
                Rule::Array => validators::array::validate_array(&new_values, field),
                Rule::Between(min, max) => {
                    validators::between::validate_between(&new_values, field, min, max)
                }
                Rule::Boolean => validators::boolean::validate_boolean(&new_values, field),
                Rule::Confirmed => validators::confirmed::validate_confirmed(&new_values, field),
                Rule::Different(ref other) => {
                    validators::different::validate_different(&new_values, field, other)
                }
                Rule::Digits(digits) => {
                    validators::digits::validate_digits(&new_values, field, digits)
                }
                Rule::DigitsBetween(min, max) => {
                    validators::digits_between::validate_digits_between(&new_values,
                                                                        field,
                                                                        min,
                                                                        max)
                }
                Rule::Distinct => validators::distinct::validate_distinct(&new_values, field),
                Rule::Email => validators::email::validate_email(&new_values, field),
                Rule::Filled => validators::filled::validate_filled(&new_values, field),
                Rule::In(ref options) => {
                    validators::in_const::validate_in(&new_values, field, options)
                }
                Rule::InArray(ref other) => {
                    validators::in_array::validate_in_array(&new_values, field, other)
                }
                Rule::Integer => validators::integer::validate_integer(&new_values, field),
                Rule::IpAddress => validators::ip_address::validate_ip_address(&new_values, field),
                Rule::Json => validators::json::validate_json(&new_values, field),
                Rule::Max(target) => validators::max::validate_max(&new_values, field, target),
                Rule::Min(target) => validators::min::validate_min(&new_values, field, target),
                Rule::Numeric => validators::numeric::validate_numeric(&new_values, field),
                Rule::Present => validators::present::validate_present(&new_values, field),
                Rule::Regex(ref pattern) => {
                    validators::regex::validate_regex(&new_values, field, pattern)
                }
                Rule::Required => validators::required::validate_required(&new_values, field),
                Rule::Same(ref other) => validators::same::validate_same(&new_values, field, other),
                Rule::Size(target) => validators::size::validate_size(&new_values, field, target),
                Rule::String => validators::string::validate_string(&new_values, field),
                Rule::Url => validators::url::validate_url(&new_values, field),
                _ => {
                    panic!(format!("Unrecognized validation rule {:?} for field {:?}",
                                   rule,
                                   field));
                }
            };
            match result {
                Ok(Some(res)) => {
                    new_values.assign(field, res).ok();
                }
                Ok(None) => (),
                Err(err) => {
                    current_errors.push(err);
                }
            };
        }
        if !current_errors.is_empty() {
            errors.insert(*field, current_errors);
        }
    }

    if errors.is_empty() {
        Ok(new_values)
    } else {
        Err(errors)
    }
}
<commit_msg>Update validate doc<commit_after>extern crate dns_lookup;
#[macro_use]
extern crate lazy_static;
extern crate params;
extern crate regex;
extern crate rustc_serialize;
extern crate url;

use params::{Map, Value};
use std::collections::BTreeMap;

mod validators {
    pub mod accepted;
    pub mod active_url;
    pub mod alpha;
    pub mod alpha_dash;
    pub mod alpha_numeric;
    pub mod array;
    pub mod between;
    pub mod boolean;
    pub mod confirmed;
    pub mod different;
    pub mod digits;
    pub mod digits_between;
    pub mod distinct;
    pub mod email;
    pub mod filled;
    pub mod in_const;
    pub mod in_array;
    pub mod integer;
    pub mod ip_address;
    pub mod json;
    pub mod max;
    pub mod min;
    pub mod numeric;
    pub mod present;
    pub mod regex;
    pub mod required;
    pub mod same;
    pub mod size;
    pub mod string;
    pub mod url;
}

#[derive(Debug,Clone)]
pub enum Rule {
    /// The field under validation must be `yes`, `on`, `1`, or `true`.
    /// This is useful for validating "Terms of Service" acceptance.
    ///
    /// On success, will transform the input to a boolean `true`.
    Accepted,
    /// The field under validation, if present, must be an active domain name.
    ActiveUrl,
    /// The field under validation must be entirely alphabetic characters.
    ///
    /// This validator accepts Latin and international (Unicode) input.
    Alpha,
    /// The field under validation may have alpha-numeric characters,
    /// as well as dashes and underscores.
    ///
    /// This validator accepts Latin and international (Unicode) input.
    AlphaDash,
    /// The field under validation must be entirely alpha-numeric characters.
    ///
    /// This validator accepts Latin and international (Unicode) input.
    AlphaNumeric,
    /// The field under validation, if present, must be an array.
    Array,
    /// The field under validation, if present, must have a size between the given min and max.
    /// Strings, numerics, and files are evaluated in the same fashion as the `Size` rule.
    Between(isize, isize),
    /// The field under validation, if present, must be able to be cast as a boolean.
    /// Accepted input are `true`, `false`, `1`, `0`, `"1"`, and `"0"`.
    ///
    /// On success, will transform the input to a boolean `true` or `false`.
    Boolean,
    /// The field under validation must have a matching field of `foo_confirmation`.
    /// For example, if the field under validation is `password`,
    /// a matching `password_confirmation` field must be present in the input.
    Confirmed,
    /// The field under validation must have a different value than `field`.
    Different(&'static str),
    /// The field under validation, if present,
    /// must be numeric and must have an exact length of value.
    ///
    /// For negative numbers, the negative sign is not counted as a digit.
    /// For floating point numbers, the number of digits preceeding the decimal place
    /// is counted.
    ///
    /// On success, will transform string input to a numeric type.
    Digits(usize),
    /// The field under validation, if present, must have a length between the given min and max.
    ///
    /// On success, will transform string input to a numeric type.
    DigitsBetween(usize, usize),
    /// When working with arrays, the field under validation must not have any duplicate values
    /// if it is present.
    Distinct,
    /// The field under validation, if present, must be formatted as an e-mail address.
    Email,
    /// The field under validation must not be empty when it is present.
    Filled,
    /// The field under validation, if present, must be included in the given list of values.
    In(Vec<Value>),
    /// The field under validation, if present, must exist in `anotherfield`'s values.
    InArray(&'static str),
    /// The field under validation, if present, must be an integer.
    ///
    /// On success, will transform string input to a numeric type.
    Integer,
    /// The field under validation, if present, must be an IP address.
    ///
    /// Accepts both IPv4 and IPv6 addresses.
    IpAddress,
    /// The field under validation, if present, must be a valid JSON string.
    Json,
    /// The field under validation, if present, must be less than or equal to a maximum value.
    /// Strings, numerics, and files are evaluated in the same fashion as the `Size` rule.
    Max(isize),
    /// The field under validation, if present, must have a minimum value.
    /// Strings, numerics, and files are evaluated in the same fashion as the `Size` rule.
    Min(isize),
    /// The field under validation must not be included in the given list of values.
    NotIn(Vec<Value>),
    /// The field under validation must not exist in `anotherfield`'s values.
    NotInArray(&'static str),
    /// The field under validation, if present, must be numeric.
    ///
    /// On success, will transform string input to a numeric type.
    Numeric,
    /// The field under validation must be present in the input data but can be empty.
    Present,
    /// The field under validation, if present, must match the given regular expression.
    ///
    /// On success, will transform input to a string.
    Regex(&'static str),
    /// The field under validation must be present in the input data and not empty.
    /// A field is considered "empty" if one of the following conditions are true:
    ///
    /// The value is null.
    ///
    /// The value is an empty string.
    ///
    /// The value is an empty array or empty object.
    Required,
    /// The field under validation must be present if the `anotherfield` field
    /// is equal to any `value`.
    RequiredIf(&'static str, Value),
    /// The field under validation must be present unless the `anotherfield` field
    /// is equal to any `value`.
    RequiredUnless(&'static str, Value),
    /// The field under validation must be present only if
    /// any of the other specified fields are present.
    RequiredWith(Vec<&'static str>),
    /// The field under validation must be present only if
    /// all of the other specified fields are present.
    RequiredWithAll(Vec<&'static str>),
    /// The field under validation must be present only when
    /// any of the other specified fields are not present.
    RequiredWithout(Vec<&'static str>),
    /// The field under validation must be present only when
    /// all of the other specified fields are not present.
    RequiredWithoutAll(Vec<&'static str>),
    /// The given field must match the field under validation.
    Same(&'static str),
    /// The field under validation must have a size matching the given value.
    ///
    /// For string data, value corresponds to the number of characters.
    ///
    /// For numeric data, value corresponds to a given integer value.
    ///
    /// For files, size corresponds to the file size in kilobytes.
    Size(isize),
    /// The field under validation, if present, must be a string.
    String,
    /// The field under validation, if present, must be formatted as a valid URL,
    /// but does not need to resolve to a real website. The URL must contain the scheme
    /// or else it will fail validation. For example, `http://google.com` will
    /// pass validation, but `google.com` will fail validation.
    Url,
}

/// Validate a map of `values` against a map of `rules`.
///
/// Returns a `Result` containing a map of post-processed `values`,
/// or a map of validation error messages.
pub fn validate(rules: BTreeMap<&str, Vec<Rule>>,
                values: Map)
                -> Result<Map, BTreeMap<&str, Vec<String>>> {
    let mut new_values = values;
    let mut errors = BTreeMap::new();

    for (field, ruleset) in &rules {
        let mut current_errors = Vec::new();
        for rule in ruleset {
            let result = match *rule {
                Rule::Accepted => validators::accepted::validate_accepted(&new_values, field),
                Rule::ActiveUrl => validators::active_url::validate_active_url(&new_values, field),
                Rule::Alpha => validators::alpha::validate_alpha(&new_values, field),
                Rule::AlphaDash => validators::alpha_dash::validate_alpha_dash(&new_values, field),
                Rule::AlphaNumeric => {
                    validators::alpha_numeric::validate_alpha_numeric(&new_values, field)
                }
                Rule::Array => validators::array::validate_array(&new_values, field),
                Rule::Between(min, max) => {
                    validators::between::validate_between(&new_values, field, min, max)
                }
                Rule::Boolean => validators::boolean::validate_boolean(&new_values, field),
                Rule::Confirmed => validators::confirmed::validate_confirmed(&new_values, field),
                Rule::Different(ref other) => {
                    validators::different::validate_different(&new_values, field, other)
                }
                Rule::Digits(digits) => {
                    validators::digits::validate_digits(&new_values, field, digits)
                }
                Rule::DigitsBetween(min, max) => {
                    validators::digits_between::validate_digits_between(&new_values,
                                                                        field,
                                                                        min,
                                                                        max)
                }
                Rule::Distinct => validators::distinct::validate_distinct(&new_values, field),
                Rule::Email => validators::email::validate_email(&new_values, field),
                Rule::Filled => validators::filled::validate_filled(&new_values, field),
                Rule::In(ref options) => {
                    validators::in_const::validate_in(&new_values, field, options)
                }
                Rule::InArray(ref other) => {
                    validators::in_array::validate_in_array(&new_values, field, other)
                }
                Rule::Integer => validators::integer::validate_integer(&new_values, field),
                Rule::IpAddress => validators::ip_address::validate_ip_address(&new_values, field),
                Rule::Json => validators::json::validate_json(&new_values, field),
                Rule::Max(target) => validators::max::validate_max(&new_values, field, target),
                Rule::Min(target) => validators::min::validate_min(&new_values, field, target),
                Rule::Numeric => validators::numeric::validate_numeric(&new_values, field),
                Rule::Present => validators::present::validate_present(&new_values, field),
                Rule::Regex(ref pattern) => {
                    validators::regex::validate_regex(&new_values, field, pattern)
                }
                Rule::Required => validators::required::validate_required(&new_values, field),
                Rule::Same(ref other) => validators::same::validate_same(&new_values, field, other),
                Rule::Size(target) => validators::size::validate_size(&new_values, field, target),
                Rule::String => validators::string::validate_string(&new_values, field),
                Rule::Url => validators::url::validate_url(&new_values, field),
                _ => {
                    panic!(format!("Unrecognized validation rule {:?} for field {:?}",
                                   rule,
                                   field));
                }
            };
            match result {
                Ok(Some(res)) => {
                    new_values.assign(field, res).ok();
                }
                Ok(None) => (),
                Err(err) => {
                    current_errors.push(err);
                }
            };
        }
        if !current_errors.is_empty() {
            errors.insert(*field, current_errors);
        }
    }

    if errors.is_empty() {
        Ok(new_values)
    } else {
        Err(errors)
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, VecDeque};
use std::iter::Iterator;
use std::u64;
use std::usize;

pub type VertexId = usize;

pub trait Property : Copy + Ord + Eq {}
impl<T> Property for T where T: Copy + Ord + Eq {}

/// Represent a Graph structure
#[derive(Debug)]
pub struct Graph<V: Property, E: Property> {
    pub vertexes: HashMap<VertexId, Vertex<V>>,
    pub edges: HashMap<(VertexId, VertexId), E>,
    adjacency_matrix: Vec<Vec<bool>>,
}

#[derive(Debug)]
pub struct Vertex<V: Property> {
    pub value: V,
    pub neighbors: Vec<VertexId>,
}

pub struct BfsIterator<'a, V: 'a + Property, E: 'a + Property, F> {
    queue: VecDeque<VertexId>,
    graph: &'a Graph<V, E>,
    distances: Vec<u64>,
    parents: Vec<VertexId>,
    predicate: F
}

impl<'a, V: Property, E: Property, F> BfsIterator<'a, V, E, F> {
    fn new(graph: &'a Graph<V, E>, source: VertexId, predicate: F) -> BfsIterator<'a, V, E, F> {
        let mut queue = VecDeque::new();
        queue.push_back(source);
        let mut distances = vec![u64::MAX; graph.n_vertexes()];
        let parents = vec![usize::MAX; graph.n_vertexes()];
        distances[source] = 0;
        BfsIterator {
            graph: graph,
            queue: queue,
            distances: distances,
            parents: parents,
            predicate: predicate
        }
    }
}

/// Iterator for a breadth first search over a graph
/// Returns in order a tuple of (vertex, distance, parent)
impl<'a, V: Property, E: Property, F> Iterator for BfsIterator<'a, V, E, F>
    where F: Fn(V, E, V) -> bool {
    type Item = (VertexId, u64, VertexId);
    fn next(&mut self) -> Option<(VertexId, u64, VertexId)> {
        let g = self.graph;
        match self.queue.pop_front() {
            Some(vertex) => {
                for v in self.graph.adjacent_vertexes(&vertex) {
                    let predicate = &self.predicate;
                    let pred = predicate(g.vertexes[&vertex].value, g.edges[&(vertex, *v)], g.vertexes[v].value);
                    if self.distances[*v] == u64::MAX && pred {
                        self.distances[*v] = self.distances[vertex] + 1;
                        self.parents[*v] = vertex;
                        self.queue.push_back(*v);
                    }
                }
                Some((vertex, self.distances[vertex], self.parents[vertex]))
            }
            _ => None
        }
    }
}

impl<'a, V: Property, E: Property> Graph<V, E> {
    pub fn new(vertex_list: &Vec<(VertexId, V)>, edge_list: &Vec<(VertexId, VertexId, E)>) -> Graph<V, E> {
        let mut vertexes: HashMap<VertexId, Vertex<V>> = HashMap::new();
        for v in vertex_list {
            vertexes.insert(v.0,
                            Vertex {
                                value: v.1,
                                neighbors: Vec::new(),
                            });
        }
        let n_vertexes: usize = vertexes.len();

        let mut adjacency_matrix: Vec<Vec<bool>> = vec![vec![false; n_vertexes]; n_vertexes];
        let mut edges: HashMap<(VertexId, VertexId), E> = HashMap::new();
        for edge in edge_list {
            adjacency_matrix[edge.0][edge.1] = true;
            vertexes.get_mut(&edge.0).unwrap().neighbors.push(edge.1);
            edges.insert((edge.0, edge.1), edge.2);
        }

        Graph {
            vertexes: vertexes,
            edges: edges,
            adjacency_matrix: adjacency_matrix,
        }
    }
    pub fn size(&self) -> (usize, usize) {
        (self.vertexes.len(), self.edges.len())
    }
    pub fn n_vertexes(&self) -> usize {
        self.vertexes.len()
    }
    pub fn n_edges(&self) -> usize {
        self.edges.len()
    }
    pub fn adjacent_vertexes(&self, vertex: &VertexId) -> &Vec<VertexId> {
        &self.vertexes[vertex].neighbors
    }
    pub fn bfs_iter(&self, source: VertexId) -> BfsIterator<V, E, fn(V, E, V) -> bool> {
        BfsIterator::new(self, source, bfs_true_predicate)
    }
    pub fn bfs_iter_predicate<F>(&'a self, source: VertexId, predicate: F) -> BfsIterator<V, E, F>
    where F: Fn(V, E, V) -> bool {
        BfsIterator::new(self, source, predicate)
    }
}

pub trait FlowGraph<V> {}

impl<'a, V: Property> FlowGraph<V> for Graph<V, i64> {}

fn bfs_true_predicate<'a, V: Property, E: Property>(_: V, _: E, _: V) -> bool {
    true
}

fn flow_predicate<'a, V: Property>(_: V, edge: i64, _: V) {
    edge > 0;
}

#[cfg(test)]
mod tests {
    use Graph;
    use VertexId;
    use std::collections::HashSet;
    use std::usize;

    #[test]
    fn test_new_graph() {
        let vertex_list = vec![(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)];
        let edge_list = vec![(0, 1, 5), (0, 2, 2), (2, 3, 3), (4, 3, 1)];
        let g = Graph::new(&vertex_list, &edge_list);
        assert_eq!(g.size(), (5, 4));
        for k in 0..5 {
            assert!(g.vertexes.contains_key(&k));
        }
        assert_eq!(g.edges[&(0, 1)], 5);
        assert_eq!(g.edges[&(0, 2)], 2);
        assert_eq!(g.edges[&(2, 3)], 3);
        assert_eq!(g.edges[&(4, 3)], 1);
    }

    #[test]
    fn test_bfs() {
        let vertex_list = vec![(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0)];
        let edge_list = vec![(0, 1, 1), (1, 2, 1), (0, 3, 1), (3, 4, 1), (4, 1, 0), (4, 5, 1), (5, 2, 1)];
        let g = Graph::new(&vertex_list, &edge_list);
        let result: Vec<(VertexId, u64, VertexId)> = g.bfs_iter(0).collect();
        let mut result_set = HashSet::new();
        result_set.extend(result);
        let mut expect = HashSet::new();
        expect.insert((0, 0, usize::MAX));
        expect.insert((1, 1, 0));
        expect.insert((2, 2, 1));
        expect.insert((3, 1, 0));
        expect.insert((4, 2, 3));
        expect.insert((5, 3, 4));
        assert_eq!(result_set, expect);
    }
}
<commit_msg>Iterator compile bug<commit_after>use std::collections::{HashMap, VecDeque};
use std::iter::Iterator;
use std::u64;
use std::usize;

pub type VertexId = usize;

pub trait Property : Copy + Ord + Eq {}
impl<T> Property for T where T: Copy + Ord + Eq {}

/// Represent a Graph structure
#[derive(Debug)]
pub struct Graph<V: Property, E: Property> {
    pub vertexes: HashMap<VertexId, Vertex<V>>,
    pub edges: HashMap<(VertexId, VertexId), E>,
    adjacency_matrix: Vec<Vec<bool>>,
}

#[derive(Debug)]
pub struct Vertex<V: Property> {
    pub value: V,
    pub neighbors: Vec<VertexId>,
}

pub struct BfsIterator<'a, V: 'a + Property, E: 'a + Property, F> {
    queue: VecDeque<VertexId>,
    graph: &'a Graph<V, E>,
    distances: Vec<u64>,
    parents: Vec<VertexId>,
    predicate: F
}

pub impl<'a, V: Property, E: Property, F> BfsIterator<'a, V, E, F> {
    fn new(graph: &'a Graph<V, E>, source: VertexId, predicate: F) -> BfsIterator<'a, V, E, F> {
        let mut queue = VecDeque::new();
        queue.push_back(source);
        let mut distances = vec![u64::MAX; graph.n_vertexes()];
        let parents = vec![usize::MAX; graph.n_vertexes()];
        distances[source] = 0;
        BfsIterator {
            graph: graph,
            queue: queue,
            distances: distances,
            parents: parents,
            predicate: predicate
        }
    }
}

/// Iterator for a breadth first search over a graph
/// Returns in order a tuple of (vertex, distance, parent)
pub impl<'a, V: Property, E: Property, F> Iterator for BfsIterator<'a, V, E, F>
    where F: Fn(V, E, V) -> bool {
    type Item = (VertexId, u64, VertexId);
    pub fn next(&mut self) -> Option<(VertexId, u64, VertexId)> {
        let g = self.graph;
        match self.queue.pop_front() {
            Some(vertex) => {
                for v in self.graph.adjacent_vertexes(&vertex) {
                    let predicate = &self.predicate;
                    let pred = predicate(g.vertexes[&vertex].value, g.edges[&(vertex, *v)], g.vertexes[v].value);
                    if self.distances[*v] == u64::MAX && pred {
                        self.distances[*v] = self.distances[vertex] + 1;
                        self.parents[*v] = vertex;
                        self.queue.push_back(*v);
                    }
                }
                Some((vertex, self.distances[vertex], self.parents[vertex]))
            }
            _ => None
        }
    }
}

impl<'a, V: Property, E: Property> Graph<V, E> {
    pub fn new(vertex_list: &Vec<(VertexId, V)>, edge_list: &Vec<(VertexId, VertexId, E)>) -> Graph<V, E> {
        let mut vertexes: HashMap<VertexId, Vertex<V>> = HashMap::new();
        for v in vertex_list {
            vertexes.insert(v.0,
                            Vertex {
                                value: v.1,
                                neighbors: Vec::new(),
                            });
        }
        let n_vertexes: usize = vertexes.len();

        let mut adjacency_matrix: Vec<Vec<bool>> = vec![vec![false; n_vertexes]; n_vertexes];
        let mut edges: HashMap<(VertexId, VertexId), E> = HashMap::new();
        for edge in edge_list {
            adjacency_matrix[edge.0][edge.1] = true;
            vertexes.get_mut(&edge.0).unwrap().neighbors.push(edge.1);
            edges.insert((edge.0, edge.1), edge.2);
        }

        Graph {
            vertexes: vertexes,
            edges: edges,
            adjacency_matrix: adjacency_matrix,
        }
    }
    pub fn size(&self) -> (usize, usize) {
        (self.vertexes.len(), self.edges.len())
    }
    pub fn n_vertexes(&self) -> usize {
        self.vertexes.len()
    }
    pub fn n_edges(&self) -> usize {
        self.edges.len()
    }
    pub fn adjacent_vertexes(&self, vertex: &VertexId) -> &Vec<VertexId> {
        &self.vertexes[vertex].neighbors
    }
    pub fn bfs_iter(&self, source: VertexId) -> BfsIterator<V, E, fn(V, E, V) -> bool> {
        BfsIterator::new(self, source, bfs_true_predicate)
    }
    pub fn bfs_iter_predicate<F>(&'a self, source: VertexId, predicate: F) -> BfsIterator<V, E, F>
    where F: Fn(V, E, V) -> bool {
        BfsIterator::new(self, source, predicate)
    }
}

pub trait FlowGraph<V> {
    fn augmenting_path(&self, source: VertexId) -> Vec<VertexId>;
}

impl<'a, V: Property> FlowGraph<V> for Graph<V, i64> {
    pub fn augmenting_path(&self, source: VertexId) -> Vec<VertexId> {
        BfsIterator::new(self, source, flow_predicate).collect()
    }
}

fn bfs_true_predicate<'a, V: Property, E: Property>(_: V, _: E, _: V) -> bool {
    true
}

fn flow_predicate<'a, V: Property>(_: V, edge: i64, _: V) {
    edge > 0;
}

#[cfg(test)]
mod tests {
    use Graph;
    use VertexId;
    use std::collections::HashSet;
    use std::usize;

    #[test]
    fn test_new_graph() {
        let vertex_list = vec![(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)];
        let edge_list = vec![(0, 1, 5), (0, 2, 2), (2, 3, 3), (4, 3, 1)];
        let g = Graph::new(&vertex_list, &edge_list);
        assert_eq!(g.size(), (5, 4));
        for k in 0..5 {
            assert!(g.vertexes.contains_key(&k));
        }
        assert_eq!(g.edges[&(0, 1)], 5);
        assert_eq!(g.edges[&(0, 2)], 2);
        assert_eq!(g.edges[&(2, 3)], 3);
        assert_eq!(g.edges[&(4, 3)], 1);
    }

    #[test]
    fn test_bfs() {
        let vertex_list = vec![(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0)];
        let edge_list = vec![(0, 1, 1), (1, 2, 1), (0, 3, 1), (3, 4, 1), (4, 1, 0), (4, 5, 1), (5, 2, 1)];
        let g = Graph::new(&vertex_list, &edge_list);
        let result: Vec<(VertexId, u64, VertexId)> = g.bfs_iter(0).collect();
        let mut result_set = HashSet::new();
        result_set.extend(result);
        let mut expect = HashSet::new();
        expect.insert((0, 0, usize::MAX));
        expect.insert((1, 1, 0));
        expect.insert((2, 2, 1));
        expect.insert((3, 1, 0));
        expect.insert((4, 2, 3));
        expect.insert((5, 3, 4));
        assert_eq!(result_set, expect);
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![feature(core_intrinsics)]

pub mod extra {
    use std::process::exit;
    use std::error::Error;
    use std::io::{self, Write, Stderr};

    /// Extension for Option-like types
    pub trait OptionalExt {
        /// The "success" variant of this optional type.
        type Succ;

        /// Unwrap or abort program with exit code
        fn try(self, stderr: &mut Stderr) -> Self::Succ;

        /// Unwrap or abort the program with failed exit code and custom error message
        fn fail<'a>(self, err: &'a str, stderr: &mut Stderr) -> Self::Succ;

        /// An unwrapping where the fail-case is not checked and threaten as statical unreachable.
        unsafe fn unchecked_unwrap(self) -> Self::Succ;
    }

    impl<T, U: Error> OptionalExt for Result<T, U> {
        type Succ = T;

        fn try(self, stderr: &mut Stderr) -> T {
            let mut stderr = stderr.lock();

            match self {
                Ok(succ) => succ,
                Err(e) => {
                    // We ignore the results to avoid stack overflow (because of unbounded
                    // recursion).
                    let _ = stderr.write(b"error: ");
                    let _ = stderr.write(e.description().as_bytes());
                    let _ = stderr.write(b"\n");
                    let _ = stderr.flush();
                    exit(1);
                },
            }
        }

        fn fail<'a>(self, err: &'a str, stderr: &mut Stderr) -> T {
            let mut stderr = stderr.lock();

            match self {
                Ok(succ) => succ,
                Err(_) => {
                    let _ = stderr.write(b"error: ");
                    let _ = stderr.write(err.as_bytes());
                    let _ = stderr.write(b"\n");
                    let _ = stderr.flush();
                    exit(1);
                },
            }
        }

        unsafe fn unchecked_unwrap(self) -> T {
            if let Ok(x) = self {
                x
            } else {
                unreachable()
            }
        }
    }

    impl<T> OptionalExt for Option<T> {
        type Succ = T;

        fn try(self, stderr: &mut Stderr) -> T {
            let mut stderr = stderr.lock();

            match self {
                Some(succ) => succ,
                None => {
                    let _ = stderr.writeln(b"error: (no message)\n");
                    let _ = stderr.flush();
                    exit(1);
                },
            }
        }

        fn fail<'a>(self, err: &'a str, stderr: &mut Stderr) -> T {
            let mut stderr = stderr.lock();

            match self {
                Some(succ) => succ,
                None => {
                    let _ = stderr.write(b"error:");
                    let _ = stderr.write(err.as_bytes());
                    let _ = stderr.write(b"\n");
                    let _ = stderr.flush();
                    exit(1);
                },
            }
        }

        unsafe fn unchecked_unwrap(self) -> T {
            if let Some(x) = self {
                x
            } else {
                unreachable()
            }
        }
    }

    pub trait WriteExt {
        fn writeln(&mut self, s: &[u8]) -> io::Result<usize>;
    }

    impl<W: Write> WriteExt for W {
        fn writeln(&mut self, s: &[u8]) -> io::Result<usize> {
            let res = self.write(s);
            match self.write(b"\n") {
                Ok(n) => res.map(|x| x + n),
                e => e,
            }
        }
    }

    /// A hint which is threaten as statical unreachable in release mode, and panic (unreachable!())
    /// in debug mode.
    #[cfg(debug)]
    pub unsafe fn unreachable() -> ! {
        unreachable!();
    }

    /// A hint which is threaten as statical unreachable in release mode, and panic (unreachable!())
    /// in debug mode.
    #[cfg(not(debug))]
    pub unsafe fn unreachable() -> ! {
        use std::intrinsics::unreachable;

        unreachable();
    }

    #[macro_export]
    macro_rules! try_some {
        ($x:expr) => {
            if let Some(x) = $x {
                x
            } else {
                return None;
            }
        };
        ($x:expr => $y:expr) => {
            if let Some(x) = $x {
                x
            } else {
                return $y;
            }
        };
    }

    pub fn fail<'a>(s: &'a str, stderr: &mut Stderr) -> ! {
        let mut stderr = stderr.lock();

        let _ = stderr.write(b"error: ");
        let _ = stderr.write(s.as_bytes());
        let _ = stderr.write(b"\n");
        let _ = stderr.flush();
        exit(1);
    }
}
<commit_msg>put_char for Write<commit_after>#![deny(warnings)]
#![feature(core_intrinsics)]
#![feature(unicode)]

pub mod extra {
    use std::process::exit;
    use std::error::Error;
    use std::io::{self, Write, Stderr};

    /// Extension for Option-like types
    pub trait OptionalExt {
        /// The "success" variant of this optional type.
        type Succ;

        /// Unwrap or abort program with exit code
        fn try(self, stderr: &mut Stderr) -> Self::Succ;

        /// Unwrap or abort the program with failed exit code and custom error message
        fn fail<'a>(self, err: &'a str, stderr: &mut Stderr) -> Self::Succ;

        /// An unwrapping where the fail-case is not checked and threaten as statical unreachable.
        unsafe fn unchecked_unwrap(self) -> Self::Succ;
    }

    impl<T, U: Error> OptionalExt for Result<T, U> {
        type Succ = T;

        fn try(self, stderr: &mut Stderr) -> T {
            let mut stderr = stderr.lock();

            match self {
                Ok(succ) => succ,
                Err(e) => {
                    // We ignore the results to avoid stack overflow (because of unbounded
                    // recursion).
                    let _ = stderr.write(b"error: ");
                    let _ = stderr.write(e.description().as_bytes());
                    let _ = stderr.write(b"\n");
                    let _ = stderr.flush();
                    exit(1);
                },
            }
        }

        fn fail<'a>(self, err: &'a str, stderr: &mut Stderr) -> T {
            let mut stderr = stderr.lock();

            match self {
                Ok(succ) => succ,
                Err(_) => {
                    let _ = stderr.write(b"error: ");
                    let _ = stderr.write(err.as_bytes());
                    let _ = stderr.write(b"\n");
                    let _ = stderr.flush();
                    exit(1);
                },
            }
        }

        unsafe fn unchecked_unwrap(self) -> T {
            if let Ok(x) = self {
                x
            } else {
                unreachable()
            }
        }
    }

    impl<T> OptionalExt for Option<T> {
        type Succ = T;

        fn try(self, stderr: &mut Stderr) -> T {
            let mut stderr = stderr.lock();

            match self {
                Some(succ) => succ,
                None => {
                    let _ = stderr.writeln(b"error: (no message)\n");
                    let _ = stderr.flush();
                    exit(1);
                },
            }
        }

        fn fail<'a>(self, err: &'a str, stderr: &mut Stderr) -> T {
            let mut stderr = stderr.lock();

            match self {
                Some(succ) => succ,
                None => {
                    let _ = stderr.write(b"error:");
                    let _ = stderr.write(err.as_bytes());
                    let _ = stderr.write(b"\n");
                    let _ = stderr.flush();
                    exit(1);
                },
            }
        }

        unsafe fn unchecked_unwrap(self) -> T {
            if let Some(x) = self {
                x
            } else {
                unreachable()
            }
        }
    }

    pub trait WriteExt {
        fn writeln(&mut self, s: &[u8]) -> io::Result<usize>;

        fn put_char(&mut self, c: char) -> io::Result<usize>;
    }

    impl<W: Write> WriteExt for W {
        fn writeln(&mut self, s: &[u8]) -> io::Result<usize> {
            let res = self.write(s);
            match self.write(b"\n") {
                Ok(n) => res.map(|x| x + n),
                e => e,
            }
        }

        fn put_char(&mut self, c: char) -> io::Result<usize> {
            let mut buf = [0; 4];
            let n = c.encode_utf8(&mut buf).expect("Invalid UTF-8! This is a bug: Report it at 'github.com/redox-os/coreutils'.");
            self.write(&buf[..n])
        }
    }

    /// A hint which is threaten as statical unreachable in release mode, and panic (unreachable!())
    /// in debug mode.
    #[cfg(debug)]
    pub unsafe fn unreachable() -> ! {
        unreachable!();
    }

    /// A hint which is threaten as statical unreachable in release mode, and panic (unreachable!())
    /// in debug mode.
    #[cfg(not(debug))]
    pub unsafe fn unreachable() -> ! {
        use std::intrinsics::unreachable;

        unreachable();
    }

    #[macro_export]
    macro_rules! try_some {
        ($x:expr) => {
            if let Some(x) = $x {
                x
            } else {
                return None;
            }
        };
        ($x:expr => $y:expr) => {
            if let Some(x) = $x {
                x
            } else {
                return $y;
            }
        };
    }

    pub fn fail<'a>(s: &'a str, stderr: &mut Stderr) -> ! {
        let mut stderr = stderr.lock();

        let _ = stderr.write(b"error: ");
        let _ = stderr.write(s.as_bytes());
        let _ = stderr.write(b"\n");
        let _ = stderr.flush();
        exit(1);
    }
}
<|endoftext|>


<commit_before>//! `primal` puts raw power into prime numbers.
//!
//! This crates includes
//!
//! - optimised prime sieves
//! - checking for primality
//! - enumerating primes
//! - factorising numbers
//! - estimating upper and lower bounds for π(*n*) (the number of primes
//!   below *n*) and *pk* (the kth prime)
//!
//! This uses a state-of-the-art cache-friendly Sieve of Eratosthenes
//! to enumerate the primes up to some fixed bound (in a memory
//! efficient manner), and then allows this cached information to be
//! used for things like enumerating and counting primes.
//!
//! `primal` takes around 2.8 seconds and less than 3MB of RAM to
//! count the exact number of primes below 1010 (455052511)
//! on my laptop (i7-3517U).
//!
//! [*Source*](http://github.com/huonw/primal)
//!
//! # Using this library
//!
//! Just add the following to your [`Cargo.toml`](http://crates.io/):
//!
//! ```toml
//! [dependencies]
//! primal = "0.2"
//! ```
//!
//! # Examples
//!
//! ## "Indexing" Primes
//!
//! Let's find the 10001st prime. The easiest way is to enumerate the
//! primes, and find the 10001st:
//!
//! ```rust
//! // (.nth is zero indexed.)
//! let p = primal::Primes::all().nth(10001 - 1).unwrap();
//! println!("The 10001st prime is {}", p); // 104743
//! ```
//!
//! This takes around 400 microseconds on my computer, which seems
//! nice and quick, but, `Primes` is flexible at the cost of
//! performance: we can make it faster. The `StreamingSieve` type
//! offers a specialised `nth_prime` function:
//!
//! ```rust
//! let p = primal::StreamingSieve::nth_prime(10001);
//! println!("The 10001st prime is {}", p); // 104743
//! ```
//!
//! This runs in only 10 microseconds! `StreamingSieve` is extremely
//! efficient and uses very little memory. It is the best way to solve
//! this task with `primal`.
//!
//! Since that was so easy, let's now make the problem bigger and
//! harder: find the sum of the 100,000th, 200,000th, 300,000th, ...,
//! 10,000,000th primes (100 in total).
//!
//! We could call `StreamingSieve::nth_prime` repeatedly:
//!
//! ```rust,no_run
//! // the primes we want to find
//! let ns = (1..100 + 1).map(|x| x * 100_000).collect::<Vec<_>>();
//!
//! // search and sum them up
//! let sum = ns.iter()
//!             .map(|n| primal::StreamingSieve::nth_prime(*n))
//!             .fold(0, |a, b| a + b);
//! println!("the sum is {}", sum);
//! ```
//!
//! This takes around 1.6s seconds to print `the sum is 8795091674`;
//! not so speedy. Each call to `nth_prime` is individually fast (400
//! microseconds for 100,000 to 40 milliseconds for 10,000,000) but
//! they add up to something bad. Every one is starting from the start
//! and redoing work that previous calls have done... wouldn't it be
//! nice if we could just do the computation for 10,000,000 and reuse
//! that for the smaller ones?
//!
//! The `Sieve` type is a wrapper around `StreamingSieve` that
//! caches information, allowing repeated queries to be answered
//! efficiently.
//!
//! There's one hitch: `Sieve` requires a limit to know how far to
//! sieve: we need some way to find an upper bound to be guaranteed to
//! be at least as large as all our primes. We could guess that, say,
//! 1010 will be large enough and use that, but that's a
//! huge overestimate (spoilers: the 10,000,000th prime is around
//! 2×108). We could also try filtering with
//! exponentially larger upper bounds until we find one that works
//! (e.g. doubling each time), or, we could just take a shortcut and
//! use deeper mathematics via
//! [`estimate_nth_prime`](fn.estimate_nth_prime.html).
//!
//! ```rust
//! // the primes we want to find
//! let ns = (1..100 + 1).map(|x| x * 100_000).collect::<Vec<_>>();
//!
//! // find our upper bound
//! let (_lo, hi) = primal::estimate_nth_prime(10_000_000);
//!
//! // find the primes up to this upper bound
//! let sieve = primal::Sieve::new(hi as usize);
//!
//! // now we can efficiently sum them up
//! let sum = ns.iter()
//!             .map(|n| sieve.nth_prime(*n))
//!             .fold(0, |a, b| a + b);
//! println!("the sum is {}", sum);
//! ```
//!
//! This takes around 40 milliseconds, and gives the same output: much
//! better!
//!
//! (By the way, the version using 1010 as the bound
//! instead of the more accurate estimate still only takes ~3
//! seconds.)
//!
//! ## Counting Primes
//!
//! Another problem: count the number of primes below 1 million. This
//! is evaluating the [prime-counting function
//! π](https://en.wikipedia.org/wiki/Prime-counting_function),
//! i.e. π(106).
//!
//! As above, there's a few ways to attack this: the iterator, and the
//! sieves.
//!
//! ```rust
//! const LIMIT: usize = 1_000_000;
//!
//! // iterator
//! let count = primal::Primes::all().take_while(|p| *p < LIMIT).count();
//! println!("there are {} primes below 1 million", count); // 78498
//!
//! // sieves
//! let sieve = primal::Sieve::new(LIMIT);
//! let count = sieve.prime_pi(LIMIT);
//! println!("there are {} primes below 1 million", count);
//!
//! let count = primal::StreamingSieve::prime_pi(LIMIT);
//! println!("there are {} primes below 1 million", count);
//! ```
//!
//! `StreamingSieve` is fastest (380 microseconds) followed by `Sieve`
//! (400) with `Primes` bringing up the rear at 1300 microseconds. Of
//! course, repeated queries will be faster with `Sieve` than with
//! `StreamingSieve`, but that flexibility comes at the cost of extra
//! memory use.
//!
//! If an approximation is all that is required, `estimate_prime_pi`
//! provides close upper and lower bounds:
//!
//! ```rust
//! let (lo, hi) = primal::estimate_prime_pi(1_000_000);
//! println!("there are between {} and {} primes below 1 million", lo, hi);
//! // 78304, 78573
//! ```
//!
//! ## Searching Primes
//!
//! Now for something where `Primes` might be useful: find the first
//! prime where the binary expansion (not including trailing zeros)
//! ends like `00..001` with at least 27 zeros. This condition is
//! checked by:
//!
//! ```rust
//! fn check(p: usize) -> bool {
//!     p > 1 && (p / 2).trailing_zeros() >= 27
//! }
//! ```
//!
//! I have no idea how large the prime might be: I know it's
//! guaranteed to be at *least* 227 + 1 + 1, but not an
//! upper limit.
//!
//! The `Primes` iterator works perfectly for this:
//!
//! ```rust
//! # fn check(p: usize) -> bool {  p > 1 && (p / 2).trailing_zeros() >= 5 } // 27 is too slow
//! let p = primal::Primes::all().find(|p| check(*p)).unwrap();
//! println!("the prime is {}", p);
//! # assert_eq!(p, 193);
//! ```
//!
//! It takes about 3.1 seconds for my computer to spit out 3,221,225,473.
//!
//! Using a sieve is a little trickier: one approach is to start with
//! some estimated upper bound (like double the absolute lower bound),
//! look for a valid prime. If one isn't found, double the upper bound
//! and start again. The `primes_from` method allows for saving a
//! little bit of work: we can start iterating from an arbitrary point
//! in the sequence, such as the lower bound.
//!
//! ```rust
//! # fn check(p: usize) -> bool {  p > 1 && (p / 2).trailing_zeros() >= 5 } // 27 is too slow
//! let p;
//! let mut lower_bound = 1 << (27 + 1);
//! # let mut lower_bound = 1 << (5 + 1);
//! loop {
//!     // our upper bound is double the lower bound
//!     let sieve = primal::Sieve::new(lower_bound * 2);
//!     if let Some(p_) = sieve.primes_from(lower_bound).find(|p| check(*p)) {
//!         p = p_;
//!         break
//!     }
//!     lower_bound *= 2;
//! }
//! println!("the prime is {}", p);
//! # assert_eq!(p, 193);
//! ```
//!
//! This takes around 3.5 seconds to print the same number. Slower
//! than the iterator!
//!
//! I was just using this silly condition as an example of something
//! that doesn't have an obvious upper bound, rather than a problem
//! that is hard to do fast. There's a much faster way to tackle it,
//! by inverting the problem: construct numbers that satisfy `check`,
//! and check the primality of those.
//!
//! The numbers that satisfy `check` are `k * (1 << (27 + 1)) + 1` for
//! `k >= 1`, so the only hard bit is testing primality. Fortunately,
//! `primal` offers the `is_prime` function which is an efficient way
//! to do primality tests, even of very large numbers.
//!
//! ```rust
//! let mut p = 0;
//! for k in 1.. {
//!     p = k * (1 << (27 + 1)) + 1;
//!     if primal::is_prime(p) { break }
//! }
//! println!("the prime is {}", p);
//! # assert_eq!(p, 3_221_225_473);
//! ```
//!
//! This takes 6 microseconds: more than 500,000×
//! faster than the iterator!

#![cfg_attr(all(test, feature = "unstable"), feature(test, step_by))]

extern crate primal_estimate;
extern crate primal_check;
extern crate primal_sieve;

#[cfg(all(test, feature = "unstable"))] extern crate test;

pub use primal_estimate::prime_pi as estimate_prime_pi;
pub use primal_estimate::nth_prime as estimate_nth_prime;
pub use primal_check::miller_rabin as is_prime;
pub use primal_check::{as_perfect_power, as_prime_power};

pub use primal_sieve::{StreamingSieve, Sieve, SievePrimes, Primes};

#[cfg(all(test, feature = "unstable"))]
mod benches {
    extern crate test;

    use super::{Sieve, is_prime};
    use self::test::Bencher;

    const N: usize = 1_000_000;
    const STEP: usize = 101;
    #[bench]
    fn bench_miller_rabin_tests(b: &mut Bencher) {
        b.iter(|| {
            (1..N).step_by(STEP)
                .filter(|&n| is_prime(n as u64)).count()
        })
    }
    #[bench]
    fn bench_sieve_tests(b: &mut Bencher) {
        b.iter(|| {
            let sieve = Sieve::new(1_000_000);
            (1..N).step_by(STEP)
                .filter(|&n| sieve.is_prime(n)).count()
        })
    }
}
<commit_msg>Added more asserts to documentation<commit_after>//! `primal` puts raw power into prime numbers.
//!
//! This crates includes
//!
//! - optimised prime sieves
//! - checking for primality
//! - enumerating primes
//! - factorising numbers
//! - estimating upper and lower bounds for π(*n*) (the number of primes
//!   below *n*) and *pk* (the kth prime)
//!
//! This uses a state-of-the-art cache-friendly Sieve of Eratosthenes
//! to enumerate the primes up to some fixed bound (in a memory
//! efficient manner), and then allows this cached information to be
//! used for things like enumerating and counting primes.
//!
//! `primal` takes around 2.8 seconds and less than 3MB of RAM to
//! count the exact number of primes below 1010 (455052511)
//! on my laptop (i7-3517U).
//!
//! [*Source*](http://github.com/huonw/primal)
//!
//! # Using this library
//!
//! Just add the following to your [`Cargo.toml`](http://crates.io/):
//!
//! ```toml
//! [dependencies]
//! primal = "0.2"
//! ```
//!
//! # Examples
//!
//! ## "Indexing" Primes
//!
//! Let's find the 10001st prime. The easiest way is to enumerate the
//! primes, and find the 10001st:
//!
//! ```rust
//! // (.nth is zero indexed.)
//! let p = primal::Primes::all().nth(10001 - 1).unwrap();
//! println!("The 10001st prime is {}", p); // 104743
//! # assert_eq!(p, 104743);
//! ```
//!
//! This takes around 400 microseconds on my computer, which seems
//! nice and quick, but, `Primes` is flexible at the cost of
//! performance: we can make it faster. The `StreamingSieve` type
//! offers a specialised `nth_prime` function:
//!
//! ```rust
//! let p = primal::StreamingSieve::nth_prime(10001);
//! println!("The 10001st prime is {}", p); // 104743
//! # assert_eq!(p, 104743);
//! ```
//!
//! This runs in only 10 microseconds! `StreamingSieve` is extremely
//! efficient and uses very little memory. It is the best way to solve
//! this task with `primal`.
//!
//! Since that was so easy, let's now make the problem bigger and
//! harder: find the sum of the 100,000th, 200,000th, 300,000th, ...,
//! 10,000,000th primes (100 in total).
//!
//! We could call `StreamingSieve::nth_prime` repeatedly:
//!
//! ```rust,no_run
//! // the primes we want to find
//! let ns = (1..100 + 1).map(|x| x * 100_000).collect::<Vec<_>>();
//!
//! // search and sum them up
//! let sum = ns.iter()
//!             .map(|n| primal::StreamingSieve::nth_prime(*n))
//!             .fold(0, |a, b| a + b);
//! println!("the sum is {}", sum);
//! ```
//!
//! This takes around 1.6s seconds to print `the sum is 8795091674`;
//! not so speedy. Each call to `nth_prime` is individually fast (400
//! microseconds for 100,000 to 40 milliseconds for 10,000,000) but
//! they add up to something bad. Every one is starting from the start
//! and redoing work that previous calls have done... wouldn't it be
//! nice if we could just do the computation for 10,000,000 and reuse
//! that for the smaller ones?
//!
//! The `Sieve` type is a wrapper around `StreamingSieve` that
//! caches information, allowing repeated queries to be answered
//! efficiently.
//!
//! There's one hitch: `Sieve` requires a limit to know how far to
//! sieve: we need some way to find an upper bound to be guaranteed to
//! be at least as large as all our primes. We could guess that, say,
//! 1010 will be large enough and use that, but that's a
//! huge overestimate (spoilers: the 10,000,000th prime is around
//! 2×108). We could also try filtering with
//! exponentially larger upper bounds until we find one that works
//! (e.g. doubling each time), or, we could just take a shortcut and
//! use deeper mathematics via
//! [`estimate_nth_prime`](fn.estimate_nth_prime.html).
//!
//! ```rust
//! // the primes we want to find
//! let ns = (1..100 + 1).map(|x| x * 100_000).collect::<Vec<_>>();
//!
//! // find our upper bound
//! let (_lo, hi) = primal::estimate_nth_prime(10_000_000);
//!
//! // find the primes up to this upper bound
//! let sieve = primal::Sieve::new(hi as usize);
//!
//! // now we can efficiently sum them up
//! let sum = ns.iter()
//!             .map(|n| sieve.nth_prime(*n))
//!             .fold(0, |a, b| a + b);
//! println!("the sum is {}", sum);
//! # assert_eq!(sum, 8795091674);
//! ```
//!
//! This takes around 40 milliseconds, and gives the same output: much
//! better!
//!
//! (By the way, the version using 1010 as the bound
//! instead of the more accurate estimate still only takes ~3
//! seconds.)
//!
//! ## Counting Primes
//!
//! Another problem: count the number of primes below 1 million. This
//! is evaluating the [prime-counting function
//! π](https://en.wikipedia.org/wiki/Prime-counting_function),
//! i.e. π(106).
//!
//! As above, there's a few ways to attack this: the iterator, and the
//! sieves.
//!
//! ```rust
//! const LIMIT: usize = 1_000_000;
//!
//! // iterator
//! let count = primal::Primes::all().take_while(|p| *p < LIMIT).count();
//! println!("there are {} primes below 1 million", count); // 78498
//! # assert_eq!(count, 78498);
//!
//! // sieves
//! let sieve = primal::Sieve::new(LIMIT);
//! let count = sieve.prime_pi(LIMIT);
//! println!("there are {} primes below 1 million", count);
//! # assert_eq!(count, 78498);
//!
//! let count = primal::StreamingSieve::prime_pi(LIMIT);
//! println!("there are {} primes below 1 million", count);
//! # assert_eq!(count, 78498);
//! ```
//!
//! `StreamingSieve` is fastest (380 microseconds) followed by `Sieve`
//! (400) with `Primes` bringing up the rear at 1300 microseconds. Of
//! course, repeated queries will be faster with `Sieve` than with
//! `StreamingSieve`, but that flexibility comes at the cost of extra
//! memory use.
//!
//! If an approximation is all that is required, `estimate_prime_pi`
//! provides close upper and lower bounds:
//!
//! ```rust
//! let (lo, hi) = primal::estimate_prime_pi(1_000_000);
//! println!("there are between {} and {} primes below 1 million", lo, hi);
//! // 78304, 78573
//! # assert_eq!(lo, 78304);
//! # assert_eq!(hi, 78573);
//! ```
//!
//! ## Searching Primes
//!
//! Now for something where `Primes` might be useful: find the first
//! prime where the binary expansion (not including trailing zeros)
//! ends like `00..001` with at least 27 zeros. This condition is
//! checked by:
//!
//! ```rust
//! fn check(p: usize) -> bool {
//!     p > 1 && (p / 2).trailing_zeros() >= 27
//! }
//! ```
//!
//! I have no idea how large the prime might be: I know it's
//! guaranteed to be at *least* 227 + 1 + 1, but not an
//! upper limit.
//!
//! The `Primes` iterator works perfectly for this:
//!
//! ```rust
//! # fn check(p: usize) -> bool {  p > 1 && (p / 2).trailing_zeros() >= 5 } // 27 is too slow
//! let p = primal::Primes::all().find(|p| check(*p)).unwrap();
//! println!("the prime is {}", p);
//! # assert_eq!(p, 193);
//! ```
//!
//! It takes about 3.1 seconds for my computer to spit out 3,221,225,473.
//!
//! Using a sieve is a little trickier: one approach is to start with
//! some estimated upper bound (like double the absolute lower bound),
//! look for a valid prime. If one isn't found, double the upper bound
//! and start again. The `primes_from` method allows for saving a
//! little bit of work: we can start iterating from an arbitrary point
//! in the sequence, such as the lower bound.
//!
//! ```rust
//! # fn check(p: usize) -> bool {  p > 1 && (p / 2).trailing_zeros() >= 5 } // 27 is too slow
//! let p;
//! let mut lower_bound = 1 << (27 + 1);
//! # let mut lower_bound = 1 << (5 + 1);
//! loop {
//!     // our upper bound is double the lower bound
//!     let sieve = primal::Sieve::new(lower_bound * 2);
//!     if let Some(p_) = sieve.primes_from(lower_bound).find(|p| check(*p)) {
//!         p = p_;
//!         break
//!     }
//!     lower_bound *= 2;
//! }
//! println!("the prime is {}", p);
//! # assert_eq!(p, 193);
//! ```
//!
//! This takes around 3.5 seconds to print the same number. Slower
//! than the iterator!
//!
//! I was just using this silly condition as an example of something
//! that doesn't have an obvious upper bound, rather than a problem
//! that is hard to do fast. There's a much faster way to tackle it,
//! by inverting the problem: construct numbers that satisfy `check`,
//! and check the primality of those.
//!
//! The numbers that satisfy `check` are `k * (1 << (27 + 1)) + 1` for
//! `k >= 1`, so the only hard bit is testing primality. Fortunately,
//! `primal` offers the `is_prime` function which is an efficient way
//! to do primality tests, even of very large numbers.
//!
//! ```rust
//! let mut p = 0;
//! for k in 1.. {
//!     p = k * (1 << (27 + 1)) + 1;
//!     if primal::is_prime(p) { break }
//! }
//! println!("the prime is {}", p);
//! # assert_eq!(p, 3_221_225_473);
//! ```
//!
//! This takes 6 microseconds: more than 500,000×
//! faster than the iterator!

#![cfg_attr(all(test, feature = "unstable"), feature(test, step_by))]

extern crate primal_estimate;
extern crate primal_check;
extern crate primal_sieve;

#[cfg(all(test, feature = "unstable"))] extern crate test;

pub use primal_estimate::prime_pi as estimate_prime_pi;
pub use primal_estimate::nth_prime as estimate_nth_prime;
pub use primal_check::miller_rabin as is_prime;
pub use primal_check::{as_perfect_power, as_prime_power};

pub use primal_sieve::{StreamingSieve, Sieve, SievePrimes, Primes};

#[cfg(all(test, feature = "unstable"))]
mod benches {
    extern crate test;

    use super::{Sieve, is_prime};
    use self::test::Bencher;

    const N: usize = 1_000_000;
    const STEP: usize = 101;
    #[bench]
    fn bench_miller_rabin_tests(b: &mut Bencher) {
        b.iter(|| {
            (1..N).step_by(STEP)
                .filter(|&n| is_prime(n as u64)).count()
        })
    }
    #[bench]
    fn bench_sieve_tests(b: &mut Bencher) {
        b.iter(|| {
            let sieve = Sieve::new(1_000_000);
            (1..N).step_by(STEP)
                .filter(|&n| sieve.is_prime(n)).count()
        })
    }
}
<|endoftext|>


<commit_before>// tag_safe
//
// A linting plugin to flag calls to methods not marked "tag_safe"
// from methods marked "tag_safe".
//
// Author: John Hodge (thePowersGang/Mutabah)
//
// TODO: Support '#[tag_unsafe(type)]' which is used when a method has no marker
// - Allows default safe fallback, with upwards propagation.
//
#![crate_name="tag_safe"]
#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private)]

#[macro_use]
extern crate log;

extern crate syntax;
#[macro_use]
extern crate rustc;

extern crate rustc_front;

use syntax::ast;
use rustc::middle::def_id::DefId;
use rustc_front::visit;
use syntax::codemap::Span;
use rustc::lint::{self, LintContext, LintPass, LateLintPass, LintArray};
use rustc::plugin::Registry;
use rustc::middle::{def,ty};
use rustc_front::hir;
use syntax::attr::AttrMetaMethods;

declare_lint!(NOT_TAGGED_SAFE, Warn, "Warn about use of non-tagged methods within tagged function");

#[derive(Copy,Clone,Debug)]
enum SafetyType
{
    Safe,
    Unsafe,
    Unknown,
}

#[derive(Default)]
struct Pass
{
    /// Cache of flag types
    flag_types: Vec<String>,
    /// Node => (Type => IsSafe)
    flag_cache: ::rustc::util::nodemap::NodeMap< ::rustc::util::nodemap::FnvHashMap<usize, SafetyType> >,

    lvl: usize,
}

struct Visitor<'a, 'tcx: 'a, F: FnMut(&Span) + 'a>
{
    pass: &'a mut Pass,
    tcx: &'a ty::ctxt<'tcx>,
    name: &'a str,
    unknown_assume: bool,
    cb: F,
}

// Hack to provide indenting in debug calls
struct Indent(usize);
impl ::std::fmt::Display for Indent {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        for s in ::std::iter::repeat(" ").take(self.0) {
            try!(write!(f, "{}", s));
        }
        Ok( () )
    }
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NOT_TAGGED_SAFE)
    }
}

impl LateLintPass for Pass {
    fn check_fn(&mut self, cx: &lint::LateContext, _kind: ::rustc_front::visit::FnKind, _decl: &hir::FnDecl, body: &hir::Block, _: Span, id: ast::NodeId) {
        let attrs = cx.tcx.map.attrs(id);
        for ty in attrs.iter()
            .filter(|a| a.check_name("tag_safe"))
            .filter_map(|a| a.meta_item_list())
            .flat_map(|x| x.iter())
        {
            // Search body for calls to non safe methods
            let mut v = Visitor{
                    pass: self, tcx: cx.tcx, name: &ty.name(),
                    // - Assumes an untagged method is unsafe
                    unknown_assume: false,
                    cb: |span| {
                            cx.span_lint(NOT_TAGGED_SAFE, *span,
                                &format!("Calling {}-unsafe method from a #[tag_safe({})] method", ty.name(), ty.name())[..]
                                );
                        },
                    };
            debug!("Method {:?} is marked safe '{}'", id, ty.name());
            visit::walk_block(&mut v, body);
        }
    }
}

impl Pass
{
    // Searches for the relevant marker
    fn check_for_marker(tcx: &ty::ctxt, id: ast::NodeId, marker: &str, name: &str) -> bool
    {
        debug!("Checking for marker {}({}) on {:?}", marker, name, id);
        tcx.map.attrs(id).iter()
            .filter_map( |a| if a.check_name(marker) { a.meta_item_list() } else { None })
            .flat_map(|x| x.iter())
            .any(|a| a.name() == name)
    }

    /// Recursively check that the provided function is either safe or unsafe.
    // Used to avoid excessive annotating
    fn recurse_fcn_body(&mut self, tcx: &ty::ctxt, node_id: ast::NodeId, name_id: usize, name: &str, unknown_assume: bool) -> bool
    {
        // Cache this method as unknown (to prevent infinite recursion)
        self.flag_cache.entry(node_id)
            .or_insert(Default::default())
            .insert(name_id, SafetyType::Unknown)
            ;

        // and apply a visitor to all
        match tcx.map.get(node_id)
        {
        rustc::front::map::NodeItem(i) =>
            match i.node {
            hir::ItemFn(_, _, _, _, _, ref body) => {
                // Enumerate this function's code, recursively checking for a call to an unsafe method
                let mut is_safe = true;
                {
                    let mut v = Visitor {
                        pass: self, tcx: tcx, name: name,
                        unknown_assume: true,
                        cb: |_| { is_safe = false; }
                        };
                    visit::walk_block(&mut v, body);
                }
                is_safe
                },
            _ => unknown_assume,
            },
        rustc::front::map::NodeImplItem(i) =>
            match i.node {
            hir::MethodImplItem(_, ref body) => {
                let mut is_safe = true;
                {
                    let mut v = Visitor {
                        pass: self, tcx: tcx, name: name,
                        unknown_assume: true,
                        cb: |_| { is_safe = false; }
                        };
                    visit::walk_block(&mut v, body);
                }
                is_safe
                },
            _ => unknown_assume,
            },
        rustc::front::map::NodeForeignItem(i) =>
            if Self::check_for_marker(tcx, i.id, "tag_safe", name) {
                true
            }
            else if Self::check_for_marker(tcx, i.id, "tag_unsafe", name) {
                false
            }
            else {
                unknown_assume
            },
        v @ _ => {
            error!("Node ID {} points to non-item {:?}", node_id, v);
            unknown_assume
            }
        }
    }

    /// Check that a method within this crate is safe with the provided tag
    fn crate_method_is_safe(&mut self, tcx: &ty::ctxt, node_id: ast::NodeId, name: &str, unknown_assume: bool) -> bool
    {
        // Obtain tag name ID (avoids storing a string in the map)
        let name_id =
            match self.flag_types.iter().position(|a| *a == name)
            {
            Some(v) => v,
            None => {
                self.flag_types.push( String::from(name) );
                self.flag_types.len() - 1
                },
            };

        // Check cache first
        if let Some(&st) = self.flag_cache.get(&node_id).and_then(|a| a.get(&name_id))
        {
            match st
            {
            SafetyType::Safe => true,
            SafetyType::Unsafe => false,
            SafetyType::Unknown => unknown_assume,
            }
        }
        else
        {
            // Search for a safety marker, possibly recursing
            let is_safe =
                if Self::check_for_marker(tcx, node_id, "tag_safe", name) {
                    true
                }
                else if Self::check_for_marker(tcx, node_id, "tag_unsafe", name) {
                    false
                }
                else {
                    self.recurse_fcn_body(tcx, node_id, name_id, name, unknown_assume)
                };
            // Save resultant value
            self.flag_cache.entry(node_id)
                .or_insert(Default::default())
                .insert(name_id, if is_safe { SafetyType::Safe } else { SafetyType::Unsafe })
                ;
            is_safe
        }
    }

    /// Locate a #[tag_safe(<name>)] attribute on the passed item
    pub fn method_is_safe(&mut self, tcx: &ty::ctxt, id: DefId, name: &str, unknown_assume: bool) -> bool
    {
        debug!("{}Checking method {:?} (A {})", Indent(self.lvl), id, unknown_assume);
        self.lvl += 1;
        let rv = if id.krate == 0 {
                self.crate_method_is_safe(tcx, id.node, name, unknown_assume)
            }
            else {
                for a in tcx.get_attrs(id).iter()
                {
                    if a.check_name("tag_safe") {
                        if a.meta_item_list().iter().flat_map(|a| a.iter()).any(|a| a.name() == name) {
                            return true;
                        }
                    }
                    if a.check_name("tag_unsafe") {
                        if a.meta_item_list().iter().flat_map(|a| a.iter()).any(|a| a.name() == name) {
                            return false;
                        }
                    }
                }
                warn!("TODO: Crate ID non-zero {:?} (assuming safe)", id);
                // TODO: Check the crate import for an annotation
                true
            };
        self.lvl -= 1;
        debug!("{}Checking method {:?} = {}", Indent(self.lvl), id, rv);
        rv
    }
}

impl<'a, 'tcx: 'a, F: FnMut(&Span)> visit::Visitor<'a> for Visitor<'a,'tcx, F>
{
    // Locate function/method calls in a code block
    // - uses visit_expr_post because it doesn't _need_ to do anything
    fn visit_expr_post(&mut self, ex: &'a hir::Expr) {
        match ex.node
        {
        // Call expressions - check that it's a path call
        hir::ExprCall(ref fcn, _) =>
            match fcn.node
            {
            hir::ExprPath(ref _qs, ref _p) => {
                    if let def::DefFn(did, _) = self.tcx.resolve_expr(&fcn) {
                        // Check for a safety tag
                        if !self.pass.method_is_safe(self.tcx, did, self.name, self.unknown_assume)
                        {
                            (self.cb)(&ex.span);
                        }
                    }
                },
            _ => {},
            },

        // Method call expressions - get the relevant method
        hir::ExprMethodCall(ref _id, ref _tys, ref _exprs) =>
            {
                let tables = self.tcx.tables.borrow();
                let mm = &tables.method_map;

                let callee = mm.get( &ty::MethodCall::expr(ex.id) ).unwrap();
                let id = callee.def_id;

                //if let ty::MethodStatic(id) = callee.origin {
                        // Check for a safety tag
                        if !self.pass.method_is_safe(self.tcx, id, self.name, self.unknown_assume) {
                            (self.cb)(&ex.span);
                        }
                //}
            },

        // Ignore any other type of node
        _ => {},
        }
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    use syntax::feature_gate::AttributeType;
    reg.register_late_lint_pass( Box::new(Pass::default()) );

    reg.register_attribute(String::from("tag_safe"),   AttributeType::Whitelisted);
    reg.register_attribute(String::from("tag_unsafe"), AttributeType::Whitelisted);
}

// vim: ts=4 expandtab sw=4
<commit_msg>Update from rust-lang/rust#28742<commit_after>// tag_safe
//
// A linting plugin to flag calls to methods not marked "tag_safe"
// from methods marked "tag_safe".
//
// Author: John Hodge (thePowersGang/Mutabah)
//
// TODO: Support '#[tag_unsafe(type)]' which is used when a method has no marker
// - Allows default safe fallback, with upwards propagation.
//
#![crate_name="tag_safe"]
#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private)]

#[macro_use]
extern crate log;

extern crate syntax;
#[macro_use]
extern crate rustc;

extern crate rustc_front;

use syntax::ast;
use rustc::middle::def_id::DefId;
use rustc_front::visit;
use syntax::codemap::Span;
use rustc::lint::{self, LintContext, LintPass, LateLintPass, LintArray};
use rustc::plugin::Registry;
use rustc::middle::{def,ty};
use rustc_front::hir;
use syntax::attr::AttrMetaMethods;

declare_lint!(NOT_TAGGED_SAFE, Warn, "Warn about use of non-tagged methods within tagged function");

#[derive(Copy,Clone,Debug)]
enum SafetyType
{
    Safe,
    Unsafe,
    Unknown,
}

#[derive(Default)]
struct Pass
{
    /// Cache of flag types
    flag_types: Vec<String>,
    /// Node => (Type => IsSafe)
    flag_cache: ::rustc::util::nodemap::NodeMap< ::rustc::util::nodemap::FnvHashMap<usize, SafetyType> >,

    lvl: usize,
}

struct Visitor<'a, 'tcx: 'a, F: FnMut(&Span) + 'a>
{
    pass: &'a mut Pass,
    tcx: &'a ty::ctxt<'tcx>,
    name: &'a str,
    unknown_assume: bool,
    cb: F,
}

// Hack to provide indenting in debug calls
struct Indent(usize);
impl ::std::fmt::Display for Indent {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        for s in ::std::iter::repeat(" ").take(self.0) {
            try!(write!(f, "{}", s));
        }
        Ok( () )
    }
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NOT_TAGGED_SAFE)
    }
}

impl LateLintPass for Pass {
    fn check_fn(&mut self, cx: &lint::LateContext, _kind: ::rustc_front::visit::FnKind, _decl: &hir::FnDecl, body: &hir::Block, _: Span, id: ast::NodeId) {
        let attrs = cx.tcx.map.attrs(id);
        for ty in attrs.iter()
            .filter(|a| a.check_name("tag_safe"))
            .filter_map(|a| a.meta_item_list())
            .flat_map(|x| x.iter())
        {
            // Search body for calls to non safe methods
            let mut v = Visitor{
                    pass: self, tcx: cx.tcx, name: &ty.name(),
                    // - Assumes an untagged method is unsafe
                    unknown_assume: false,
                    cb: |span| {
                            cx.span_lint(NOT_TAGGED_SAFE, *span,
                                &format!("Calling {}-unsafe method from a #[tag_safe({})] method", ty.name(), ty.name())[..]
                                );
                        },
                    };
            debug!("Method {:?} is marked safe '{}'", id, ty.name());
            visit::walk_block(&mut v, body);
        }
    }
}

impl Pass
{
    // Searches for the relevant marker
    fn check_for_marker(tcx: &ty::ctxt, id: ast::NodeId, marker: &str, name: &str) -> bool
    {
        debug!("Checking for marker {}({}) on {:?}", marker, name, id);
        tcx.map.attrs(id).iter()
            .filter_map( |a| if a.check_name(marker) { a.meta_item_list() } else { None })
            .flat_map(|x| x.iter())
            .any(|a| a.name() == name)
    }

    /// Recursively check that the provided function is either safe or unsafe.
    // Used to avoid excessive annotating
    fn recurse_fcn_body(&mut self, tcx: &ty::ctxt, node_id: ast::NodeId, name_id: usize, name: &str, unknown_assume: bool) -> bool
    {
        // Cache this method as unknown (to prevent infinite recursion)
        self.flag_cache.entry(node_id)
            .or_insert(Default::default())
            .insert(name_id, SafetyType::Unknown)
            ;

        // and apply a visitor to all
        match tcx.map.get(node_id)
        {
        rustc::front::map::NodeItem(i) =>
            match i.node {
            hir::ItemFn(_, _, _, _, _, ref body) => {
                // Enumerate this function's code, recursively checking for a call to an unsafe method
                let mut is_safe = true;
                {
                    let mut v = Visitor {
                        pass: self, tcx: tcx, name: name,
                        unknown_assume: true,
                        cb: |_| { is_safe = false; }
                        };
                    visit::walk_block(&mut v, body);
                }
                is_safe
                },
            _ => unknown_assume,
            },
        rustc::front::map::NodeImplItem(i) =>
            match i.node {
            hir::MethodImplItem(_, ref body) => {
                let mut is_safe = true;
                {
                    let mut v = Visitor {
                        pass: self, tcx: tcx, name: name,
                        unknown_assume: true,
                        cb: |_| { is_safe = false; }
                        };
                    visit::walk_block(&mut v, body);
                }
                is_safe
                },
            _ => unknown_assume,
            },
        rustc::front::map::NodeForeignItem(i) =>
            if Self::check_for_marker(tcx, i.id, "tag_safe", name) {
                true
            }
            else if Self::check_for_marker(tcx, i.id, "tag_unsafe", name) {
                false
            }
            else {
                unknown_assume
            },
        v @ _ => {
            error!("Node ID {} points to non-item {:?}", node_id, v);
            unknown_assume
            }
        }
    }

    /// Check that a method within this crate is safe with the provided tag
    fn crate_method_is_safe(&mut self, tcx: &ty::ctxt, node_id: ast::NodeId, name: &str, unknown_assume: bool) -> bool
    {
        // Obtain tag name ID (avoids storing a string in the map)
        let name_id =
            match self.flag_types.iter().position(|a| *a == name)
            {
            Some(v) => v,
            None => {
                self.flag_types.push( String::from(name) );
                self.flag_types.len() - 1
                },
            };

        // Check cache first
        if let Some(&st) = self.flag_cache.get(&node_id).and_then(|a| a.get(&name_id))
        {
            match st
            {
            SafetyType::Safe => true,
            SafetyType::Unsafe => false,
            SafetyType::Unknown => unknown_assume,
            }
        }
        else
        {
            // Search for a safety marker, possibly recursing
            let is_safe =
                if Self::check_for_marker(tcx, node_id, "tag_safe", name) {
                    true
                }
                else if Self::check_for_marker(tcx, node_id, "tag_unsafe", name) {
                    false
                }
                else {
                    self.recurse_fcn_body(tcx, node_id, name_id, name, unknown_assume)
                };
            // Save resultant value
            self.flag_cache.entry(node_id)
                .or_insert(Default::default())
                .insert(name_id, if is_safe { SafetyType::Safe } else { SafetyType::Unsafe })
                ;
            is_safe
        }
    }

    /// Locate a #[tag_safe(<name>)] attribute on the passed item
    pub fn method_is_safe(&mut self, tcx: &ty::ctxt, id: DefId, name: &str, unknown_assume: bool) -> bool
    {
        debug!("{}Checking method {:?} (A {})", Indent(self.lvl), id, unknown_assume);
        self.lvl += 1;
        let rv = if id.krate == 0 {
                self.crate_method_is_safe(tcx, tcx.map.as_local_node_id(id).unwrap(), name, unknown_assume)
            }
            else {
                for a in tcx.get_attrs(id).iter()
                {
                    if a.check_name("tag_safe") {
                        if a.meta_item_list().iter().flat_map(|a| a.iter()).any(|a| a.name() == name) {
                            return true;
                        }
                    }
                    if a.check_name("tag_unsafe") {
                        if a.meta_item_list().iter().flat_map(|a| a.iter()).any(|a| a.name() == name) {
                            return false;
                        }
                    }
                }
                warn!("TODO: Crate ID non-zero {:?} (assuming safe)", id);
                // TODO: Check the crate import for an annotation
                true
            };
        self.lvl -= 1;
        debug!("{}Checking method {:?} = {}", Indent(self.lvl), id, rv);
        rv
    }
}

impl<'a, 'tcx: 'a, F: FnMut(&Span)> visit::Visitor<'a> for Visitor<'a,'tcx, F>
{
    // Locate function/method calls in a code block
    // - uses visit_expr_post because it doesn't _need_ to do anything
    fn visit_expr_post(&mut self, ex: &'a hir::Expr) {
        match ex.node
        {
        // Call expressions - check that it's a path call
        hir::ExprCall(ref fcn, _) =>
            match fcn.node
            {
            hir::ExprPath(ref _qs, ref _p) => {
                    if let def::DefFn(did, _) = self.tcx.resolve_expr(&fcn) {
                        // Check for a safety tag
                        if !self.pass.method_is_safe(self.tcx, did, self.name, self.unknown_assume)
                        {
                            (self.cb)(&ex.span);
                        }
                    }
                },
            _ => {},
            },

        // Method call expressions - get the relevant method
        hir::ExprMethodCall(ref _id, ref _tys, ref _exprs) =>
            {
                let tables = self.tcx.tables.borrow();
                let mm = &tables.method_map;

                let callee = mm.get( &ty::MethodCall::expr(ex.id) ).unwrap();
                let id = callee.def_id;

                //if let ty::MethodStatic(id) = callee.origin {
                        // Check for a safety tag
                        if !self.pass.method_is_safe(self.tcx, id, self.name, self.unknown_assume) {
                            (self.cb)(&ex.span);
                        }
                //}
            },

        // Ignore any other type of node
        _ => {},
        }
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    use syntax::feature_gate::AttributeType;
    reg.register_late_lint_pass( Box::new(Pass::default()) );

    reg.register_attribute(String::from("tag_safe"),   AttributeType::Whitelisted);
    reg.register_attribute(String::from("tag_unsafe"), AttributeType::Whitelisted);
}

// vim: ts=4 expandtab sw=4
<|endoftext|>