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

//!
//! # Regular patterns
//!
//! This provides a data structure, `Pattern<Symbol>` representing a matching pattern in a regular language. This is a
//! more generalised form of a regular expression as it supports symbol types other than simple strings. A pattern using
//! the `char` symbol has identical expressive power to a regular expression.
//!
//! Regular patterns can be created from strings, arrays or vectors using `into_pattern`, and can use any cloneable type
//! to represent a symbol:
//!
//! ```
//! # use ndfa::*;
//! let match_abc = "abc".into_pattern();
//! let match_123 = [1,2,3].into_pattern();
//! ```
//!
//! These patterns are quite boring (they just match exactly the string that's passed in). To create more interesting
//! patterns, there are a series of functions that will create patterns with repetitions or other constructs in them:
//!
//! ```
//! # use ndfa::*;
//! let stuff_or_nonsense = "stuff".or("nonsense");
//! let any_amount_of_stuff = "stuff".repeat_forever(1);
//! let went_to_market = "piggies".repeat(0..5);
//! ```
//!
//! For convenience, these methods will work on any type that can be converted into a pattern. Every regular expression
//! can be converted into a regular pattern, but these patterns are also for symbol types other than characters, and do
//! not require any quoting in order to be used (and are hence much easier to use with dynamic values).
//!
//! ```
//! # use ndfa::*;
//! let some_counting = vec![1, 2, 3].repeat_forever(1);
//! ```
//!

use std::iter::FromIterator;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait ToPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn to_pattern(&self) -> Pattern<Symbol>;
}

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

impl<Symbol> IntoPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<Symbol> IntoPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        *self
    }
}

impl<'a, Symbol: Clone, PatternType: ToPattern<Symbol>> IntoPattern<Symbol> for &'a PatternType {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a [Symbol] {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a> IntoPattern<char> for &'a str {
    #[inline]
    fn into_pattern(self) -> Pattern<char> {
        self.to_pattern()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        (**self).clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Vec<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.clone())
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for [Symbol] {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.to_vec())
    }
}

impl ToPattern<char> for str {
    #[inline]
    fn to_pattern(&self) -> Pattern<char> {
        Match(Vec::from_iter(self.chars()))
    }
}

///
/// Implemented by things that can modify existing patterns into other forms
///
/// Pattern transformers act by altering a single pattern object into a new form
///
pub trait PatternTransformer<Symbol> {
    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

///
/// Implemented by things that combine patterns together to create new patterns
///
pub trait PatternCombiner<Symbol, SecondPattern: IntoPattern<Symbol>> {
    /// Appends a pattern to this one
    fn append(self, pattern: SecondPattern) -> Pattern<Symbol>;

    /// Matches either this pattern or the specified pattern
    fn or(self, pattern: SecondPattern) -> Pattern<Symbol>;
}

impl<Symbol> Pattern<Symbol> {

}

impl<Symbol, PatternType: IntoPattern<Symbol>> PatternTransformer<Symbol> for PatternType {
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol> {
        RepeatInfinite(min_count, Box::new(self.into_pattern()))
    }

    fn repeat(self, count: Range<u32>) -> Pattern<Symbol> {
        Repeat(count, Box::new(self.into_pattern()))
    }
}

impl<Symbol: Clone, PatternType: IntoPattern<Symbol>, SecondPatternType: IntoPattern<Symbol>> PatternCombiner<Symbol, SecondPatternType> for PatternType {
    fn append(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'Match(x)' and 'Match(y)' should produce 'Match(xy)'
            (Match(first_string), Match(second_string)) => Match(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (MatchAll(first_string), MatchAll(second_string)) => MatchAll(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'y' should produce 'MatchAll(xy)'
            (MatchAll(first_string), second) => {
                let mut result = first_string.clone();
                result.push(second);
                MatchAll(result)
            },

            // Combining 'x' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (first, MatchAll(second_string)) => {
                let mut result: Vec<Pattern<Symbol>> = vec![first];
                for p in second_string {
                    result.push(p.clone());
                }
                MatchAll(result)
            },

            // Everything else is just MatchAll(xy)
            (first, second) => MatchAll(vec![first, second])
        }
    }

    fn or(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'MatchAny(x)' and 'MatchAny(y)' should produce 'MatchAny(xy)'
            (MatchAny(first_string), MatchAny(second_string)) => MatchAny(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Everything else is just MatchAny(xy)
            (first, second) => MatchAny(vec![first, second])
        }
    }
}

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

    #[test]
    fn can_convert_vec_to_pattern() {
        let pattern = vec![0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }

    #[test]
    fn can_repeat_pattern() {
        let pattern = "abc".repeat(1..2);

        assert!(pattern == Repeat(1..2, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_repeat_pattern_forever() {
        let pattern = "abc".repeat_forever(0);

        assert!(pattern == RepeatInfinite(0, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_append_pattern_combine_matches() {
        let pattern = "abc".append("def");

        assert!(pattern == Match(vec!['a', 'b', 'c', 'd', 'e', 'f']));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_left() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append("def");

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_right() {
        let pattern = "abc".append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_both() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_not_matchall_or_match() {
        let pattern: Pattern<char> = MatchAny(vec![Epsilon]).append(MatchAny(vec![Epsilon]));

        assert!(pattern == MatchAll(vec![MatchAny(vec![Epsilon]), MatchAny(vec![Epsilon])]));
    }

    #[test]
    fn can_or_pattern() {
        let pattern = "abc".or("def");

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_or_pattern_combine_matchanys() {
        let pattern = MatchAny(vec!["abc".to_pattern()]).or(MatchAny(vec!["def".to_pattern()]));

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }
}
<commit_msg>This will be a function for compiling patterns<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Regular patterns
//!
//! This provides a data structure, `Pattern<Symbol>` representing a matching pattern in a regular language. This is a
//! more generalised form of a regular expression as it supports symbol types other than simple strings. A pattern using
//! the `char` symbol has identical expressive power to a regular expression.
//!
//! Regular patterns can be created from strings, arrays or vectors using `into_pattern`, and can use any cloneable type
//! to represent a symbol:
//!
//! ```
//! # use ndfa::*;
//! let match_abc = "abc".into_pattern();
//! let match_123 = [1,2,3].into_pattern();
//! ```
//!
//! These patterns are quite boring (they just match exactly the string that's passed in). To create more interesting
//! patterns, there are a series of functions that will create patterns with repetitions or other constructs in them:
//!
//! ```
//! # use ndfa::*;
//! let stuff_or_nonsense = "stuff".or("nonsense");
//! let any_amount_of_stuff = "stuff".repeat_forever(1);
//! let went_to_market = "piggies".repeat(0..5);
//! ```
//!
//! For convenience, these methods will work on any type that can be converted into a pattern. Every regular expression
//! can be converted into a regular pattern, but these patterns are also for symbol types other than characters, and do
//! not require any quoting in order to be used (and are hence much easier to use with dynamic values).
//!
//! ```
//! # use ndfa::*;
//! let some_counting = vec![1, 2, 3].repeat_forever(1);
//! ```
//!

use std::iter::FromIterator;
use std::ops::Range;

use super::state_machine::*;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

impl<Symbol> Pattern<Symbol> {
    ///
    /// Compiles this pattern onto a state machine, returning the accepting symbol
    ///
    pub fn compile<OutputSymbol>(&self, state_machine: &mut MutableStateMachine<Symbol, OutputSymbol>, start_state: StateId) -> StateId {
        unimplemented!()
    }
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait ToPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn to_pattern(&self) -> Pattern<Symbol>;
}

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

impl<Symbol> IntoPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<Symbol> IntoPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        *self
    }
}

impl<'a, Symbol: Clone, PatternType: ToPattern<Symbol>> IntoPattern<Symbol> for &'a PatternType {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a [Symbol] {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a> IntoPattern<char> for &'a str {
    #[inline]
    fn into_pattern(self) -> Pattern<char> {
        self.to_pattern()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        (**self).clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Vec<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.clone())
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for [Symbol] {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.to_vec())
    }
}

impl ToPattern<char> for str {
    #[inline]
    fn to_pattern(&self) -> Pattern<char> {
        Match(Vec::from_iter(self.chars()))
    }
}

///
/// Implemented by things that can modify existing patterns into other forms
///
/// Pattern transformers act by altering a single pattern object into a new form
///
pub trait PatternTransformer<Symbol> {
    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

///
/// Implemented by things that combine patterns together to create new patterns
///
pub trait PatternCombiner<Symbol, SecondPattern: IntoPattern<Symbol>> {
    /// Appends a pattern to this one
    fn append(self, pattern: SecondPattern) -> Pattern<Symbol>;

    /// Matches either this pattern or the specified pattern
    fn or(self, pattern: SecondPattern) -> Pattern<Symbol>;
}

impl<Symbol> Pattern<Symbol> {

}

impl<Symbol, PatternType: IntoPattern<Symbol>> PatternTransformer<Symbol> for PatternType {
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol> {
        RepeatInfinite(min_count, Box::new(self.into_pattern()))
    }

    fn repeat(self, count: Range<u32>) -> Pattern<Symbol> {
        Repeat(count, Box::new(self.into_pattern()))
    }
}

impl<Symbol: Clone, PatternType: IntoPattern<Symbol>, SecondPatternType: IntoPattern<Symbol>> PatternCombiner<Symbol, SecondPatternType> for PatternType {
    fn append(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'Match(x)' and 'Match(y)' should produce 'Match(xy)'
            (Match(first_string), Match(second_string)) => Match(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (MatchAll(first_string), MatchAll(second_string)) => MatchAll(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'y' should produce 'MatchAll(xy)'
            (MatchAll(first_string), second) => {
                let mut result = first_string.clone();
                result.push(second);
                MatchAll(result)
            },

            // Combining 'x' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (first, MatchAll(second_string)) => {
                let mut result: Vec<Pattern<Symbol>> = vec![first];
                for p in second_string {
                    result.push(p.clone());
                }
                MatchAll(result)
            },

            // Everything else is just MatchAll(xy)
            (first, second) => MatchAll(vec![first, second])
        }
    }

    fn or(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'MatchAny(x)' and 'MatchAny(y)' should produce 'MatchAny(xy)'
            (MatchAny(first_string), MatchAny(second_string)) => MatchAny(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Everything else is just MatchAny(xy)
            (first, second) => MatchAny(vec![first, second])
        }
    }
}

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

    #[test]
    fn can_convert_vec_to_pattern() {
        let pattern = vec![0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }

    #[test]
    fn can_repeat_pattern() {
        let pattern = "abc".repeat(1..2);

        assert!(pattern == Repeat(1..2, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_repeat_pattern_forever() {
        let pattern = "abc".repeat_forever(0);

        assert!(pattern == RepeatInfinite(0, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_append_pattern_combine_matches() {
        let pattern = "abc".append("def");

        assert!(pattern == Match(vec!['a', 'b', 'c', 'd', 'e', 'f']));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_left() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append("def");

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_right() {
        let pattern = "abc".append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_both() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_not_matchall_or_match() {
        let pattern: Pattern<char> = MatchAny(vec![Epsilon]).append(MatchAny(vec![Epsilon]));

        assert!(pattern == MatchAll(vec![MatchAny(vec![Epsilon]), MatchAny(vec![Epsilon])]));
    }

    #[test]
    fn can_or_pattern() {
        let pattern = "abc".or("def");

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_or_pattern_combine_matchanys() {
        let pattern = MatchAny(vec!["abc".to_pattern()]).or(MatchAny(vec!["def".to_pattern()]));

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }
}
<|endoftext|>


<commit_before>use config::{Config, ConfigError, File, FileFormat, Source, Value};
use failure::ResultExt;
use serde::Deserialize;
use slog_scope::{info, warn};
use std::collections::HashMap;
use std::convert::TryFrom;
use std::path::PathBuf;
use structopt::StructOpt;

use crate::osm_reader::poi;
use crate::Error;

#[derive(Debug, Clone, Deserialize)]
pub struct StreetExclusion {
    pub highways: Option<Vec<String>>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Street {
    pub import: bool,
    pub exclusion: StreetExclusion,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Admin {
    pub import: bool,
    pub levels: Vec<u32>,
    pub city_level: u32,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Poi {
    pub import: bool,
    pub config: Option<poi::PoiConfig>,
}

#[cfg(feature = "db-storage")]
#[derive(Debug, Clone, Deserialize)]
pub struct Database {
    pub file: PathBuf,
    pub buffer_size: usize,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Elasticsearch {
    pub connection_string: String,
    pub insert_thread_count: usize,
    pub streets_shards: usize,
    pub streets_replicas: usize,
    pub admins_shards: usize,
    pub admins_replicas: usize,
    pub pois_shards: usize,
    pub pois_replicas: usize,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Settings {
    pub dataset: String,
    #[cfg(feature = "db-storage")]
    pub database: Option<Database>,
    pub elasticsearch: Elasticsearch,
    pub street: Option<Street>,
    pub poi: Option<Poi>,
    pub admin: Option<Admin>,
}

impl Settings {
    // To create settings, we first retrieve default settings, merge in specific settings if
    // needed, and finally override them with command line arguments.
    pub fn new(args: Args) -> Result<Self, Error> {
        let config_dir = args.config_dir.clone();
        let settings = args.settings.clone();

        let mut config = Config::new();
        // let config_dir = config_dir.clone();
        match config_dir {
            Some(mut dir) => {
                // Start off by merging in the "default" configuration file
                dir.push("osm2mimir-default");

                if let Some(path) = dir.to_str() {
                    info!("using configuration from {}", path);
                    // Now if the file exists, we read it, otherwise, we
                    // read from the compiled version.
                    if dir.exists() {
                        config.merge(File::with_name(path)).with_context(|e| {
                            format!(
                                "Could not merge default configuration from file {}: {}",
                                path, e
                            )
                        })?;
                    } else {
                        config
                            .merge(File::from_str(
                                include_str!("../../config/osm2mimir-default.toml"),
                                FileFormat::Toml,
                            ))
                            .with_context(|e| {
                                format!(
                                    "Could not merge default configuration from file {}: {}",
                                    path, e
                                )
                            })?;
                    }
                } else {
                    return Err(failure::err_msg(format!(
                        "Could not read default settings in '{}'",
                        dir.display()
                    )));
                }

                dir.pop(); // remove the default
                           // If we provided a special configuration, merge it.
                if let Some(settings) = settings {
                    dir.push(&settings);

                    if let Some(path) = dir.to_str() {
                        info!("using configuration from {}", path);
                        config
                            .merge(File::with_name(path).required(true))
                            .with_context(|e| {
                                format!(
                                    "Could not merge {} configuration in file {}: {}",
                                    settings, path, e
                                )
                            })?;
                    } else {
                        return Err(failure::err_msg(format!(
                            "Could not read configuration for '{}'",
                            settings,
                        )));
                    }
                    dir.pop();
                }
            }
            None => {
                if settings.is_some() {
                    // If the user set the 'settings' at the command line, he should
                    // also have used the 'config_dir' option. So we issue a warning,
                    // and leave with an error because the expected configuration can
                    // not be read.
                    warn!("settings option used without the 'config_dir' option. Please set the config directory with --config-dir.");
                    return Err(failure::err_msg(String::from(
                        "Could not build program settings",
                    )));
                }
                config
                    .merge(File::from_str(
                        include_str!("../../config/osm2mimir-default.toml"),
                        FileFormat::Toml,
                    ))
                    .with_context(|e| {
                        format!(
                            "Could not merge default configuration from file at compile time: {}",
                            e
                        )
                    })?;
            }
        }

        // Now override with command line values
        config
            .merge(args)
            .with_context(|e| format!("Could not merge arguments into configuration: {}", e))?;

        // You can deserialize (and thus freeze) the entire configuration as
        config.try_into().map_err(|e| {
            failure::err_msg(format!(
                "Could not generate settings from configuration: {}",
                e
            ))
        })
    }
}

#[derive(StructOpt, Clone, Debug)]
pub struct Args {
    /// OSM PBF file.
    #[structopt(short = "i", long = "input", parse(from_os_str))]
    pub input: PathBuf,
    /// Admin levels to keep.
    #[structopt(short = "l", long = "level")]
    level: Option<Vec<u32>>,
    /// City level to  calculate weight.
    #[structopt(short = "C", long = "city-level")]
    city_level: Option<u32>,
    /// Elasticsearch parameters.
    #[structopt(short = "c", long = "connection-string")]
    connection_string: Option<String>,
    /// Import ways.
    #[structopt(short = "w", long = "import-way")]
    import_way: Option<bool>,
    /// Don't import ways.
    #[structopt(long = "no-import-way")]
    no_import_way: Option<bool>,
    /// Import admins.
    #[structopt(short = "a", long = "import-admin")]
    import_admin: Option<bool>,
    /// Don't import admins.
    #[structopt(long = "no-import-admin")]
    no_import_admin: Option<bool>,
    /// Import POIs.
    #[structopt(short = "p", long = "import-poi")]
    import_poi: Option<bool>,
    /// Don't import POIs.
    #[structopt(long = "--no-import-poi")]
    no_import_poi: Option<bool>,
    /// Name of the dataset.
    #[structopt(short = "d", long = "dataset")]
    pub dataset: Option<String>,
    /// Number of shards for the admin es index
    #[structopt(long = "nb-admin-shards")]
    nb_admin_shards: Option<usize>,
    /// Number of replicas for the es index
    #[structopt(long = "nb-admin-replicas")]
    nb_admin_replicas: Option<usize>,
    /// Number of shards for the street es index
    #[structopt(long = "nb-street-shards")]
    nb_street_shards: Option<usize>,
    /// Number of replicas for the street es index
    #[structopt(long = "nb-street-replicas")]
    nb_street_replicas: Option<usize>,
    /// Number of shards for the es index
    #[structopt(long = "nb-poi-shards")]
    nb_poi_shards: Option<usize>,
    /// Number of replicas for the es index
    #[structopt(long = "nb-poi-replicas")]
    nb_poi_replicas: Option<usize>,
    /// If you use this option by providing a filename, then we
    /// will use a SQlite database that will be persisted. You
    /// can only do that if osm2mimir was compiled with the
    /// 'db-storage' feature. If you don't provide a value, then
    /// we will use in memory storage.
    #[cfg(feature = "db-storage")]
    #[structopt(long = "db-file", parse(from_os_str))]
    pub db_file: Option<PathBuf>,

    /// DB buffer size.
    #[cfg(feature = "db-storage")]
    #[structopt(long = "db-buffer-size")]
    pub db_buffer_size: Option<usize>,
    /// Number of threads to use to insert into Elasticsearch. Note that Elasticsearch is not able
    /// to handle values that are too high.
    #[structopt(short = "T", long = "nb-insert-threads")]
    nb_insert_threads: Option<usize>,

    /// Path to the config directory
    /// osm2mimir will read the default configuration in there, and maybe
    /// more depending on the settings option.
    /// If no option is given, we'll just read the ./config/osm2mimir-default.toml
    /// at compile time.
    #[structopt(short = "D", long = "config-dir")]
    config_dir: Option<PathBuf>,

    /// Specific configuration, on top of the default ones.
    /// You should provide the basename of the file, eg acme, so that
    /// osm2mimir will use {config-dir}/acme.toml. (Requires config_dir to
    /// be set)
    #[structopt(short = "s", long = "settings")]
    settings: Option<String>,
}

impl Source for Args {
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
        Box::new((*self).clone())
    }

    fn collect(&self) -> Result<HashMap<String, Value>, ConfigError> {
        let mut m = HashMap::new();

        // DATASET
        if let Some(dataset) = self.dataset.clone() {
            m.insert(String::from("dataset"), Value::new(None, dataset));
        }

        // ADMIN
        if self.import_admin.is_some() {
            m.insert(String::from("admin.import"), Value::new(None, true));
        } else if self.no_import_admin.is_some() {
            m.insert(String::from("admin.import"), Value::new(None, false));
        }

        if let Some(city_level) = self.city_level {
            m.insert(
                String::from("admin.city_level"),
                Value::new(
                    None,
                    i64::try_from(city_level).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert admin city_level to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }
        if let Some(level) = self.level.clone() {
            m.insert(
                String::from("admin.levels"),
                Value::new(
                    None,
                    level.into_iter().try_fold(Vec::new(), |mut acc, l| {
                        let i = i64::try_from(l).map_err(|e| {
                            ConfigError::Message(format!(
                                "Could not convert admin city_level to integer: {}",
                                e
                            ))
                        })?;
                        acc.push(i);
                        Ok(acc)
                    })?,
                ),
            );
        }

        // WAY
        if self.import_way.is_some() {
            m.insert(String::from("street.import"), Value::new(None, true));
        } else if self.no_import_way.is_some() {
            m.insert(String::from("street.import"), Value::new(None, false));
        }

        // POI
        if self.import_poi.is_some() {
            m.insert(String::from("poi.import"), Value::new(None, true));
        } else if self.no_import_poi.is_some() {
            m.insert(String::from("poi.import"), Value::new(None, false));
        }

        // ELASTICSEARCH SETTINGS

        if let Some(connection_string) = self.connection_string.clone() {
            m.insert(
                String::from("elasticsearch.connection_string"),
                Value::new(None, connection_string),
            );
        }

        if let Some(nb_way_shards) = self.nb_street_shards {
            m.insert(
                String::from("elasticsearch.streets_shards"),
                Value::new(
                    None,
                    i64::try_from(nb_way_shards).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert count of streets shards to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        if let Some(nb_way_replicas) = self.nb_street_replicas {
            m.insert(
                String::from("elasticsearch.streets_replicas"),
                Value::new(
                    None,
                    i64::try_from(nb_way_replicas).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert count of way replicas to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        if let Some(nb_poi_shards) = self.nb_poi_shards {
            m.insert(
                String::from("elasticsearch.pois_shards"),
                Value::new(
                    None,
                    i64::try_from(nb_poi_shards).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert count of poi shards to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        if let Some(nb_poi_replicas) = self.nb_poi_replicas {
            m.insert(
                String::from("elasticsearch.pois_replicas"),
                Value::new(
                    None,
                    i64::try_from(nb_poi_replicas).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert count of poi replicas to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        if let Some(nb_admin_shards) = self.nb_admin_shards {
            m.insert(
                String::from("elasticsearch.admins_shards"),
                Value::new(
                    None,
                    i64::try_from(nb_admin_shards).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert count of admin shards to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        if let Some(nb_admin_replicas) = self.nb_admin_replicas {
            m.insert(
                String::from("elasticsearch.admins_replicas"),
                Value::new(
                    None,
                    i64::try_from(nb_admin_replicas).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert count of admin replicas to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        if let Some(nb_insert_threads) = self.nb_insert_threads {
            m.insert(
                String::from("elasticsearch.insert_thread_count"),
                Value::new(
                    None,
                    i64::try_from(nb_insert_threads).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert elasticsearch insert thread count to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        // DATABASE
        #[cfg(feature = "db-storage")]
        if let Some(db_file) = self.db_file.clone() {
            m.insert(
                String::from("database.file"),
                Value::new(None, db_file.to_str().expect("valid utf-8 filename")),
            );
        }

        #[cfg(feature = "db-storage")]
        if let Some(db_buffer_size) = self.db_buffer_size {
            m.insert(
                String::from("database.buffer_size"),
                Value::new(
                    None,
                    i64::try_from(db_buffer_size).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert database buffer size to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        Ok(m)
    }
}
<commit_msg>[Fixed] Revert to single import flag<commit_after>use config::{Config, ConfigError, File, FileFormat, Source, Value};
use failure::ResultExt;
use serde::Deserialize;
use slog_scope::{info, warn};
use std::collections::HashMap;
use std::convert::TryFrom;
use std::path::PathBuf;
use structopt::StructOpt;

use crate::osm_reader::poi;
use crate::Error;

#[derive(Debug, Clone, Deserialize)]
pub struct StreetExclusion {
    pub highways: Option<Vec<String>>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Street {
    pub import: bool,
    pub exclusion: StreetExclusion,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Admin {
    pub import: bool,
    pub levels: Vec<u32>,
    pub city_level: u32,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Poi {
    pub import: bool,
    pub config: Option<poi::PoiConfig>,
}

#[cfg(feature = "db-storage")]
#[derive(Debug, Clone, Deserialize)]
pub struct Database {
    pub file: PathBuf,
    pub buffer_size: usize,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Elasticsearch {
    pub connection_string: String,
    pub insert_thread_count: usize,
    pub streets_shards: usize,
    pub streets_replicas: usize,
    pub admins_shards: usize,
    pub admins_replicas: usize,
    pub pois_shards: usize,
    pub pois_replicas: usize,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Settings {
    pub dataset: String,
    #[cfg(feature = "db-storage")]
    pub database: Option<Database>,
    pub elasticsearch: Elasticsearch,
    pub street: Option<Street>,
    pub poi: Option<Poi>,
    pub admin: Option<Admin>,
}

impl Settings {
    // To create settings, we first retrieve default settings, merge in specific settings if
    // needed, and finally override them with command line arguments.
    pub fn new(args: Args) -> Result<Self, Error> {
        let config_dir = args.config_dir.clone();
        let settings = args.settings.clone();

        let mut config = Config::new();
        // let config_dir = config_dir.clone();
        match config_dir {
            Some(mut dir) => {
                // Start off by merging in the "default" configuration file
                dir.push("osm2mimir-default");

                if let Some(path) = dir.to_str() {
                    info!("using configuration from {}", path);
                    // Now if the file exists, we read it, otherwise, we
                    // read from the compiled version.
                    if dir.exists() {
                        config.merge(File::with_name(path)).with_context(|e| {
                            format!(
                                "Could not merge default configuration from file {}: {}",
                                path, e
                            )
                        })?;
                    } else {
                        config
                            .merge(File::from_str(
                                include_str!("../../config/osm2mimir-default.toml"),
                                FileFormat::Toml,
                            ))
                            .with_context(|e| {
                                format!(
                                    "Could not merge default configuration from file {}: {}",
                                    path, e
                                )
                            })?;
                    }
                } else {
                    return Err(failure::err_msg(format!(
                        "Could not read default settings in '{}'",
                        dir.display()
                    )));
                }

                dir.pop(); // remove the default
                           // If we provided a special configuration, merge it.
                if let Some(settings) = settings {
                    dir.push(&settings);

                    if let Some(path) = dir.to_str() {
                        info!("using configuration from {}", path);
                        config
                            .merge(File::with_name(path).required(true))
                            .with_context(|e| {
                                format!(
                                    "Could not merge {} configuration in file {}: {}",
                                    settings, path, e
                                )
                            })?;
                    } else {
                        return Err(failure::err_msg(format!(
                            "Could not read configuration for '{}'",
                            settings,
                        )));
                    }
                    dir.pop();
                }
            }
            None => {
                if settings.is_some() {
                    // If the user set the 'settings' at the command line, he should
                    // also have used the 'config_dir' option. So we issue a warning,
                    // and leave with an error because the expected configuration can
                    // not be read.
                    warn!("settings option used without the 'config_dir' option. Please set the config directory with --config-dir.");
                    return Err(failure::err_msg(String::from(
                        "Could not build program settings",
                    )));
                }
                config
                    .merge(File::from_str(
                        include_str!("../../config/osm2mimir-default.toml"),
                        FileFormat::Toml,
                    ))
                    .with_context(|e| {
                        format!(
                            "Could not merge default configuration from file at compile time: {}",
                            e
                        )
                    })?;
            }
        }

        // Now override with command line values
        config
            .merge(args)
            .with_context(|e| format!("Could not merge arguments into configuration: {}", e))?;

        // You can deserialize (and thus freeze) the entire configuration as
        config.try_into().map_err(|e| {
            failure::err_msg(format!(
                "Could not generate settings from configuration: {}",
                e
            ))
        })
    }
}

#[derive(StructOpt, Clone, Debug)]
pub struct Args {
    /// OSM PBF file.
    #[structopt(short = "i", long = "input", parse(from_os_str))]
    pub input: PathBuf,
    /// Admin levels to keep.
    #[structopt(short = "l", long = "level")]
    level: Option<Vec<u32>>,
    /// City level to  calculate weight.
    #[structopt(short = "C", long = "city-level")]
    city_level: Option<u32>,
    /// Elasticsearch parameters.
    #[structopt(short = "c", long = "connection-string")]
    connection_string: Option<String>,
    /// Import ways.
    #[structopt(short = "w", long = "import-way")]
    import_way: Option<bool>,
    /// Import admins.
    #[structopt(short = "a", long = "import-admin")]
    import_admin: Option<bool>,
    /// Import POIs.
    #[structopt(short = "p", long = "import-poi")]
    import_poi: Option<bool>,
    /// Name of the dataset.
    #[structopt(short = "d", long = "dataset")]
    pub dataset: Option<String>,
    /// Number of shards for the admin es index
    #[structopt(long = "nb-admin-shards")]
    nb_admin_shards: Option<usize>,
    /// Number of replicas for the es index
    #[structopt(long = "nb-admin-replicas")]
    nb_admin_replicas: Option<usize>,
    /// Number of shards for the street es index
    #[structopt(long = "nb-street-shards")]
    nb_street_shards: Option<usize>,
    /// Number of replicas for the street es index
    #[structopt(long = "nb-street-replicas")]
    nb_street_replicas: Option<usize>,
    /// Number of shards for the es index
    #[structopt(long = "nb-poi-shards")]
    nb_poi_shards: Option<usize>,
    /// Number of replicas for the es index
    #[structopt(long = "nb-poi-replicas")]
    nb_poi_replicas: Option<usize>,
    /// If you use this option by providing a filename, then we
    /// will use a SQlite database that will be persisted. You
    /// can only do that if osm2mimir was compiled with the
    /// 'db-storage' feature. If you don't provide a value, then
    /// we will use in memory storage.
    #[cfg(feature = "db-storage")]
    #[structopt(long = "db-file", parse(from_os_str))]
    pub db_file: Option<PathBuf>,

    /// DB buffer size.
    #[cfg(feature = "db-storage")]
    #[structopt(long = "db-buffer-size")]
    pub db_buffer_size: Option<usize>,
    /// Number of threads to use to insert into Elasticsearch. Note that Elasticsearch is not able
    /// to handle values that are too high.
    #[structopt(short = "T", long = "nb-insert-threads")]
    nb_insert_threads: Option<usize>,

    /// Path to the config directory
    /// osm2mimir will read the default configuration in there, and maybe
    /// more depending on the settings option.
    /// If no option is given, we'll just read the ./config/osm2mimir-default.toml
    /// at compile time.
    #[structopt(short = "D", long = "config-dir")]
    config_dir: Option<PathBuf>,

    /// Specific configuration, on top of the default ones.
    /// You should provide the basename of the file, eg acme, so that
    /// osm2mimir will use {config-dir}/acme.toml. (Requires config_dir to
    /// be set)
    #[structopt(short = "s", long = "settings")]
    settings: Option<String>,
}

impl Source for Args {
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
        Box::new((*self).clone())
    }

    fn collect(&self) -> Result<HashMap<String, Value>, ConfigError> {
        let mut m = HashMap::new();

        // DATASET
        if let Some(dataset) = self.dataset.clone() {
            m.insert(String::from("dataset"), Value::new(None, dataset));
        }

        // ADMIN
        if let Some(import_admin) = self.import_admin {
            m.insert(String::from("admin.import"), Value::new(None, import_admin));
        }

        if let Some(city_level) = self.city_level {
            m.insert(
                String::from("admin.city_level"),
                Value::new(
                    None,
                    i64::try_from(city_level).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert admin city_level to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }
        if let Some(level) = self.level.clone() {
            m.insert(
                String::from("admin.levels"),
                Value::new(
                    None,
                    level.into_iter().try_fold(Vec::new(), |mut acc, l| {
                        let i = i64::try_from(l).map_err(|e| {
                            ConfigError::Message(format!(
                                "Could not convert admin city_level to integer: {}",
                                e
                            ))
                        })?;
                        acc.push(i);
                        Ok(acc)
                    })?,
                ),
            );
        }

        // WAY
        if let Some(import_way) = self.import_way {
            m.insert(String::from("street.import"), Value::new(None, import_way));
        }

        // POI
        if let Some(import_poi) = self.import_poi {
            m.insert(String::from("poi.import"), Value::new(None, import_poi));
        }

        // ELASTICSEARCH SETTINGS

        if let Some(connection_string) = self.connection_string.clone() {
            m.insert(
                String::from("elasticsearch.connection_string"),
                Value::new(None, connection_string),
            );
        }

        if let Some(nb_way_shards) = self.nb_street_shards {
            m.insert(
                String::from("elasticsearch.streets_shards"),
                Value::new(
                    None,
                    i64::try_from(nb_way_shards).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert count of streets shards to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        if let Some(nb_way_replicas) = self.nb_street_replicas {
            m.insert(
                String::from("elasticsearch.streets_replicas"),
                Value::new(
                    None,
                    i64::try_from(nb_way_replicas).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert count of way replicas to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        if let Some(nb_poi_shards) = self.nb_poi_shards {
            m.insert(
                String::from("elasticsearch.pois_shards"),
                Value::new(
                    None,
                    i64::try_from(nb_poi_shards).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert count of poi shards to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        if let Some(nb_poi_replicas) = self.nb_poi_replicas {
            m.insert(
                String::from("elasticsearch.pois_replicas"),
                Value::new(
                    None,
                    i64::try_from(nb_poi_replicas).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert count of poi replicas to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        if let Some(nb_admin_shards) = self.nb_admin_shards {
            m.insert(
                String::from("elasticsearch.admins_shards"),
                Value::new(
                    None,
                    i64::try_from(nb_admin_shards).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert count of admin shards to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        if let Some(nb_admin_replicas) = self.nb_admin_replicas {
            m.insert(
                String::from("elasticsearch.admins_replicas"),
                Value::new(
                    None,
                    i64::try_from(nb_admin_replicas).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert count of admin replicas to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        if let Some(nb_insert_threads) = self.nb_insert_threads {
            m.insert(
                String::from("elasticsearch.insert_thread_count"),
                Value::new(
                    None,
                    i64::try_from(nb_insert_threads).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert elasticsearch insert thread count to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        // DATABASE
        #[cfg(feature = "db-storage")]
        if let Some(db_file) = self.db_file.clone() {
            m.insert(
                String::from("database.file"),
                Value::new(None, db_file.to_str().expect("valid utf-8 filename")),
            );
        }

        #[cfg(feature = "db-storage")]
        if let Some(db_buffer_size) = self.db_buffer_size {
            m.insert(
                String::from("database.buffer_size"),
                Value::new(
                    None,
                    i64::try_from(db_buffer_size).map_err(|e| {
                        ConfigError::Message(format!(
                            "Could not convert database buffer size to integer: {}",
                            e
                        ))
                    })?,
                ),
            );
        }

        Ok(m)
    }
}
<|endoftext|>


<commit_before>#[crate_id(name="users", vers="1.0.0", author="KokaKiwi")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) KokaKiwi <kokakiwi@kokakiwi.net>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: whoami (GNU coreutils) 8.22 */

// Allow dead code here in order to keep all fields, constants here, for consistency.
#[allow(dead_code)];

#[feature(macro_rules)];

extern mod extra;
extern mod getopts;

use std::io::print;
use std::cast;
use std::libc;
use std::os;
use std::ptr;
use std::str;

#[path = "../util.rs"]
mod util;

static DEFAULT_FILE: &'static str = "/var/run/utmp";

static UT_LINESIZE: uint = 32;
static UT_NAMESIZE: uint = 32;
static UT_HOSTSIZE: uint = 256;

static EMPTY: libc::c_short = 0;
static RUN_LVL: libc::c_short = 1;
static BOOT_TIME: libc::c_short = 2;
static NEW_TIME: libc::c_short = 3;
static OLD_TIME: libc::c_short = 4;
static INIT_PROCESS: libc::c_short = 5;
static LOGIN_PROCESS: libc::c_short = 6;
static USER_PROCESS: libc::c_short = 7;
static DEAD_PROCESS: libc::c_short = 8;
static ACCOUNTING: libc::c_short = 9;

struct c_exit_status {
    e_termination: libc::c_short,
    e_exit: libc::c_short,
}

struct c_utmp {
    ut_type: libc::c_short,
    ut_pid: libc::pid_t,
    ut_line: [libc::c_char, ..UT_LINESIZE],
    ut_id: [libc::c_char, ..4],

    ut_user: [libc::c_char, ..UT_NAMESIZE],
    ut_host: [libc::c_char, ..UT_HOSTSIZE],
    ut_exit: c_exit_status,
    ut_session: libc::c_long,
    ut_tv: libc::timeval,

    ut_addr_v6: [libc::int32_t, ..4],
    __unused: [libc::c_char, ..20],
}

extern {
    fn getutent() -> *c_utmp;
    fn getutid(ut: *c_utmp) -> *c_utmp;
    fn getutline(ut: *c_utmp) -> *c_utmp;

    fn pututline(ut: *c_utmp) -> *c_utmp;

    fn setutent();
    fn endutent();

    fn utmpname(file: *libc::c_char) -> libc::c_int;
}

static NAME: &'static str = "users";

fn main() {
    let args = os::args();
    let program = args[0].as_slice();
    let opts = ~[
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => fail!(f.to_err_msg()),
    };

    if matches.opt_present("help") {
        println!("users 1.0.0");
        println!("");
        println!("Usage:");
        println!("  {:s} [OPTION]... [FILE]", program);
        println!("");
        print(getopts::usage("Output who is currently logged in according to FILE.", opts));
        return;
    }

    if matches.opt_present("version") {
        println!("users 1.0.0");
        return;
    }

    let mut filename = DEFAULT_FILE;
    if matches.free.len() > 0 {
        filename = matches.free[0].as_slice();
    }

    exec(filename);
}

fn exec(filename: &str) {
    filename.with_c_str(|filename| {
        unsafe {
            utmpname(filename);
        }
    });

    let mut users: ~[~str] = ~[];

    unsafe {
        setutent();

        loop {
            let line = getutent();

            if line == ptr::null() {
                break;
            }

            if (*line).ut_type == USER_PROCESS {
                let user = str::raw::from_c_str(cast::transmute(&(*line).ut_user));
                users.push(user);
            }
        }

        endutent();
    }

    if users.len() > 0 {
        users.sort();
        println!("{}", users.connect(" "));
    }
}
<commit_msg>users: port to Mac<commit_after>#[crate_id(name="users", vers="1.0.0", author="KokaKiwi")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) KokaKiwi <kokakiwi@kokakiwi.net>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: whoami (GNU coreutils) 8.22 */

// Allow dead code here in order to keep all fields, constants here, for consistency.
#[allow(dead_code)];

#[feature(macro_rules, globs)];

extern mod extra;
extern mod getopts;

use std::io::print;
use std::cast;
use std::libc;
use std::os;
use std::ptr;
use std::str;
use utmpx::*;

#[path = "../util.rs"]
mod util;

#[cfg(target_os = "linux")]
mod utmpx {
    use std::libc;

    pub static DEFAULT_FILE: &'static str = "/var/run/utmp";

    pub static UT_LINESIZE: uint = 32;
    pub static UT_NAMESIZE: uint = 32;
    pub static UT_IDSIZE: uint = 4;
    pub static UT_HOSTSIZE: uint = 256;

    pub static EMPTY: libc::c_short = 0;
    pub static RUN_LVL: libc::c_short = 1;
    pub static BOOT_TIME: libc::c_short = 2;
    pub static NEW_TIME: libc::c_short = 3;
    pub static OLD_TIME: libc::c_short = 4;
    pub static INIT_PROCESS: libc::c_short = 5;
    pub static LOGIN_PROCESS: libc::c_short = 6;
    pub static USER_PROCESS: libc::c_short = 7;
    pub static DEAD_PROCESS: libc::c_short = 8;
    pub static ACCOUNTING: libc::c_short = 9;

    pub struct c_exit_status {
        e_termination: libc::c_short,
        e_exit: libc::c_short,
    }

    pub struct c_utmp {
        ut_type: libc::c_short,
        ut_pid: libc::pid_t,
        ut_line: [libc::c_char, ..UT_LINESIZE],
        ut_id: [libc::c_char, ..UT_IDSIZE],

        ut_user: [libc::c_char, ..UT_NAMESIZE],
        ut_host: [libc::c_char, ..UT_HOSTSIZE],
        ut_exit: c_exit_status,
        ut_session: libc::c_long,
        ut_tv: libc::timeval,

        ut_addr_v6: [libc::int32_t, ..4],
        __unused: [libc::c_char, ..20],
    }
}

#[cfg(target_os = "macos")]
mod utmpx {
    use std::libc;

    pub static DEFAULT_FILE: &'static str = "/var/run/utmpx";

    pub static UT_LINESIZE: uint = 32;
    pub static UT_NAMESIZE: uint = 256;
    pub static UT_IDSIZE: uint = 4;
    pub static UT_HOSTSIZE: uint = 256;

    pub static EMPTY: libc::c_short = 0;
    pub static RUN_LVL: libc::c_short = 1;
    pub static BOOT_TIME: libc::c_short = 2;
    pub static OLD_TIME: libc::c_short = 3;
    pub static NEW_TIME: libc::c_short = 4;
    pub static INIT_PROCESS: libc::c_short = 5;
    pub static LOGIN_PROCESS: libc::c_short = 6;
    pub static USER_PROCESS: libc::c_short = 7;
    pub static DEAD_PROCESS: libc::c_short = 8;
    pub static ACCOUNTING: libc::c_short = 9;

    pub struct c_exit_status {
        e_termination: libc::c_short,
        e_exit: libc::c_short,
    }

    pub struct c_utmp {
        ut_user: [libc::c_char, ..UT_NAMESIZE],
        ut_id: [libc::c_char, ..UT_IDSIZE],
        ut_line: [libc::c_char, ..UT_LINESIZE],
        ut_pid: libc::pid_t,
        ut_type: libc::c_short,
        ut_tv: libc::timeval,
        ut_host: [libc::c_char, ..UT_HOSTSIZE],
        __unused: [libc::c_char, ..16]
    }
}

extern {
    fn getutxent() -> *c_utmp;
    fn getutxid(ut: *c_utmp) -> *c_utmp;
    fn getutxline(ut: *c_utmp) -> *c_utmp;

    fn pututxline(ut: *c_utmp) -> *c_utmp;

    fn setutxent();
    fn endutxent();

    fn utmpxname(file: *libc::c_char) -> libc::c_int;
}

static NAME: &'static str = "users";

fn main() {
    let args = os::args();
    let program = args[0].as_slice();
    let opts = ~[
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => fail!(f.to_err_msg()),
    };

    if matches.opt_present("help") {
        println!("users 1.0.0");
        println!("");
        println!("Usage:");
        println!("  {:s} [OPTION]... [FILE]", program);
        println!("");
        print(getopts::usage("Output who is currently logged in according to FILE.", opts));
        return;
    }

    if matches.opt_present("version") {
        println!("users 1.0.0");
        return;
    }

    let mut filename = DEFAULT_FILE;
    if matches.free.len() > 0 {
        filename = matches.free[0].as_slice();
    }

    exec(filename);
}

fn exec(filename: &str) {
    filename.with_c_str(|filename| {
        unsafe {
            utmpxname(filename);
        }
    });

    let mut users: ~[~str] = ~[];

    unsafe {
        setutxent();

        loop {
            let line = getutxent();

            if line == ptr::null() {
                break;
            }

            if (*line).ut_type == USER_PROCESS {
                let user = str::raw::from_c_str(cast::transmute(&(*line).ut_user));
                users.push(user);
            }
        }

        endutxent();
    }

    if users.len() > 0 {
        users.sort();
        println!("{}", users.connect(" "));
    }
}
<|endoftext|>


<commit_before>use crate::utils::{is_direct_expn_of, is_expn_of, match_function_call, paths, span_lint};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for missing parameters in `panic!`.
    ///
    /// **Why is this bad?** Contrary to the `format!` family of macros, there are
    /// two forms of `panic!`: if there are no parameters given, the first argument
    /// is not a format string and used literally. So while `format!("{}")` will
    /// fail to compile, `panic!("{}")` will not.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```no_run
    /// panic!("This `panic!` is probably missing a parameter there: {}");
    /// ```
    pub PANIC_PARAMS,
    style,
    "missing parameters in `panic!` calls"
}

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `panic!`.
    ///
    /// **Why is this bad?** `panic!` will stop the execution of the executable
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```no_run
    /// panic!("even with a good reason");
    /// ```
    pub PANIC,
    restriction,
    "usage of the `panic!` macro"
}

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `unimplemented!`.
    ///
    /// **Why is this bad?** This macro should not be present in production code
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```no_run
    /// unimplemented!();
    /// ```
    pub UNIMPLEMENTED,
    restriction,
    "`unimplemented!` should not be present in production code"
}

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `todo!`.
    ///
    /// **Why is this bad?** This macro should not be present in production code
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```no_run
    /// todo!();
    /// ```
    pub TODO,
    restriction,
    "`todo!` should not be present in production code"
}

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `unreachable!`.
    ///
    /// **Why is this bad?** This macro can cause code to panic
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```no_run
    /// unreachable!();
    /// ```
    pub UNREACHABLE,
    restriction,
    "`unreachable!` should not be present in production code"
}

declare_lint_pass!(PanicUnimplemented => [PANIC_PARAMS, UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]);

impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if_chain! {
            if let ExprKind::Block(ref block, _) = expr.kind;
            if let Some(ref ex) = block.expr;
            if let Some(params) = match_function_call(cx, ex, &paths::BEGIN_PANIC)
                .or(match_function_call(cx, ex, &paths::BEGIN_PANIC_FMT));
            then {
                let span = get_outer_span(expr);
                if is_expn_of(expr.span, "unimplemented").is_some() {
                    span_lint(cx, UNIMPLEMENTED, span,
                              "`unimplemented` should not be present in production code");
                } else if is_expn_of(expr.span, "todo").is_some() {
                    span_lint(cx, TODO, span,
                              "`todo` should not be present in production code");
                } else if is_expn_of(expr.span, "unreachable").is_some() {
                    span_lint(cx, UNREACHABLE, span,
                              "`unreachable` should not be present in production code");
                } else if is_expn_of(expr.span, "panic").is_some() {
                    span_lint(cx, PANIC, span,
                              "`panic` should not be present in production code");
                    match_panic(params, expr, cx);
                }
            }
        }
    }
}

fn get_outer_span(expr: &Expr<'_>) -> Span {
    if_chain! {
        if expr.span.from_expansion();
        let first = expr.span.ctxt().outer_expn_data();
        if first.call_site.from_expansion();
        let second = first.call_site.ctxt().outer_expn_data();
        then {
            second.call_site
        } else {
            expr.span
        }
    }
}

fn match_panic(params: &[Expr<'_>], expr: &Expr<'_>, cx: &LateContext<'_>) {
    if_chain! {
        if let ExprKind::Lit(ref lit) = params[0].kind;
        if is_direct_expn_of(expr.span, "panic").is_some();
        if let LitKind::Str(ref string, _) = lit.node;
        let string = string.as_str().replace("{{", "").replace("}}", "");
        if let Some(par) = string.find('{');
        if string[par..].contains('}');
        if params[0].span.source_callee().is_none();
        if params[0].span.lo() != params[0].span.hi();
        then {
            span_lint(cx, PANIC_PARAMS, params[0].span,
                      "you probably are missing some parameter in your format string");
        }
    }
}
<commit_msg>Clean up dogfood fallout<commit_after>use crate::utils::{is_direct_expn_of, is_expn_of, match_function_call, paths, span_lint};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for missing parameters in `panic!`.
    ///
    /// **Why is this bad?** Contrary to the `format!` family of macros, there are
    /// two forms of `panic!`: if there are no parameters given, the first argument
    /// is not a format string and used literally. So while `format!("{}")` will
    /// fail to compile, `panic!("{}")` will not.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```no_run
    /// panic!("This `panic!` is probably missing a parameter there: {}");
    /// ```
    pub PANIC_PARAMS,
    style,
    "missing parameters in `panic!` calls"
}

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `panic!`.
    ///
    /// **Why is this bad?** `panic!` will stop the execution of the executable
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```no_run
    /// panic!("even with a good reason");
    /// ```
    pub PANIC,
    restriction,
    "usage of the `panic!` macro"
}

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `unimplemented!`.
    ///
    /// **Why is this bad?** This macro should not be present in production code
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```no_run
    /// unimplemented!();
    /// ```
    pub UNIMPLEMENTED,
    restriction,
    "`unimplemented!` should not be present in production code"
}

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `todo!`.
    ///
    /// **Why is this bad?** This macro should not be present in production code
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```no_run
    /// todo!();
    /// ```
    pub TODO,
    restriction,
    "`todo!` should not be present in production code"
}

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `unreachable!`.
    ///
    /// **Why is this bad?** This macro can cause code to panic
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```no_run
    /// unreachable!();
    /// ```
    pub UNREACHABLE,
    restriction,
    "`unreachable!` should not be present in production code"
}

declare_lint_pass!(PanicUnimplemented => [PANIC_PARAMS, UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]);

impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if_chain! {
            if let ExprKind::Block(ref block, _) = expr.kind;
            if let Some(ref ex) = block.expr;
            if let Some(params) = match_function_call(cx, ex, &paths::BEGIN_PANIC)
                .or_else(|| match_function_call(cx, ex, &paths::BEGIN_PANIC_FMT));
            then {
                let span = get_outer_span(expr);
                if is_expn_of(expr.span, "unimplemented").is_some() {
                    span_lint(cx, UNIMPLEMENTED, span,
                              "`unimplemented` should not be present in production code");
                } else if is_expn_of(expr.span, "todo").is_some() {
                    span_lint(cx, TODO, span,
                              "`todo` should not be present in production code");
                } else if is_expn_of(expr.span, "unreachable").is_some() {
                    span_lint(cx, UNREACHABLE, span,
                              "`unreachable` should not be present in production code");
                } else if is_expn_of(expr.span, "panic").is_some() {
                    span_lint(cx, PANIC, span,
                              "`panic` should not be present in production code");
                    match_panic(params, expr, cx);
                }
            }
        }
    }
}

fn get_outer_span(expr: &Expr<'_>) -> Span {
    if_chain! {
        if expr.span.from_expansion();
        let first = expr.span.ctxt().outer_expn_data();
        if first.call_site.from_expansion();
        let second = first.call_site.ctxt().outer_expn_data();
        then {
            second.call_site
        } else {
            expr.span
        }
    }
}

fn match_panic(params: &[Expr<'_>], expr: &Expr<'_>, cx: &LateContext<'_>) {
    if_chain! {
        if let ExprKind::Lit(ref lit) = params[0].kind;
        if is_direct_expn_of(expr.span, "panic").is_some();
        if let LitKind::Str(ref string, _) = lit.node;
        let string = string.as_str().replace("{{", "").replace("}}", "");
        if let Some(par) = string.find('{');
        if string[par..].contains('}');
        if params[0].span.source_callee().is_none();
        if params[0].span.lo() != params[0].span.hi();
        then {
            span_lint(cx, PANIC_PARAMS, params[0].span,
                      "you probably are missing some parameter in your format string");
        }
    }
}
<|endoftext|>


<commit_before>use futures::future;
use futures::{Poll, Async, StartSend, AsyncSink, Future, Stream, Sink};
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::codec::{Framed, Encoder, Decoder};
use tokio_core::reactor::{Handle, Core};
use tokio_core::net::TcpStream;
use bytes::{BytesMut, BufMut};
use errors::ECIESError;
use secp256k1::key::SecretKey;
use bigint::H512;
use std::io;
use std::net::SocketAddr;
use super::algorithm::ECIES;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// Current ECIES state of a connection
pub enum ECIESState {
    Auth, Ack, Header, Body
}

#[derive(Clone, Debug, PartialEq, Eq)]
/// Raw values for an ECIES protocol
pub enum ECIESValue {
    Auth, Ack, Header(usize), Body(Vec<u8>)
}

/// Tokio codec for ECIES
pub struct ECIESCodec {
    ecies: ECIES,
    state: ECIESState,
}

impl ECIESCodec {
    /// Create a new server codec using the given secret key
    pub fn new_server(secret_key: SecretKey) -> Result<Self, ECIESError> {
        Ok(Self {
            ecies: ECIES::new_server(secret_key)?,
            state: ECIESState::Auth
        })
    }

    /// Create a new client codec using the given secret key and the server's public id
    pub fn new_client(secret_key: SecretKey, remote_id: H512) -> Result<Self, ECIESError> {
        Ok(Self {
            ecies: ECIES::new_client(secret_key, remote_id)?,
            state: ECIESState::Auth
        })
    }
}

impl Decoder for ECIESCodec {
    type Item = ECIESValue;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<ECIESValue>, io::Error> {
        match self.state {
            ECIESState::Auth => {
                if buf.len() < self.ecies.auth_len() {
                    return Ok(None);
                }

                let data = buf.split_to(self.ecies.auth_len());
                self.ecies.parse_auth(&data)?;

                self.state = ECIESState::Header;
                Ok(Some(ECIESValue::Auth))
            },
            ECIESState::Ack => {
                if buf.len() < self.ecies.ack_len() {
                    return Ok(None);
                }

                let data = buf.split_to(self.ecies.ack_len());
                self.ecies.parse_ack(&data)?;

                self.state = ECIESState::Header;
                Ok(Some(ECIESValue::Ack))
            },
            ECIESState::Header => {
                if buf.len() < self.ecies.header_len() {
                    return Ok(None);
                }

                let data = buf.split_to(self.ecies.header_len());
                let size = self.ecies.parse_header(&data)?;

                self.state = ECIESState::Body;
                Ok(Some(ECIESValue::Header(size)))
            },
            ECIESState::Body => {
                if buf.len() < self.ecies.body_len() {
                    return Ok(None);
                }

                let data = buf.split_to(self.ecies.body_len());
                let ret = self.ecies.parse_body(&data)?;

                self.state = ECIESState::Header;
                Ok(Some(ECIESValue::Body(ret)))
            },
        }
    }
}

impl Encoder for ECIESCodec {
    type Item = ECIESValue;
    type Error = io::Error;

    fn encode(&mut self, msg: ECIESValue, buf: &mut BytesMut) -> Result<(), io::Error> {
        match msg {
            ECIESValue::Auth => {
                let data = self.ecies.create_auth()?;
                self.state = ECIESState::Ack;
                buf.reserve(data.len());
                buf.extend(data);
                Ok(())
            },
            ECIESValue::Ack => {
                let data = self.ecies.create_ack()?;
                self.state = ECIESState::Header;
                buf.reserve(data.len());
                buf.extend(data);
                Ok(())
            },
            ECIESValue::Header(size) => {
                let data = self.ecies.create_header(size);
                buf.reserve(data.len());
                buf.extend(data);
                Ok(())
            },
            ECIESValue::Body(val) => {
                let data = self.ecies.create_body(val.as_ref());
                buf.reserve(data.len());
                buf.extend(data);
                Ok(())
            }
        }
    }
}

/// ECIES stream over TCP exchanging raw bytes
pub struct ECIESStream {
    stream: Framed<TcpStream, ECIESCodec>,
    polled_header: bool,
    sending_body: Option<Vec<u8>>,
}

impl ECIESStream {
    /// Connect to an ECIES server
    pub fn connect(
        addr: &SocketAddr, handle: &Handle,
        secret_key: SecretKey, remote_id: H512
    ) -> Box<Future<Item = ECIESStream, Error = io::Error>> {
        let ecies = match ECIESCodec::new_client(secret_key, remote_id) {
            Ok(val) => val,
            Err(e) => return Box::new(future::err(
                io::Error::new(io::ErrorKind::Other, "invalid handshake")))
                as Box<Future<Item = ECIESStream, Error = io::Error>>,
        };

        debug!("connecting to ecies stream ...");
        let stream = TcpStream::connect(addr, handle)
            .and_then(|socket| {
                debug!("sending ecies auth ...");
                socket.framed(ecies).send(ECIESValue::Auth)
            })
            .and_then(|transport| transport.into_future().map_err(|(e, _)| e))
            .and_then(move |(ack, transport)| {
                debug!("receiving ecies ack ...");
                if ack == Some(ECIESValue::Ack) {
                    Ok(ECIESStream {
                        stream: transport,
                        polled_header: false,
                        sending_body: None,
                    })
                } else {
                    error!("expected ack, got {:?} instead", ack);
                    Err(io::Error::new(io::ErrorKind::Other, "invalid handshake"))
                }
            });

        Box::new(stream)
    }
}

impl Stream for ECIESStream {
    type Item = Vec<u8>;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        if !self.polled_header {
            match try_ready!(self.stream.poll()) {
                Some(ECIESValue::Header(_)) => (),
                Some(_) =>
                    return Err(io::Error::new(io::ErrorKind::Other, "ECIES stream protocol error")),
                None => return Ok(Async::Ready(None)),
            };
            self.polled_header = true;
        }
        let body = match try_ready!(self.stream.poll()) {
            Some(ECIESValue::Body(val)) => val,
            Some(_) =>
                return Err(io::Error::new(io::ErrorKind::Other, "ECIES stream protocol error")),
            None => return Ok(Async::Ready(None)),
        };
        self.polled_header = false;
        Ok(Async::Ready(Some(body)))
    }
}

impl Sink for ECIESStream {
    type SinkItem = Vec<u8>;
    type SinkError = io::Error;

    fn start_send(&mut self, item: Vec<u8>) -> StartSend<Self::SinkItem, Self::SinkError> {
        if self.sending_body.is_some() {
            let sending_body = self.sending_body.take().unwrap();
            match self.stream.start_send(ECIESValue::Body(sending_body))? {
                AsyncSink::Ready => (), // Cache cleared, able to deal with the current item.
                AsyncSink::NotReady(ECIESValue::Body(sending_body)) => {
                    self.sending_body = Some(sending_body);
                    return Ok(AsyncSink::NotReady(item));
                },
                _ => panic!(),
            }
        }

        match self.stream.start_send(ECIESValue::Header(item.len()))? {
            AsyncSink::Ready => (),
            AsyncSink::NotReady(header) => return Ok(AsyncSink::NotReady(item)),
        }

        match self.stream.start_send(ECIESValue::Body(item))? {
            AsyncSink::Ready => (),
            AsyncSink::NotReady(ECIESValue::Body(item)) => {
                self.sending_body = Some(item);
            },
            _ => panic!(),
        }

        Ok(AsyncSink::Ready)
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        if self.sending_body.is_some() {
            let sending_body = self.sending_body.take().unwrap();
            match self.stream.start_send(ECIESValue::Body(sending_body))? {
                AsyncSink::Ready => (),
                AsyncSink::NotReady(ECIESValue::Body(sending_body)) => {
                    self.sending_body = Some(sending_body);
                    return Ok(Async::NotReady);
                },
                _ => panic!(),
            }
        }

        self.stream.poll_complete()
    }
}
<commit_msg>rlpx: accept incoming connection in ECIES<commit_after>use futures::future;
use futures::{Poll, Async, StartSend, AsyncSink, Future, Stream, Sink};
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::codec::{Framed, Encoder, Decoder};
use tokio_core::reactor::{Handle, Core};
use tokio_core::net::TcpStream;
use bytes::{BytesMut, BufMut};
use errors::ECIESError;
use secp256k1::key::SecretKey;
use bigint::H512;
use std::io;
use std::net::SocketAddr;
use super::algorithm::ECIES;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// Current ECIES state of a connection
pub enum ECIESState {
    Auth, Ack, Header, Body
}

#[derive(Clone, Debug, PartialEq, Eq)]
/// Raw values for an ECIES protocol
pub enum ECIESValue {
    Auth, Ack, Header(usize), Body(Vec<u8>)
}

/// Tokio codec for ECIES
pub struct ECIESCodec {
    ecies: ECIES,
    state: ECIESState,
}

impl ECIESCodec {
    /// Create a new server codec using the given secret key
    pub fn new_server(secret_key: SecretKey) -> Result<Self, ECIESError> {
        Ok(Self {
            ecies: ECIES::new_server(secret_key)?,
            state: ECIESState::Auth
        })
    }

    /// Create a new client codec using the given secret key and the server's public id
    pub fn new_client(secret_key: SecretKey, remote_id: H512) -> Result<Self, ECIESError> {
        Ok(Self {
            ecies: ECIES::new_client(secret_key, remote_id)?,
            state: ECIESState::Auth
        })
    }
}

impl Decoder for ECIESCodec {
    type Item = ECIESValue;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<ECIESValue>, io::Error> {
        match self.state {
            ECIESState::Auth => {
                if buf.len() < self.ecies.auth_len() {
                    return Ok(None);
                }

                let data = buf.split_to(self.ecies.auth_len());
                self.ecies.parse_auth(&data)?;

                self.state = ECIESState::Header;
                Ok(Some(ECIESValue::Auth))
            },
            ECIESState::Ack => {
                if buf.len() < self.ecies.ack_len() {
                    return Ok(None);
                }

                let data = buf.split_to(self.ecies.ack_len());
                self.ecies.parse_ack(&data)?;

                self.state = ECIESState::Header;
                Ok(Some(ECIESValue::Ack))
            },
            ECIESState::Header => {
                if buf.len() < self.ecies.header_len() {
                    return Ok(None);
                }

                let data = buf.split_to(self.ecies.header_len());
                let size = self.ecies.parse_header(&data)?;

                self.state = ECIESState::Body;
                Ok(Some(ECIESValue::Header(size)))
            },
            ECIESState::Body => {
                if buf.len() < self.ecies.body_len() {
                    return Ok(None);
                }

                let data = buf.split_to(self.ecies.body_len());
                let ret = self.ecies.parse_body(&data)?;

                self.state = ECIESState::Header;
                Ok(Some(ECIESValue::Body(ret)))
            },
        }
    }
}

impl Encoder for ECIESCodec {
    type Item = ECIESValue;
    type Error = io::Error;

    fn encode(&mut self, msg: ECIESValue, buf: &mut BytesMut) -> Result<(), io::Error> {
        match msg {
            ECIESValue::Auth => {
                let data = self.ecies.create_auth()?;
                self.state = ECIESState::Ack;
                buf.reserve(data.len());
                buf.extend(data);
                Ok(())
            },
            ECIESValue::Ack => {
                let data = self.ecies.create_ack()?;
                self.state = ECIESState::Header;
                buf.reserve(data.len());
                buf.extend(data);
                Ok(())
            },
            ECIESValue::Header(size) => {
                let data = self.ecies.create_header(size);
                buf.reserve(data.len());
                buf.extend(data);
                Ok(())
            },
            ECIESValue::Body(val) => {
                let data = self.ecies.create_body(val.as_ref());
                buf.reserve(data.len());
                buf.extend(data);
                Ok(())
            }
        }
    }
}

/// ECIES stream over TCP exchanging raw bytes
pub struct ECIESStream {
    stream: Framed<TcpStream, ECIESCodec>,
    polled_header: bool,
    sending_body: Option<Vec<u8>>,
}

impl ECIESStream {
    /// Connect to an ECIES server
    pub fn connect(
        addr: &SocketAddr, handle: &Handle,
        secret_key: SecretKey, remote_id: H512
    ) -> Box<Future<Item = ECIESStream, Error = io::Error>> {
        let ecies = match ECIESCodec::new_client(secret_key, remote_id) {
            Ok(val) => val,
            Err(e) => return Box::new(future::err(
                io::Error::new(io::ErrorKind::Other, "invalid handshake")))
                as Box<Future<Item = ECIESStream, Error = io::Error>>,
        };

        debug!("connecting to ecies stream ...");
        let stream = TcpStream::connect(addr, handle)
            .and_then(|socket| {
                debug!("sending ecies auth ...");
                socket.framed(ecies).send(ECIESValue::Auth)
            })
            .and_then(|transport| transport.into_future().map_err(|(e, _)| e))
            .and_then(move |(ack, transport)| {
                debug!("receiving ecies ack ...");
                if ack == Some(ECIESValue::Ack) {
                    Ok(ECIESStream {
                        stream: transport,
                        polled_header: false,
                        sending_body: None,
                    })
                } else {
                    error!("expected ack, got {:?} instead", ack);
                    Err(io::Error::new(io::ErrorKind::Other, "invalid handshake"))
                }
            });

        Box::new(stream)
    }

    /// Listen on a just connected ECIES clinet
    pub fn incoming(
        stream: TcpStream, secret_key: SecretKey
    ) -> Box<Future<Item = ECIESStream, Error = io::Error>> {
        let ecies = match ECIESCodec::new_server(secret_key) {
            Ok(val) => val,
            Err(e) => return Box::new(future::err(
                io::Error::new(io::ErrorKind::Other, "invalid handshake")))
                as Box<Future<Item = ECIESStream, Error = io::Error>>,
        };

        debug!("incoming ecies stream ...");
        let stream = stream.framed(ecies).into_future().map_err(|(e, _)| e)
            .and_then(move |(ack, transport)| {
                debug!("receiving ecies auth");
                if ack == Some(ECIESValue::Auth) {
                    Ok(transport)
                } else {
                    error!("expected auth, got {:?} instead", ack);
                    Err(io::Error::new(io::ErrorKind::Other, "invalid handshake"))
                }
            })
            .and_then(|socket| {
                debug!("sending ecies ack ...");
                socket.send(ECIESValue::Ack)
            })
            .and_then(|socket| {
                Ok(ECIESStream {
                    stream: socket,
                    polled_header: false,
                    sending_body: None,
                })
            });

        Box::new(stream)
    }
}

impl Stream for ECIESStream {
    type Item = Vec<u8>;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        if !self.polled_header {
            match try_ready!(self.stream.poll()) {
                Some(ECIESValue::Header(_)) => (),
                Some(_) =>
                    return Err(io::Error::new(io::ErrorKind::Other, "ECIES stream protocol error")),
                None => return Ok(Async::Ready(None)),
            };
            self.polled_header = true;
        }
        let body = match try_ready!(self.stream.poll()) {
            Some(ECIESValue::Body(val)) => val,
            Some(_) =>
                return Err(io::Error::new(io::ErrorKind::Other, "ECIES stream protocol error")),
            None => return Ok(Async::Ready(None)),
        };
        self.polled_header = false;
        Ok(Async::Ready(Some(body)))
    }
}

impl Sink for ECIESStream {
    type SinkItem = Vec<u8>;
    type SinkError = io::Error;

    fn start_send(&mut self, item: Vec<u8>) -> StartSend<Self::SinkItem, Self::SinkError> {
        if self.sending_body.is_some() {
            let sending_body = self.sending_body.take().unwrap();
            match self.stream.start_send(ECIESValue::Body(sending_body))? {
                AsyncSink::Ready => (), // Cache cleared, able to deal with the current item.
                AsyncSink::NotReady(ECIESValue::Body(sending_body)) => {
                    self.sending_body = Some(sending_body);
                    return Ok(AsyncSink::NotReady(item));
                },
                _ => panic!(),
            }
        }

        match self.stream.start_send(ECIESValue::Header(item.len()))? {
            AsyncSink::Ready => (),
            AsyncSink::NotReady(header) => return Ok(AsyncSink::NotReady(item)),
        }

        match self.stream.start_send(ECIESValue::Body(item))? {
            AsyncSink::Ready => (),
            AsyncSink::NotReady(ECIESValue::Body(item)) => {
                self.sending_body = Some(item);
            },
            _ => panic!(),
        }

        Ok(AsyncSink::Ready)
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        if self.sending_body.is_some() {
            let sending_body = self.sending_body.take().unwrap();
            match self.stream.start_send(ECIESValue::Body(sending_body))? {
                AsyncSink::Ready => (),
                AsyncSink::NotReady(ECIESValue::Body(sending_body)) => {
                    self.sending_body = Some(sending_body);
                    return Ok(Async::NotReady);
                },
                _ => panic!(),
            }
        }

        self.stream.poll_complete()
    }
}
<|endoftext|>


<commit_before>// Built-in Lints
#![deny(warnings, missing_debug_implementations, missing_copy_implementations)]
// Clippy lints
#![cfg_attr(feature = "clippy", allow(unstable_features))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(feature = "clippy",
           allow(option_map_unwrap_or_else, option_map_unwrap_or, match_same_arms,
                   type_complexity))]
#![cfg_attr(feature = "clippy",
           warn(option_unwrap_used, print_stdout,
                  wrong_pub_self_convention, mut_mut, non_ascii_literal, similar_names,
                  unicode_not_nfc, enum_glob_use, if_not_else, items_after_statements,
                  used_underscore_binding))]
#![cfg_attr(all(test, feature = "clippy"), allow(option_unwrap_used, result_unwrap_used))]
extern crate migrations_internals;
extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

mod migrations;
mod embed_migrations;
mod util;

use proc_macro::TokenStream;
use syn::parse_derive_input;

#[proc_macro_derive(EmbedMigrations, attributes(embed_migrations_options))]
pub fn derive_embed_migrations(input: TokenStream) -> TokenStream {
    let item = parse_derive_input(&input.to_string()).unwrap();
    embed_migrations::derive_embed_migrations(&item)
        .to_string()
        .parse()
        .unwrap()
}
<commit_msg>cargo fmt<commit_after>// Built-in Lints
#![deny(warnings, missing_debug_implementations, missing_copy_implementations)]
// Clippy lints
#![cfg_attr(feature = "clippy", allow(unstable_features))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(feature = "clippy",
           allow(option_map_unwrap_or_else, option_map_unwrap_or, match_same_arms,
                   type_complexity))]
#![cfg_attr(feature = "clippy",
           warn(option_unwrap_used, print_stdout, wrong_pub_self_convention, mut_mut,
                non_ascii_literal, similar_names, unicode_not_nfc, enum_glob_use, if_not_else,
                items_after_statements, used_underscore_binding))]
#![cfg_attr(all(test, feature = "clippy"), allow(option_unwrap_used, result_unwrap_used))]
extern crate migrations_internals;
extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

mod migrations;
mod embed_migrations;
mod util;

use proc_macro::TokenStream;
use syn::parse_derive_input;

#[proc_macro_derive(EmbedMigrations, attributes(embed_migrations_options))]
pub fn derive_embed_migrations(input: TokenStream) -> TokenStream {
    let item = parse_derive_input(&input.to_string()).unwrap();
    embed_migrations::derive_embed_migrations(&item)
        .to_string()
        .parse()
        .unwrap()
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Sieve_of_Eratosthenes

use std::slice;
use std::iter;

fn int_sqrt(n: uint) -> uint {
    (n as f64).sqrt() as uint
}

fn simple_sieve(limit: uint) -> ~[uint] {
    if limit < 2 {
        return ~[];
    }

    let mut primes = slice::from_elem(limit + 1, true);

    for prime in iter::range_inclusive(2, int_sqrt(limit) + 1) {
        if primes[prime] {
            for multiple in iter::range_step(prime * prime, limit + 1, prime) {
                primes[multiple] = false
            }
        }
    }
    iter::range_inclusive(2, limit).filter(|&n| primes[n]).collect()
}

fn main() {
    println!("{:?}", simple_sieve(100))
}
<commit_msg>Fixed sieve of eratosthenes<commit_after>// Implements http://rosettacode.org/wiki/Sieve_of_Eratosthenes

use std::iter;

fn int_sqrt(n: uint) -> uint {
    (n as f64).sqrt() as uint
}

fn simple_sieve(limit: uint) -> ~[uint] {
    if limit < 2 {
        return ~[];
    }

    let mut primes = Vec::from_fn(limit + 1, |_| true);

    for prime in iter::range_inclusive(2, int_sqrt(limit) + 1) {
        if *primes.get(0) {
            for multiple in iter::range_step(prime * prime, limit + 1, prime) {
                *primes.get_mut(multiple) = false
            }
        }
    }

    iter::range_inclusive(2, limit).filter(|&n| *primes.get(n)).collect()
}

fn main() {
    println!("{:?}", simple_sieve(100))
}
<|endoftext|>


<commit_before>use std::slice;
use std::num;
use std::iter;

fn int_sqrt(n: uint) -> uint {
    num::sqrt(n as f64) as uint
}

fn simple_sieve(limit: uint) -> ~[uint] {
    if limit < 2 {
        return ~[];
    }

    let mut primes = slice::from_elem(limit + 1, true);

    for prime in iter::range_inclusive(2, int_sqrt(limit) + 1) {
        if primes[prime] {
            for multiple in iter::range_step(prime * prime, limit + 1, prime) {
                primes[multiple] = false
            }
        }
    }
    iter::range_inclusive(2, limit).filter(|&n| primes[n]).collect()
}

fn main() {
    println!("{:?}", simple_sieve(100))
}
<commit_msg>fix compilation error for sqrt method call<commit_after>use std::slice;
use std::iter;

fn int_sqrt(n: uint) -> uint {
    (n as f64).sqrt() as uint
}

fn simple_sieve(limit: uint) -> ~[uint] {
    if limit < 2 {
        return ~[];
    }

    let mut primes = slice::from_elem(limit + 1, true);

    for prime in iter::range_inclusive(2, int_sqrt(limit) + 1) {
        if primes[prime] {
            for multiple in iter::range_step(prime * prime, limit + 1, prime) {
                primes[multiple] = false
            }
        }
    }
    iter::range_inclusive(2, limit).filter(|&n| primes[n]).collect()
}

fn main() {
    println!("{:?}", simple_sieve(100))
}
<|endoftext|>