<commit_before>//! Read configurations files.

#![deny(clippy::missing_docs_in_private_items)]

use rustc_ast::ast::{LitKind, MetaItemKind, NestedMetaItem};
use rustc_span::source_map;
use source_map::Span;
use std::lazy::SyncLazy;
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use std::{env, fmt, fs, io};

/// Gets the configuration file from arguments.
pub fn file_from_args(args: &[NestedMetaItem]) -> Result<Option<PathBuf>, (&'static str, Span)> {
    for arg in args.iter().filter_map(NestedMetaItem::meta_item) {
        if arg.has_name(sym!(conf_file)) {
            return match arg.kind {
                MetaItemKind::Word | MetaItemKind::List(_) => Err(("`conf_file` must be a named value", arg.span)),
                MetaItemKind::NameValue(ref value) => {
                    if let LitKind::Str(ref file, _) = value.kind {
                        Ok(Some(file.to_string().into()))
                    } else {
                        Err(("`conf_file` value must be a string", value.span))
                    }
                },
            };
        }
    }

    Ok(None)
}

/// Error from reading a configuration file.
#[derive(Debug)]
pub enum Error {
    /// An I/O error.
    Io(io::Error),
    /// Not valid toml or doesn't fit the expected config format
    Toml(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Io(err) => err.fmt(f),
            Self::Toml(err) => err.fmt(f),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Self::Io(e)
    }
}

/// Vec of errors that might be collected during config toml parsing
static ERRORS: SyncLazy<Mutex<Vec<Error>>> = SyncLazy::new(|| Mutex::new(Vec::new()));

macro_rules! define_Conf {
    ($(#[$doc:meta] ($config:ident, $config_str:literal: $Ty:ty, $default:expr),)+) => {
        mod helpers {
            use serde::Deserialize;
            /// Type used to store lint configuration.
            #[derive(Deserialize)]
            #[serde(rename_all = "kebab-case", deny_unknown_fields)]
            pub struct Conf {
                $(
                    #[$doc]
                    #[serde(default = $config_str)]
                    #[serde(with = $config_str)]
                    pub $config: $Ty,
                )+
                #[allow(dead_code)]
                #[serde(default)]
                third_party: Option<::toml::Value>,
            }

            $(
                mod $config {
                    use serde::Deserialize;
                    pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<$Ty, D::Error> {
                        use super::super::{ERRORS, Error};

                        Ok(
                            <$Ty>::deserialize(deserializer).unwrap_or_else(|e| {
                                ERRORS
                                    .lock()
                                    .expect("no threading here")
                                    .push(Error::Toml(e.to_string()));
                                super::$config()
                            })
                        )
                    }
                }

                #[must_use]
                fn $config() -> $Ty {
                    let x = $default;
                    x
                }
            )+
        }
    };
}

pub use self::helpers::Conf;
define_Conf! {
    /// Lint: MANUAL_NON_EXHAUSTIVE, MANUAL_STRIP, OPTION_AS_REF_DEREF, MATCH_LIKE_MATCHES_MACRO. The minimum rust version that the project supports
    (msrv, "msrv": Option<String>, None),
    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
    (blacklisted_names, "blacklisted_names": Vec<String>, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
    /// Lint: COGNITIVE_COMPLEXITY. The maximum cognitive complexity a function can have
    (cognitive_complexity_threshold, "cognitive_complexity_threshold": u64, 25),
    /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. Use the Cognitive Complexity lint instead.
    (cyclomatic_complexity_threshold, "cyclomatic_complexity_threshold": Option<u64>, None),
    /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
    (doc_valid_idents, "doc_valid_idents": Vec<String>, [
        "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
        "DirectX",
        "ECMAScript",
        "GPLv2", "GPLv3",
        "GitHub", "GitLab",
        "IPv4", "IPv6",
        "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript",
        "NaN", "NaNs",
        "OAuth", "GraphQL",
        "OCaml",
        "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap",
        "TensorFlow",
        "TrueType",
        "iOS", "macOS",
        "TeX", "LaTeX", "BibTeX", "BibLaTeX",
        "MinGW",
        "CamelCase",
    ].iter().map(ToString::to_string).collect()),
    /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
    (too_many_arguments_threshold, "too_many_arguments_threshold": u64, 7),
    /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
    (type_complexity_threshold, "type_complexity_threshold": u64, 250),
    /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
    (single_char_binding_names_threshold, "single_char_binding_names_threshold": u64, 4),
    /// Lint: BOXED_LOCAL, USELESS_VEC. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
    (too_large_for_stack, "too_large_for_stack": u64, 200),
    /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
    (enum_variant_name_threshold, "enum_variant_name_threshold": u64, 3),
    /// Lint: LARGE_ENUM_VARIANT. The maximum size of a enum's variant to avoid box suggestion
    (enum_variant_size_threshold, "enum_variant_size_threshold": u64, 200),
    /// Lint: VERBOSE_BIT_MASK. The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
    (verbose_bit_mask_threshold, "verbose_bit_mask_threshold": u64, 1),
    /// Lint: DECIMAL_LITERAL_REPRESENTATION. The lower bound for linting decimal literals
    (literal_representation_threshold, "literal_representation_threshold": u64, 16384),
    /// Lint: TRIVIALLY_COPY_PASS_BY_REF. The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
    (trivial_copy_size_limit, "trivial_copy_size_limit": Option<u64>, None),
    /// Lint: LARGE_TYPE_PASS_BY_MOVE. The minimum size (in bytes) to consider a type for passing by reference instead of by value.
    (pass_by_value_size_limit, "pass_by_value_size_limit": u64, 256),
    /// Lint: TOO_MANY_LINES. The maximum number of lines a function or method can have
    (too_many_lines_threshold, "too_many_lines_threshold": u64, 100),
    /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. The maximum allowed size for arrays on the stack
    (array_size_threshold, "array_size_threshold": u64, 512_000),
    /// Lint: VEC_BOX. The size of the boxed type in bytes, where boxing in a `Vec` is allowed
    (vec_box_size_threshold, "vec_box_size_threshold": u64, 4096),
    /// Lint: TYPE_REPETITION_IN_BOUNDS. The maximum number of bounds a trait can have to be linted
    (max_trait_bounds, "max_trait_bounds": u64, 3),
    /// Lint: STRUCT_EXCESSIVE_BOOLS. The maximum number of bools a struct can have
    (max_struct_bools, "max_struct_bools": u64, 3),
    /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. The maximum number of bools function parameters can have
    (max_fn_params_bools, "max_fn_params_bools": u64, 3),
    /// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests).
    (warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false),
    /// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses
    (disallowed_methods, "disallowed_methods": Vec<String>, Vec::<String>::new()),
    /// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators.
    (unreadable_literal_lint_fractions, "unreadable_literal_lint_fractions": bool, true),
}

impl Default for Conf {
    #[must_use]
    fn default() -> Self {
        toml::from_str("").expect("we never error on empty config files")
    }
}

/// Search for the configuration file.
pub fn lookup_conf_file() -> io::Result<Option<PathBuf>> {
    /// Possible filename to search for.
    const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];

    // Start looking for a config file in CLIPPY_CONF_DIR, or failing that, CARGO_MANIFEST_DIR.
    // If neither of those exist, use ".".
    let mut current = env::var_os("CLIPPY_CONF_DIR")
        .or_else(|| env::var_os("CARGO_MANIFEST_DIR"))
        .map_or_else(|| PathBuf::from("."), PathBuf::from);
    loop {
        for config_file_name in &CONFIG_FILE_NAMES {
            let config_file = current.join(config_file_name);
            match fs::metadata(&config_file) {
                // Only return if it's a file to handle the unlikely situation of a directory named
                // `clippy.toml`.
                Ok(ref md) if !md.is_dir() => return Ok(Some(config_file)),
                // Return the error if it's something other than `NotFound`; otherwise we didn't
                // find the project file yet, and continue searching.
                Err(e) if e.kind() != io::ErrorKind::NotFound => return Err(e),
                _ => {},
            }
        }

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

/// Produces a `Conf` filled with the default values and forwards the errors
///
/// Used internally for convenience
fn default(errors: Vec<Error>) -> (Conf, Vec<Error>) {
    (Conf::default(), errors)
}

/// Read the `toml` configuration file.
///
/// In case of error, the function tries to continue as much as possible.
pub fn read(path: &Path) -> (Conf, Vec<Error>) {
    let content = match fs::read_to_string(path) {
        Ok(content) => content,
        Err(err) => return default(vec![err.into()]),
    };

    assert!(ERRORS.lock().expect("no threading -> mutex always safe").is_empty());
    match toml::from_str(&content) {
        Ok(toml) => {
            let mut errors = ERRORS.lock().expect("no threading -> mutex always safe").split_off(0);

            let toml_ref: &Conf = &toml;

            let cyc_field: Option<u64> = toml_ref.cyclomatic_complexity_threshold;

            if cyc_field.is_some() {
                let cyc_err = "found deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead.".to_string();
                errors.push(Error::Toml(cyc_err));
            }

            (toml, errors)
        },
        Err(e) => {
            let mut errors = ERRORS.lock().expect("no threading -> mutex always safe").split_off(0);
            errors.push(Error::Toml(e.to_string()));

            default(errors)
        },
    }
}
<commit_msg>Auto merge of #6465 - Suyash458:master, r=flip1995<commit_after>//! Read configurations files.

#![deny(clippy::missing_docs_in_private_items)]

use rustc_ast::ast::{LitKind, MetaItemKind, NestedMetaItem};
use rustc_span::source_map;
use source_map::Span;
use std::lazy::SyncLazy;
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use std::{env, fmt, fs, io};

/// Gets the configuration file from arguments.
pub fn file_from_args(args: &[NestedMetaItem]) -> Result<Option<PathBuf>, (&'static str, Span)> {
    for arg in args.iter().filter_map(NestedMetaItem::meta_item) {
        if arg.has_name(sym!(conf_file)) {
            return match arg.kind {
                MetaItemKind::Word | MetaItemKind::List(_) => Err(("`conf_file` must be a named value", arg.span)),
                MetaItemKind::NameValue(ref value) => {
                    if let LitKind::Str(ref file, _) = value.kind {
                        Ok(Some(file.to_string().into()))
                    } else {
                        Err(("`conf_file` value must be a string", value.span))
                    }
                },
            };
        }
    }

    Ok(None)
}

/// Error from reading a configuration file.
#[derive(Debug)]
pub enum Error {
    /// An I/O error.
    Io(io::Error),
    /// Not valid toml or doesn't fit the expected config format
    Toml(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Io(err) => err.fmt(f),
            Self::Toml(err) => err.fmt(f),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Self::Io(e)
    }
}

/// Vec of errors that might be collected during config toml parsing
static ERRORS: SyncLazy<Mutex<Vec<Error>>> = SyncLazy::new(|| Mutex::new(Vec::new()));

macro_rules! define_Conf {
    ($(#[$doc:meta] ($config:ident, $config_str:literal: $Ty:ty, $default:expr),)+) => {
        mod helpers {
            use serde::Deserialize;
            /// Type used to store lint configuration.
            #[derive(Deserialize)]
            #[serde(rename_all = "kebab-case", deny_unknown_fields)]
            pub struct Conf {
                $(
                    #[$doc]
                    #[serde(default = $config_str)]
                    #[serde(with = $config_str)]
                    pub $config: $Ty,
                )+
                #[allow(dead_code)]
                #[serde(default)]
                third_party: Option<::toml::Value>,
            }

            $(
                mod $config {
                    use serde::Deserialize;
                    pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<$Ty, D::Error> {
                        use super::super::{ERRORS, Error};

                        Ok(
                            <$Ty>::deserialize(deserializer).unwrap_or_else(|e| {
                                ERRORS
                                    .lock()
                                    .expect("no threading here")
                                    .push(Error::Toml(e.to_string()));
                                super::$config()
                            })
                        )
                    }
                }

                #[must_use]
                fn $config() -> $Ty {
                    let x = $default;
                    x
                }
            )+
        }
    };
}

pub use self::helpers::Conf;
define_Conf! {
    /// Lint: REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN. The minimum rust version that the project supports
    (msrv, "msrv": Option<String>, None),
    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
    (blacklisted_names, "blacklisted_names": Vec<String>, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
    /// Lint: COGNITIVE_COMPLEXITY. The maximum cognitive complexity a function can have
    (cognitive_complexity_threshold, "cognitive_complexity_threshold": u64, 25),
    /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. Use the Cognitive Complexity lint instead.
    (cyclomatic_complexity_threshold, "cyclomatic_complexity_threshold": Option<u64>, None),
    /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
    (doc_valid_idents, "doc_valid_idents": Vec<String>, [
        "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
        "DirectX",
        "ECMAScript",
        "GPLv2", "GPLv3",
        "GitHub", "GitLab",
        "IPv4", "IPv6",
        "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript",
        "NaN", "NaNs",
        "OAuth", "GraphQL",
        "OCaml",
        "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap",
        "TensorFlow",
        "TrueType",
        "iOS", "macOS",
        "TeX", "LaTeX", "BibTeX", "BibLaTeX",
        "MinGW",
        "CamelCase",
    ].iter().map(ToString::to_string).collect()),
    /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
    (too_many_arguments_threshold, "too_many_arguments_threshold": u64, 7),
    /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
    (type_complexity_threshold, "type_complexity_threshold": u64, 250),
    /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
    (single_char_binding_names_threshold, "single_char_binding_names_threshold": u64, 4),
    /// Lint: BOXED_LOCAL, USELESS_VEC. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
    (too_large_for_stack, "too_large_for_stack": u64, 200),
    /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
    (enum_variant_name_threshold, "enum_variant_name_threshold": u64, 3),
    /// Lint: LARGE_ENUM_VARIANT. The maximum size of a enum's variant to avoid box suggestion
    (enum_variant_size_threshold, "enum_variant_size_threshold": u64, 200),
    /// Lint: VERBOSE_BIT_MASK. The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
    (verbose_bit_mask_threshold, "verbose_bit_mask_threshold": u64, 1),
    /// Lint: DECIMAL_LITERAL_REPRESENTATION. The lower bound for linting decimal literals
    (literal_representation_threshold, "literal_representation_threshold": u64, 16384),
    /// Lint: TRIVIALLY_COPY_PASS_BY_REF. The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
    (trivial_copy_size_limit, "trivial_copy_size_limit": Option<u64>, None),
    /// Lint: LARGE_TYPE_PASS_BY_MOVE. The minimum size (in bytes) to consider a type for passing by reference instead of by value.
    (pass_by_value_size_limit, "pass_by_value_size_limit": u64, 256),
    /// Lint: TOO_MANY_LINES. The maximum number of lines a function or method can have
    (too_many_lines_threshold, "too_many_lines_threshold": u64, 100),
    /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. The maximum allowed size for arrays on the stack
    (array_size_threshold, "array_size_threshold": u64, 512_000),
    /// Lint: VEC_BOX. The size of the boxed type in bytes, where boxing in a `Vec` is allowed
    (vec_box_size_threshold, "vec_box_size_threshold": u64, 4096),
    /// Lint: TYPE_REPETITION_IN_BOUNDS. The maximum number of bounds a trait can have to be linted
    (max_trait_bounds, "max_trait_bounds": u64, 3),
    /// Lint: STRUCT_EXCESSIVE_BOOLS. The maximum number of bools a struct can have
    (max_struct_bools, "max_struct_bools": u64, 3),
    /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. The maximum number of bools function parameters can have
    (max_fn_params_bools, "max_fn_params_bools": u64, 3),
    /// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests).
    (warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false),
    /// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses
    (disallowed_methods, "disallowed_methods": Vec<String>, Vec::<String>::new()),
    /// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators.
    (unreadable_literal_lint_fractions, "unreadable_literal_lint_fractions": bool, true),
}

impl Default for Conf {
    #[must_use]
    fn default() -> Self {
        toml::from_str("").expect("we never error on empty config files")
    }
}

/// Search for the configuration file.
pub fn lookup_conf_file() -> io::Result<Option<PathBuf>> {
    /// Possible filename to search for.
    const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];

    // Start looking for a config file in CLIPPY_CONF_DIR, or failing that, CARGO_MANIFEST_DIR.
    // If neither of those exist, use ".".
    let mut current = env::var_os("CLIPPY_CONF_DIR")
        .or_else(|| env::var_os("CARGO_MANIFEST_DIR"))
        .map_or_else(|| PathBuf::from("."), PathBuf::from);
    loop {
        for config_file_name in &CONFIG_FILE_NAMES {
            let config_file = current.join(config_file_name);
            match fs::metadata(&config_file) {
                // Only return if it's a file to handle the unlikely situation of a directory named
                // `clippy.toml`.
                Ok(ref md) if !md.is_dir() => return Ok(Some(config_file)),
                // Return the error if it's something other than `NotFound`; otherwise we didn't
                // find the project file yet, and continue searching.
                Err(e) if e.kind() != io::ErrorKind::NotFound => return Err(e),
                _ => {},
            }
        }

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

/// Produces a `Conf` filled with the default values and forwards the errors
///
/// Used internally for convenience
fn default(errors: Vec<Error>) -> (Conf, Vec<Error>) {
    (Conf::default(), errors)
}

/// Read the `toml` configuration file.
///
/// In case of error, the function tries to continue as much as possible.
pub fn read(path: &Path) -> (Conf, Vec<Error>) {
    let content = match fs::read_to_string(path) {
        Ok(content) => content,
        Err(err) => return default(vec![err.into()]),
    };

    assert!(ERRORS.lock().expect("no threading -> mutex always safe").is_empty());
    match toml::from_str(&content) {
        Ok(toml) => {
            let mut errors = ERRORS.lock().expect("no threading -> mutex always safe").split_off(0);

            let toml_ref: &Conf = &toml;

            let cyc_field: Option<u64> = toml_ref.cyclomatic_complexity_threshold;

            if cyc_field.is_some() {
                let cyc_err = "found deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead.".to_string();
                errors.push(Error::Toml(cyc_err));
            }

            (toml, errors)
        },
        Err(e) => {
            let mut errors = ERRORS.lock().expect("no threading -> mutex always safe").split_off(0);
            errors.push(Error::Toml(e.to_string()));

            default(errors)
        },
    }
}
<|endoftext|>


<commit_before>use ewma::EWMA;

struct Meter {
    value: i64,
    ewma1: EWMA
}

impl Meter {
}

fn new() -> Meter {
    let i = -5.0f64/60.0f64/1f64;

    return Meter {
        value: 0,
        ewma1: EWMA::new(1f64 - i)
    }
}<commit_msg>More complete meter<commit_after>extern crate time;

use self::time::get_time;
use self::time::Timespec;

use std::sync::Mutex;

use ewma::EWMA;

pub struct MeterSnapshot{
    count: i64,
    rate1: f64,
    rate5: f64,
    rate15: f64,
    rate_mean: f64
}

pub struct Meter {
    data: Mutex<MeterSnapshot>,
    a1: EWMA,
    a5: EWMA,
    a15: EWMA,
    start: Timespec
}

impl Meter {
    pub fn mark(&self, n: i64) {
        let mut s = self.data.lock();
        s.count += n;
        self.a1.update(n as uint);
        self.a5.update(n as uint);
        self.a15.update(n as uint);
    }

    pub fn snapshot(&self) -> MeterSnapshot{
        let s = self.data.lock();
        MeterSnapshot {
            count: s.count,
            rate1: s.rate1,
            rate5: s.rate5,
            rate15: s.rate15,
            rate_mean: s.rate_mean
        }
    }

    fn update_snapshot(&self) {
        let mut s = self.data.lock();
        s.rate1 = self.a1.rate();
        s.rate5 = self.a5.rate();
        s.rate15 = self.a15.rate();

        let diff = get_time() - self.start;
        s.rate_mean = s.count as f64 / diff.num_seconds() as f64;
    }

    pub fn tick(&mut self) {
        self.data.lock();
        self.a1.tick();
        self.a5.tick();
        self.a15.tick();
        self.update_snapshot()
    }

    pub fn new() -> Meter {
        let i = -5.0f64/60.0f64/1f64;

        let data = MeterSnapshot{
            count: 0i64,
            rate1: 0f64,
            rate5: 0f64,
            rate15: 0f64,
            rate_mean: 0f64
        };

        Meter {
            data: Mutex::new(data),
            a1: EWMA::new(1f64 - i),
            a5: EWMA::new(5f64 - i),
            a15: EWMA::new(15f64 - i),
            start: get_time()
        }
    }
}

#[cfg(test)]
mod test {
    use meter::{Meter,MeterSnapshot};

    #[test]
    fn zero() {
        let m: Meter = Meter::new();
        let s: MeterSnapshot = m.snapshot();
        assert_eq!(s.count, 0);
    }

    #[test]
    fn non_zero() {
        let m: Meter = Meter::new();
        m.mark(3);
        let s: MeterSnapshot = m.snapshot();
        assert_eq!(s.count, 3);
    }

    #[test]
    fn snapshot() {
        let m: Meter = Meter::new();
        m.mark(1);
        m.mark(1);

        let s = m.snapshot();

        m.mark(1);

        assert_eq!(s.count, 2);
        assert_eq!(m.snapshot().count, 3);
    }
}<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(clippy::all)]
#![allow(improper_ctypes)]
//! This module exposes the raw Htslib bindings.

#[cfg(feature = "bzip2")]
extern crate bzip2_sys;
#[cfg(feature = "curl")]
extern crate curl_sys;
#[cfg(feature = "libdeflate")]
extern crate libdeflate_sys;
extern crate libz_sys;
#[cfg(feature = "lzma")]
extern crate lzma_sys;

// Include on-the-fly generated bindings.
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
<commit_msg>fix: dummy release<commit_after>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(clippy::all)]
#![allow(improper_ctypes)]
//! This module exposes the raw HTSlib bindings.

#[cfg(feature = "bzip2")]
extern crate bzip2_sys;
#[cfg(feature = "curl")]
extern crate curl_sys;
#[cfg(feature = "libdeflate")]
extern crate libdeflate_sys;
extern crate libz_sys;
#[cfg(feature = "lzma")]
extern crate lzma_sys;

// Include on-the-fly generated bindings.
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
<|endoftext|>


<commit_before>extern crate cgmath;

use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use cgmath::*;

use types::*;
use polyomino::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ShapeId(u32);

#[derive(Debug)]
pub struct Shape {
    // Gameplay:
    id: ShapeId,

    //TODO: use a faster hash table or just a vec https://github.com/servo/rust-fnv
    parent_ids: HashMap<ShapeId, IVec2>,

    pub polyomino: Polyomino,
    pub zoom_scale: i32,

    // Drawing:
    pub fill_color: [f32; 3],
    pub outline_color: [f32; 3],
}

impl Shape {
    pub fn has_position(&self, p: IVec2) -> bool {
        self.polyomino.has_position(p)
    }

    pub fn has_parent(&self, parent: &Shape) -> bool {
        self.parent_ids.contains_key(&parent.id)
    }

    pub fn position_on(&self, parent: &Shape) -> IVec2 {
        self.parent_ids[&parent.id]
    }
}

fn build_fill_mesh() -> () {}

pub struct Universe {
    pub shapes: HashMap<ShapeId, Shape>, // Should probably just be a Vec
}

impl Universe {
    pub fn minimal() -> Universe {
        let id1 = ShapeId(1);
        let id2 = ShapeId(2);
        let shape1 = Shape {
            id: id1,
            parent_ids: hashmap!{ id2 => Vector2::new(0, 0) },
            polyomino: Polyomino::monomino(),
            zoom_scale: 2,
            fill_color: [1.0, 1.0, 1.0],
            outline_color: [0.5, 0.5, 0.5],
        };
        let shape2 = Shape {
            id: id2,
            parent_ids: hashmap!{ id1 => Vector2::new(0, 0) },
            polyomino: Polyomino::monomino(),
            zoom_scale: 2,
            fill_color: [1.0, 0.5, 0.5],
            outline_color: [0.5, 0.25, 0.25],
        };

        let mut shapes = HashMap::new();
        shapes.insert(id1, shape1);
        shapes.insert(id2, shape2);

        Universe { shapes: shapes }
    }

    pub fn parents_of<'a>(&'a self, shape: &'a Shape) -> impl Iterator<Item = &'a Shape> + 'a {
        shape.parent_ids.keys().map(move |id| &self.shapes[id])
    }

    pub fn parents_of_id<'a>(&'a self, shape_id: ShapeId) -> impl Iterator<Item = &'a Shape> {
        self.parents_of(&self.shapes[&shape_id])
    }

    pub fn children_of<'a>(&'a self, parent: &'a Shape) -> impl Iterator<Item = &'a Shape> {
        self.shapes.values().filter(move |s| s.has_parent(parent))
    }
    pub fn children_of_id<'a>(&'a self, parent_id: ShapeId) -> impl Iterator<Item = &'a Shape> {
        self.shapes.values().filter(move |s| {
            s.parent_ids.contains_key(&parent_id)
        })
    }

    pub fn parents_with_position_of(&self, shape: &Shape) -> Vec<(&Shape, IVec2)> {
        shape
            .parent_ids
            .iter()
            .map(|(id, pos)| (&self.shapes[id], *pos))
            .collect()
    }
}

pub struct Square<'a> {
    pub universe: &'a Universe,
    pub shape: &'a Shape,
    pub position: IVec2,
}

impl<'a> Square<'a> {
    fn location_on(&self, parent_id: ShapeId) -> Option<Location> {
        let pos_on = self.shape.parent_ids.get(&parent_id)?;
        let new_shape = &self.universe.shapes[&parent_id];
        let new_pos = (self.position + pos_on) / new_shape.zoom_scale;
        let new_subp = (self.position + pos_on) % new_shape.zoom_scale;

        Some(Location {
            square: Square {
                universe: self.universe,
                shape: new_shape,
                position: new_pos,
            },
            subposition: new_subp,
        })
    }

    fn location(&self) -> Location {
        // TODO: This sort of sanity checking is slower, probably doesn't matter
        let mut locations: Vec<Location> = self.shape
            .parent_ids
            .keys()
            .filter_map(|s| self.location_on(*s))
            .collect();

        match locations.len() {
            0 => panic!("A square is not sitting on a location!"),
            1 => locations.pop().unwrap(),
            _ => panic!("A square is sitting on multiple locations!"),
        }
    }
}

pub struct Location<'a> {
    pub square: Square<'a>,
    pub subposition: IVec2,
}

impl<'a> Location<'a> {
    pub fn inhabitant(&self) -> Option<Square> {
        let c = self.to_coordinate();

        let mut inhabitants: Vec<Square> = self.square
            .universe
            .parents_with_position_of(self.square.shape)
            .into_iter()
            .filter(|&(s, pos)| s.has_position(c - pos))
            .map(|(s, pos)| {
                Square {
                    universe: self.square.universe,
                    shape: s,
                    position: c - pos,
                }
            })
            .collect();

        if inhabitants.len() > 1 {
            // TODO: This sort of sanity checking is probably a bit slower
            panic!("A location has multiple inhabitants!");
        } else {
            inhabitants.pop()
        }
    }

    fn to_coordinate(&self) -> IVec2 {
        (self.square.position * self.square.shape.zoom_scale) + self.subposition
    }
}

// This stores offsets of each shape in the chunk

// TODO: these offsets may be too small, need a vec of offsets, one
// for each level (that can be converted to a normal form, if we want)
#[derive(Clone)]
pub struct Chunk {
    pub top_shape_ids: HashSet<(ShapeId, IVec2)>,
    pub lower_shape_ids: HashSet<(ShapeId, IVec2)>,
}

impl Chunk {
}

type ExploreResult = HashMap<ShapeId, u16>;

impl Universe {
    fn explore_step(&self, result: &mut ExploreResult, queue: &mut VecDeque<(ShapeId, u16)>) -> () {
        while !queue.is_empty() {
            let (s, i) = queue.pop_front().unwrap();

            let needs_update: bool = match result.get(&s) {
                None => true,
                Some(i2) => i < *i2,
            };

            if !needs_update {
                continue;
            }

            result.insert(s, i);

            if i > 0 {
                for p in self.parents_of_id(s) {
                    queue.push_front((p.id, i - 1));
                }
            }

            for p in self.children_of_id(s) {
                queue.push_back((p.id, i + 1));
            }
        }
    }

    fn explore(&self, shape_ids: impl Iterator<Item = ShapeId>) -> Chunk {
        let mut result = HashMap::new();
        let mut queue = VecDeque::new();

        for sid in shape_ids {
            queue.push_back((sid, 0));
        }

        self.explore_step(&mut result, &mut queue);

        let top = result.iter().filter_map(
            |(s, d)| if *d == 0 { Some(*s) } else { None },
        ).collect();
        let lower = result.iter().filter_map(
            |(s, d)| if *d > 0 { Some(*s) } else { None },
        ).collect();

        Chunk {
            top_shape_ids: top,
            lower_shape_ids: lower
        }
    }

    pub fn chunk_of(&self, shape: &Shape) -> Chunk {
        self.explore(Some(shape.id).into_iter())
    }

    pub fn parent_of(&self, chunk: &Chunk) -> Chunk {
        self.explore(chunk.top_shape_ids.clone().into_iter())
    }
}

pub struct GameState {
    pub universe: Universe,
    pub player_chunk: Chunk,
}

impl GameState {
    pub fn minimal() -> GameState {
        let u = Universe::minimal();

        GameState {
            universe: u,
            player_chunk: Chunk {
                origin_id: ShapeId(1),
                top_shape_ids: hashset![ShapeId(1)],
                lower_shape_ids: hashset![],
            },
        }
    }
}
<commit_msg>Reorganise chunk a little<commit_after>extern crate cgmath;

use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use cgmath::*;

use types::*;
use polyomino::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ShapeId(u32);

#[derive(Debug)]
pub struct Shape {
    // Gameplay:
    id: ShapeId,

    //TODO: use a faster hash table or just a vec https://github.com/servo/rust-fnv
    parent_ids: HashMap<ShapeId, IVec2>,

    pub polyomino: Polyomino,
    pub zoom_scale: i32,

    // Drawing:
    pub fill_color: [f32; 3],
    pub outline_color: [f32; 3],
}

impl Shape {
    pub fn has_position(&self, p: IVec2) -> bool {
        self.polyomino.has_position(p)
    }

    pub fn has_parent(&self, parent: &Shape) -> bool {
        self.parent_ids.contains_key(&parent.id)
    }

    pub fn position_on(&self, parent: &Shape) -> IVec2 {
        self.parent_ids[&parent.id]
    }
}

fn build_fill_mesh() -> () {}

pub struct Universe {
    pub shapes: HashMap<ShapeId, Shape>, // Should probably just be a Vec
}

impl Universe {
    pub fn minimal() -> Universe {
        let id1 = ShapeId(1);
        let id2 = ShapeId(2);
        let shape1 = Shape {
            id: id1,
            parent_ids: hashmap!{ id2 => Vector2::new(0, 0) },
            polyomino: Polyomino::monomino(),
            zoom_scale: 2,
            fill_color: [1.0, 1.0, 1.0],
            outline_color: [0.5, 0.5, 0.5],
        };
        let shape2 = Shape {
            id: id2,
            parent_ids: hashmap!{ id1 => Vector2::new(0, 0) },
            polyomino: Polyomino::monomino(),
            zoom_scale: 2,
            fill_color: [1.0, 0.5, 0.5],
            outline_color: [0.5, 0.25, 0.25],
        };

        let mut shapes = HashMap::new();
        shapes.insert(id1, shape1);
        shapes.insert(id2, shape2);

        Universe { shapes: shapes }
    }

    pub fn parents_of<'a>(&'a self, shape: &'a Shape) -> impl Iterator<Item = &'a Shape> + 'a {
        shape.parent_ids.keys().map(move |id| &self.shapes[id])
    }

    pub fn parents_of_id<'a>(&'a self, shape_id: ShapeId) -> impl Iterator<Item = &'a Shape> {
        self.parents_of(&self.shapes[&shape_id])
    }

    pub fn children_of<'a>(&'a self, parent: &'a Shape) -> impl Iterator<Item = &'a Shape> {
        self.shapes.values().filter(move |s| s.has_parent(parent))
    }
    pub fn children_of_id<'a>(&'a self, parent_id: ShapeId) -> impl Iterator<Item = &'a Shape> {
        self.shapes.values().filter(move |s| {
            s.parent_ids.contains_key(&parent_id)
        })
    }

    pub fn parents_with_position_of(&self, shape: &Shape) -> Vec<(&Shape, IVec2)> {
        shape
            .parent_ids
            .iter()
            .map(|(id, pos)| (&self.shapes[id], *pos))
            .collect()
    }
}

pub struct Square<'a> {
    pub universe: &'a Universe,
    pub shape: &'a Shape,
    pub position: IVec2,
}

impl<'a> Square<'a> {
    fn location_on(&self, parent_id: ShapeId) -> Option<Location> {
        let pos_on = self.shape.parent_ids.get(&parent_id)?;
        let new_shape = &self.universe.shapes[&parent_id];
        let new_pos = (self.position + pos_on) / new_shape.zoom_scale;
        let new_subp = (self.position + pos_on) % new_shape.zoom_scale;

        Some(Location {
            square: Square {
                universe: self.universe,
                shape: new_shape,
                position: new_pos,
            },
            subposition: new_subp,
        })
    }

    fn location(&self) -> Location {
        // TODO: This sort of sanity checking is slower, probably doesn't matter
        let mut locations: Vec<Location> = self.shape
            .parent_ids
            .keys()
            .filter_map(|s| self.location_on(*s))
            .collect();

        match locations.len() {
            0 => panic!("A square is not sitting on a location!"),
            1 => locations.pop().unwrap(),
            _ => panic!("A square is sitting on multiple locations!"),
        }
    }
}

pub struct Location<'a> {
    pub square: Square<'a>,
    pub subposition: IVec2,
}

impl<'a> Location<'a> {
    pub fn inhabitant(&self) -> Option<Square> {
        let c = self.to_coordinate();

        let mut inhabitants: Vec<Square> = self.square
            .universe
            .parents_with_position_of(self.square.shape)
            .into_iter()
            .filter(|&(s, pos)| s.has_position(c - pos))
            .map(|(s, pos)| {
                Square {
                    universe: self.square.universe,
                    shape: s,
                    position: c - pos,
                }
            })
            .collect();

        if inhabitants.len() > 1 {
            // TODO: This sort of sanity checking is probably a bit slower
            panic!("A location has multiple inhabitants!");
        } else {
            inhabitants.pop()
        }
    }

    fn to_coordinate(&self) -> IVec2 {
        (self.square.position * self.square.shape.zoom_scale) + self.subposition
    }
}

// This stores offsets of each shape in the chunk

// TODO: these offsets may be too small, need a vec of offsets, one
// for each level (that can be converted to a normal form, if we want)
#[derive(Clone)]
pub struct Chunk {
    pub origin_id: ShapeId,
    pub top_shape_ids: HashSet<(ShapeId, IVec2)>,
    pub lower_shape_ids: HashSet<(ShapeId, IVec2)>,
}

impl Chunk {
}

impl Universe {
    type ExploreResult = HashMap<ShapeId, u16>;
    type ExploreQueue = HashMap<ShapeId, IVec2, u16>;
    fn explore_step(&self, result: &mut ExploreResult, queue: &mut ExploreQueue) -> () {
        while !queue.is_empty() {
            let (s, i) = queue.pop_front().unwrap();

            let needs_update: bool = match result.get(&s) {
                None => true,
                Some(i2) => i < *i2,
            };

            if !needs_update {
                continue;
            }

            result.insert(s, i);

            if i > 0 {
                for p in self.parents_of_id(s) {
                    queue.push_front((p.id, i - 1));
                }
            }

            for p in self.children_of_id(s) {
                queue.push_back((p.id, i + 1));
            }
        }
    }

    fn explore(&self, shape_ids: impl Iterator<Item = ShapeId>) -> Chunk {
        let mut result = HashMap::new();
        let mut queue = VecDeque::new();

        for sid in shape_ids {
            queue.push_back((sid, 0));
        }

        self.explore_step(&mut result, &mut queue);

        let top = result.iter().filter_map(
            |(s, d)| if *d == 0 { Some(*s) } else { None },
        ).collect();
        let lower = result.iter().filter_map(
            |(s, d)| if *d > 0 { Some(*s) } else { None },
        ).collect();

        Chunk {
            top_shape_ids: top,
            lower_shape_ids: lower
        }
    }

    pub fn chunk_of(&self, shape: &Shape) -> Chunk {
        self.explore(Some(shape.id).into_iter())
    }

    pub fn parent_of(&self, chunk: &Chunk) -> Chunk {
        self.explore(chunk.top_shape_ids.clone().into_iter())
    }
}

pub struct GameState {
    pub universe: Universe,
    pub player_chunk: Chunk,
}

impl GameState {
    pub fn minimal() -> GameState {
        let u = Universe::minimal();

        GameState {
            universe: u,
            player_chunk: Chunk {
                origin_id: ShapeId(1),
                top_shape_ids: hashset![ShapeId(1)],
                lower_shape_ids: hashset![],
            },
        }
    }
}
<|endoftext|>


<commit_before>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_http_server;
//!
//! use jsonrpc_core::*;
//! use jsonrpc_http_server::*;
//!
//! fn main() {
//! 	let mut io = IoHandler::default();
//! 	io.add_method("say_hello", |_: Params| {
//! 		Ok(Value::String("hello".to_string()))
//! 	});
//!
//! 	let _server = ServerBuilder::new(io).start_http(&"127.0.0.1:3030".parse().unwrap());
//! }
//! ```

#![warn(missing_docs)]

#[macro_use] extern crate log;
extern crate hyper;
extern crate unicase;
extern crate jsonrpc_core as jsonrpc;
extern crate futures;
extern crate tokio_core;

pub mod request_response;
pub mod cors;
mod handler;
mod hosts_validator;
#[cfg(test)]
mod tests;

use std::sync::{Arc, Mutex};
use std::net::SocketAddr;
use std::thread;
use std::collections::HashSet;
use std::ops::Deref;
use hyper::server;
use jsonrpc::MetaIoHandler;
use jsonrpc::reactor::{RpcHandler, RpcEventLoop, RpcEventLoopHandle};

pub use hyper::header::AccessControlAllowOrigin;
pub use handler::{PanicHandler, ServerHandler};
pub use hosts_validator::is_host_header_valid;

/// Result of starting the Server.
pub type ServerResult = Result<Server, RpcServerError>;

/// RPC Server startup error.
#[derive(Debug)]
pub enum RpcServerError {
	/// IO Error
	IoError(std::io::Error),
	/// Other Error (hyper)
	Other(hyper::error::Error),
}

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

impl From<hyper::error::Error> for RpcServerError {
	fn from(err: hyper::error::Error) -> Self {
		match err {
			hyper::error::Error::Io(e) => RpcServerError::IoError(e),
			e => RpcServerError::Other(e)
		}
	}
}

/// Specifies if domains should be validated.
pub enum DomainsValidation<T> {
	/// Allow only domains on the list.
	AllowOnly(Vec<T>),
	/// Disable domains validation completely.
	Disabled,
}

impl<T> Into<Option<Vec<T>>> for DomainsValidation<T> {
	fn into(self) -> Option<Vec<T>> {
		use DomainsValidation::*;
		match self {
			AllowOnly(list) => Some(list),
			Disabled => None,
		}
	}
}

impl<T> From<Option<Vec<T>>> for DomainsValidation<T> {
	fn from(other: Option<Vec<T>>) -> Self {
		match other {
			Some(list) => DomainsValidation::AllowOnly(list),
			None => DomainsValidation::Disabled,
		}
	}
}

/// Extracts metadata from the HTTP request.
pub trait HttpMetaExtractor<M: jsonrpc::Metadata>: Sync + Send + 'static {
	/// Read the metadata from the request
	fn read_metadata(&self, _: &server::Request<hyper::net::HttpStream>) -> M {
		Default::default()
	}
}

#[derive(Default)]
struct NoopExtractor;
impl<M: jsonrpc::Metadata> HttpMetaExtractor<M> for NoopExtractor {}

/// Basic RPC abstraction.
#[derive(Clone)]
pub struct Rpc<M: jsonrpc::Metadata = ()> {
	/// RPC Handler
	pub handler: RpcHandler<M>,
	/// Metadata extractor
	pub extractor: Arc<HttpMetaExtractor<M>>,
}

impl<M: jsonrpc::Metadata> From<RpcHandler<M>> for Rpc<M> {
	fn from(handler: RpcHandler<M>) -> Self {
		Rpc {
			handler: handler,
			extractor: Arc::new(NoopExtractor),
		}
	}
}

impl<M: jsonrpc::Metadata> Deref for Rpc<M> {
	type Target = RpcHandler<M>;

	fn deref(&self) -> &Self::Target {
		&self.handler
	}
}

enum Handler<M: jsonrpc::Metadata> {
	Simple(MetaIoHandler<M>),
	WithLoop(RpcHandler<M>),
}

/// Convenient JSON-RPC HTTP Server builder.
pub struct ServerBuilder<M: jsonrpc::Metadata = ()> {
	jsonrpc_handler: Handler<M>,
	meta_extractor: Arc<HttpMetaExtractor<M>>,
	cors_domains: Option<Vec<AccessControlAllowOrigin>>,
	allowed_hosts: Option<Vec<String>>,
	panic_handler: Option<Box<Fn() -> () + Send>>,
}

impl<M: jsonrpc::Metadata> ServerBuilder<M> {
	/// Creates new `ServerBuilder` for given `IoHandler`.
	///
	/// If you want to re-use the same handler in couple places
	/// see `with_remote` function.
	///
	/// By default:
	/// 1. Server is not sending any CORS headers.
	/// 2. Server is validating `Host` header.
	pub fn new<T>(handler: T) -> Self where
		T: Into<MetaIoHandler<M>>
	{
		ServerBuilder {
			jsonrpc_handler: Handler::Simple(handler.into()),
			meta_extractor: Arc::new(NoopExtractor::default()),
			cors_domains: None,
			allowed_hosts: None,
			panic_handler: None,
		}
	}

	/// Creates new `ServerBuilder` given access to the event loop `Remote`.
	///
	/// By default:
	/// 1. Server is not sending any CORS headers.
	/// 2. Server is validating `Host` header.
	pub fn with_rpc_handler(handler: RpcHandler<M>) -> Self {
		ServerBuilder {
			jsonrpc_handler: Handler::WithLoop(handler),
			meta_extractor: Arc::new(NoopExtractor::default()),
			cors_domains: None,
			allowed_hosts: None,
			panic_handler: None,
		}
	}

	/// Sets handler invoked in case of server panic.
	pub fn panic_handler<F>(mut self, handler: F) -> Self where F : Fn() -> () + Send + 'static {
		self.panic_handler = Some(Box::new(handler));
		self
	}

	/// Configures a list of allowed CORS origins.
	pub fn cors(mut self, cors_domains: DomainsValidation<AccessControlAllowOrigin>) -> Self {
		self.cors_domains = cors_domains.into();
		self
	}

	/// Configures metadata extractor
	pub fn meta_extractor(mut self, extractor: Arc<HttpMetaExtractor<M>>) -> Self {
		self.meta_extractor = extractor;
		self
	}

	/// Allow connections only with `Host` header set to binding address.
	pub fn allow_only_bind_host(mut self) -> Self {
		self.allowed_hosts = Some(Vec::new());
		self
	}

	/// Specify a list of valid `Host` headers. Binding address is allowed automatically.
	pub fn allowed_hosts(mut self, allowed_hosts: DomainsValidation<String>) -> Self {
		self.allowed_hosts = allowed_hosts.into();
		self
	}

	/// Start this JSON-RPC HTTP server trying to bind to specified `SocketAddr`.
	pub fn start_http(self, addr: &SocketAddr) -> ServerResult {
		let panic_for_server = Arc::new(Mutex::new(self.panic_handler));
		let cors_domains = self.cors_domains;
		let hosts = Arc::new(Mutex::new(self.allowed_hosts));
		let hosts_setter = hosts.clone();

		let (handler, event_loop) = match self.jsonrpc_handler {
			Handler::WithLoop(handler) => (handler, None),
			Handler::Simple(io_handler) => {
				let event_loop = RpcEventLoop::spawn();
				(event_loop.handler(Arc::new(io_handler)), Some(event_loop.into()))
			},
		};

		let jsonrpc_handler = Rpc {
			handler: handler,
			extractor: self.meta_extractor,
		};

		let (l, srv) = try!(try!(hyper::Server::http(addr)).handle(move |control| {
			let handler = PanicHandler { handler: panic_for_server.clone() };
			let hosts = hosts.lock().unwrap().clone();
			ServerHandler::new(jsonrpc_handler.clone(), cors_domains.clone(), hosts, handler, control)
		}));

		// Add current host to allowed headers.
		// NOTE: we need to use `l.addrs()` instead of `addr`
		// it might be different!
		{
			let mut hosts = hosts_setter.lock().unwrap();
			if let Some(current_hosts) = hosts.take() {
				let mut new_hosts = current_hosts.into_iter().collect::<HashSet<_>>();
				for addr in l.addrs() {
					let address = addr.to_string();
					new_hosts.insert(address.clone());
					new_hosts.insert(address.replace("127.0.0.1", "localhost"));
				}
				// Override hosts
				*hosts = Some(new_hosts.into_iter().collect());
			}
		}

		let handle = thread::spawn(move || {
			srv.run();
		});

		Ok(Server {
			server: Some(l),
			handle: Some(handle),
			event_loop: event_loop,
		})
	}
}

/// jsonrpc http server instance
pub struct Server {
	server: Option<server::Listening>,
	handle: Option<thread::JoinHandle<()>>,
	event_loop: Option<RpcEventLoopHandle>,
}

impl Server {
	/// Returns addresses of this server
	pub fn addrs(&self) -> &[SocketAddr] {
		self.server.as_ref().unwrap().addrs()
	}

	/// Closes the server.
	pub fn close(mut self) {
		self.server.take().unwrap().close();
		self.event_loop.take().map(|v| v.close());
	}

	/// Will block, waiting for the server to finish.
	pub fn wait(mut self) -> thread::Result<()> {
		self.handle.take().unwrap().join()
	}
}

impl Drop for Server {
	fn drop(&mut self) {
		self.server.take().unwrap().close();
		self.event_loop.take().map(|v| v.close());
	}
}
<commit_msg>Better support for http meta extractor<commit_after>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_http_server;
//!
//! use jsonrpc_core::*;
//! use jsonrpc_http_server::*;
//!
//! fn main() {
//! 	let mut io = IoHandler::default();
//! 	io.add_method("say_hello", |_: Params| {
//! 		Ok(Value::String("hello".to_string()))
//! 	});
//!
//! 	let _server = ServerBuilder::new(io).start_http(&"127.0.0.1:3030".parse().unwrap());
//! }
//! ```

#![warn(missing_docs)]

#[macro_use] extern crate log;
extern crate hyper;
extern crate unicase;
extern crate jsonrpc_core as jsonrpc;
extern crate futures;
extern crate tokio_core;

pub mod request_response;
pub mod cors;
mod handler;
mod hosts_validator;
#[cfg(test)]
mod tests;

use std::sync::{Arc, Mutex};
use std::net::SocketAddr;
use std::thread;
use std::collections::HashSet;
use std::ops::Deref;
use hyper::server;
use jsonrpc::MetaIoHandler;
use jsonrpc::reactor::{RpcHandler, RpcEventLoop, RpcEventLoopHandle};

pub use hyper::header::AccessControlAllowOrigin;
pub use handler::{PanicHandler, ServerHandler};
pub use hosts_validator::is_host_header_valid;

/// Result of starting the Server.
pub type ServerResult = Result<Server, RpcServerError>;

/// RPC Server startup error.
#[derive(Debug)]
pub enum RpcServerError {
	/// IO Error
	IoError(std::io::Error),
	/// Other Error (hyper)
	Other(hyper::error::Error),
}

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

impl From<hyper::error::Error> for RpcServerError {
	fn from(err: hyper::error::Error) -> Self {
		match err {
			hyper::error::Error::Io(e) => RpcServerError::IoError(e),
			e => RpcServerError::Other(e)
		}
	}
}

/// Specifies if domains should be validated.
pub enum DomainsValidation<T> {
	/// Allow only domains on the list.
	AllowOnly(Vec<T>),
	/// Disable domains validation completely.
	Disabled,
}

impl<T> Into<Option<Vec<T>>> for DomainsValidation<T> {
	fn into(self) -> Option<Vec<T>> {
		use DomainsValidation::*;
		match self {
			AllowOnly(list) => Some(list),
			Disabled => None,
		}
	}
}

impl<T> From<Option<Vec<T>>> for DomainsValidation<T> {
	fn from(other: Option<Vec<T>>) -> Self {
		match other {
			Some(list) => DomainsValidation::AllowOnly(list),
			None => DomainsValidation::Disabled,
		}
	}
}

/// Extracts metadata from the HTTP request.
pub trait HttpMetaExtractor<M: jsonrpc::Metadata>: Sync + Send + 'static {
	/// Read the metadata from the request
	fn read_metadata(&self, _: &server::Request<hyper::net::HttpStream>) -> M {
		Default::default()
	}
}

#[derive(Default)]
struct NoopExtractor;
impl<M: jsonrpc::Metadata> HttpMetaExtractor<M> for NoopExtractor {}

/// RPC Handler bundled with metadata extractor.
#[derive(Clone)]
pub struct Rpc<M: jsonrpc::Metadata = ()> {
	/// RPC Handler
	pub handler: RpcHandler<M>,
	/// Metadata extractor
	pub extractor: Arc<HttpMetaExtractor<M>>,
}

impl<M: jsonrpc::Metadata> Rpc<M> {
	/// Creates new RPC with extractor
	pub fn new(handler: RpcHandler<M>, extractor: Arc<HttpMetaExtractor<M>>) -> Self {
		Rpc {
			handler: handler,
			extractor: extractor,
		}
	}
}

impl<M: jsonrpc::Metadata> From<RpcHandler<M>> for Rpc<M> {
	fn from(handler: RpcHandler<M>) -> Self {
		Rpc {
			handler: handler,
			extractor: Arc::new(NoopExtractor),
		}
	}
}

impl<M: jsonrpc::Metadata> Deref for Rpc<M> {
	type Target = RpcHandler<M>;

	fn deref(&self) -> &Self::Target {
		&self.handler
	}
}

enum Handler<M: jsonrpc::Metadata> {
	Simple(MetaIoHandler<M>),
	WithLoop(RpcHandler<M>),
}

/// Convenient JSON-RPC HTTP Server builder.
pub struct ServerBuilder<M: jsonrpc::Metadata = ()> {
	jsonrpc_handler: Handler<M>,
	meta_extractor: Arc<HttpMetaExtractor<M>>,
	cors_domains: Option<Vec<AccessControlAllowOrigin>>,
	allowed_hosts: Option<Vec<String>>,
	panic_handler: Option<Box<Fn() -> () + Send>>,
}

impl<M: jsonrpc::Metadata> ServerBuilder<M> {
	/// Creates new `ServerBuilder` for given `IoHandler`.
	///
	/// If you want to re-use the same handler in couple places
	/// see `with_remote` function.
	///
	/// By default:
	/// 1. Server is not sending any CORS headers.
	/// 2. Server is validating `Host` header.
	pub fn new<T>(handler: T) -> Self where
		T: Into<MetaIoHandler<M>>
	{
		ServerBuilder {
			jsonrpc_handler: Handler::Simple(handler.into()),
			meta_extractor: Arc::new(NoopExtractor::default()),
			cors_domains: None,
			allowed_hosts: None,
			panic_handler: None,
		}
	}

	/// Creates new `ServerBuilder` given access to the event loop `Remote`.
	///
	/// By default:
	/// 1. Server is not sending any CORS headers.
	/// 2. Server is validating `Host` header.
	pub fn with_rpc_handler(handler: RpcHandler<M>) -> Self {
		ServerBuilder {
			jsonrpc_handler: Handler::WithLoop(handler),
			meta_extractor: Arc::new(NoopExtractor::default()),
			cors_domains: None,
			allowed_hosts: None,
			panic_handler: None,
		}
	}

	/// Sets handler invoked in case of server panic.
	pub fn panic_handler<F>(mut self, handler: F) -> Self where F : Fn() -> () + Send + 'static {
		self.panic_handler = Some(Box::new(handler));
		self
	}

	/// Configures a list of allowed CORS origins.
	pub fn cors(mut self, cors_domains: DomainsValidation<AccessControlAllowOrigin>) -> Self {
		self.cors_domains = cors_domains.into();
		self
	}

	/// Configures metadata extractor
	pub fn meta_extractor(mut self, extractor: Arc<HttpMetaExtractor<M>>) -> Self {
		self.meta_extractor = extractor;
		self
	}

	/// Allow connections only with `Host` header set to binding address.
	pub fn allow_only_bind_host(mut self) -> Self {
		self.allowed_hosts = Some(Vec::new());
		self
	}

	/// Specify a list of valid `Host` headers. Binding address is allowed automatically.
	pub fn allowed_hosts(mut self, allowed_hosts: DomainsValidation<String>) -> Self {
		self.allowed_hosts = allowed_hosts.into();
		self
	}

	/// Start this JSON-RPC HTTP server trying to bind to specified `SocketAddr`.
	pub fn start_http(self, addr: &SocketAddr) -> ServerResult {
		let panic_for_server = Arc::new(Mutex::new(self.panic_handler));
		let cors_domains = self.cors_domains;
		let hosts = Arc::new(Mutex::new(self.allowed_hosts));
		let hosts_setter = hosts.clone();

		let (handler, event_loop) = match self.jsonrpc_handler {
			Handler::WithLoop(handler) => (handler, None),
			Handler::Simple(io_handler) => {
				let event_loop = RpcEventLoop::spawn();
				(event_loop.handler(Arc::new(io_handler)), Some(event_loop.into()))
			},
		};

		let jsonrpc_handler = Rpc {
			handler: handler,
			extractor: self.meta_extractor,
		};

		let (l, srv) = try!(try!(hyper::Server::http(addr)).handle(move |control| {
			let handler = PanicHandler { handler: panic_for_server.clone() };
			let hosts = hosts.lock().unwrap().clone();
			ServerHandler::new(jsonrpc_handler.clone(), cors_domains.clone(), hosts, handler, control)
		}));

		// Add current host to allowed headers.
		// NOTE: we need to use `l.addrs()` instead of `addr`
		// it might be different!
		{
			let mut hosts = hosts_setter.lock().unwrap();
			if let Some(current_hosts) = hosts.take() {
				let mut new_hosts = current_hosts.into_iter().collect::<HashSet<_>>();
				for addr in l.addrs() {
					let address = addr.to_string();
					new_hosts.insert(address.clone());
					new_hosts.insert(address.replace("127.0.0.1", "localhost"));
				}
				// Override hosts
				*hosts = Some(new_hosts.into_iter().collect());
			}
		}

		let handle = thread::spawn(move || {
			srv.run();
		});

		Ok(Server {
			server: Some(l),
			handle: Some(handle),
			event_loop: event_loop,
		})
	}
}

/// jsonrpc http server instance
pub struct Server {
	server: Option<server::Listening>,
	handle: Option<thread::JoinHandle<()>>,
	event_loop: Option<RpcEventLoopHandle>,
}

impl Server {
	/// Returns addresses of this server
	pub fn addrs(&self) -> &[SocketAddr] {
		self.server.as_ref().unwrap().addrs()
	}

	/// Closes the server.
	pub fn close(mut self) {
		self.server.take().unwrap().close();
		self.event_loop.take().map(|v| v.close());
	}

	/// Will block, waiting for the server to finish.
	pub fn wait(mut self) -> thread::Result<()> {
		self.handle.take().unwrap().join()
	}
}

impl Drop for Server {
	fn drop(&mut self) {
		self.server.take().unwrap().close();
		self.event_loop.take().map(|v| v.close());
	}
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use std::rc::Rc;
use mimir::rubber::{Rubber, TypedIndex};
use utils::{format_label, get_zip_codes_from_admins};
use mimir;
use admin_geofinder::AdminGeoFinder;
use std::collections::HashMap;
use std::mem::replace;

const GLOBAL_STOP_INDEX_NAME: &'static str = "munin_global_stops";

pub fn set_weights<'a, It>(stops: It, nb_stop_points: &HashMap<String, u32>)
where
    It: Iterator<Item = &'a mut mimir::Stop>,
{
    let max = *nb_stop_points.values().max().unwrap_or(&1) as f64;
    for stop in stops {
        stop.weight = if let Some(weight) = nb_stop_points.get(&stop.id) {
            *weight as f64 / max
        } else {
            0.
        };
    }
}

pub fn import_stops(mut stops: Vec<mimir::Stop>, connection_string: &str, dataset: &str) {
    info!("creation of indexes");
    let mut rubber = Rubber::new(connection_string);
    rubber.initialize_templates().unwrap();

    attach_stops_to_admins(stops.iter_mut(), &mut rubber);

    for stop in &mut stops {
        stop.coverages.push(dataset.to_string());
    }

    let global_index = update_global_stop_index(&mut rubber, stops.iter(), dataset).unwrap();

    info!("Importing {} stops into Mimir", stops.len());
    let nb_stops = rubber.index(dataset, stops.iter()).unwrap();
    info!("Nb of indexed stops: {}", nb_stops);

    publish_global_index(&mut rubber, &global_index).unwrap();
}

fn attach_stop(stop: &mut mimir::Stop, admins: Vec<Rc<mimir::Admin>>) {
    stop.administrative_regions = admins;
    stop.label = format_label(&stop.administrative_regions, &stop.name);
    stop.zip_codes = get_zip_codes_from_admins(&stop.administrative_regions);
}

/// Attach the stops to administrative regions
///
/// The admins are loaded from Elasticsearch and stored in a quadtree
/// We attach a stop with all the admins that have a boundary containing
/// the coordinate of the stop
fn attach_stops_to_admins<'a, It: Iterator<Item = &'a mut mimir::Stop>>(
    stops: It,
    rubber: &mut Rubber,
) {
    let admins = rubber.get_all_admins().unwrap_or_else(|_| {
        info!("Administratives regions not found in elasticsearch db");
        vec![]
    });

    info!("{} administrative regions loaded from mimir", admins.len());

    let admins_geofinder = admins.into_iter().collect::<AdminGeoFinder>();

    let mut nb_unmatched = 0u32;
    let mut nb_matched = 0u32;
    for mut stop in stops {
        let admins = admins_geofinder.get(&stop.coord);

        if admins.is_empty() {
            nb_unmatched += 1;
        } else {
            nb_matched += 1;
        }

        attach_stop(&mut stop, admins);
    }

    info!(
        "there are {}/{} stops without any admin",
        nb_unmatched,
        nb_matched + nb_unmatched
    );
}

/// merge the stops from all the different indexes
/// for the moment the merge is very simple and uses only the ID
/// (and we take the data from the first stop inserted)
fn merge_stops<It: IntoIterator<Item = mimir::Stop>>(
    stops: It,
) -> Box<Iterator<Item = mimir::Stop>> {
    let mut stops_by_id = HashMap::<String, mimir::Stop>::new();
    for mut stop in stops.into_iter() {
        let cov = replace(&mut stop.coverages, vec![]);
        stops_by_id
            .entry(stop.id.clone())
            .or_insert(stop)
            .coverages
            .extend(cov.into_iter());
    }
    Box::new(stops_by_id.into_iter().map(|(_, v)| v))
}

fn get_all_stops(rubber: &mut Rubber, index: String) -> Result<Vec<mimir::Stop>, String> {
    rubber
        .get_all_objects_from_index(&index)
        .map_err(|e| e.to_string())
}

fn update_global_stop_index<'a, It: Iterator<Item = &'a mimir::Stop>>(
    rubber: &mut Rubber,
    stops: It,
    dataset: &str,
) -> Result<String, String> {
    let dataset_index = mimir::rubber::get_main_type_and_dataset_index::<mimir::Stop>(dataset);
    let stops_indexes = rubber
        .get_all_aliased_index(&mimir::rubber::get_main_type_index::<mimir::Stop>())?
        .into_iter()
        .filter(|&(_, ref aliases)| !aliases.contains(&dataset_index))
        .map(|(index, _)| index);

    let all_other_es_stops: Vec<_> = stops_indexes
        .map(|index| get_all_stops(rubber, index).unwrap())
        .flat_map(|stops| stops.into_iter())
        .collect();

    let all_es_stops = all_other_es_stops
        .into_iter()
        .chain(stops.into_iter().cloned());

    let all_merged_stops = merge_stops(all_es_stops);
    let es_index_name = mimir::rubber::get_date_index_name(GLOBAL_STOP_INDEX_NAME);

    rubber.create_index(&es_index_name)?;
    let typed_index = TypedIndex::new(es_index_name.clone());

    let nb_stops_added = rubber
        .bulk_index(&typed_index, all_merged_stops)
        .map_err(|e| e.to_string())?;
    info!("{} stops added in the global index", nb_stops_added);
    // create global index
    // fill structure for each stop indexes
    Ok(es_index_name)
}

// publish the global stop index
// alias the new index to the global stop alias, and remove the old index
fn publish_global_index(rubber: &mut Rubber, new_global_index: &str) -> Result<(), String> {
    let last_global_indexes: Vec<_> = rubber
        .get_all_aliased_index(GLOBAL_STOP_INDEX_NAME)?
        .into_iter()
        .map(|(k, _)| k)
        .filter(|k| k != new_global_index)
        .collect();
    rubber.alias(
        GLOBAL_STOP_INDEX_NAME,
        &vec![new_global_index.to_string()],
        &last_global_indexes,
    )?;

    for index in last_global_indexes {
        rubber.delete_index(&index)?;
    }
    Ok(())
}
<commit_msg>first impl<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use std::rc::Rc;
use mimir::rubber::{Rubber, TypedIndex};
use utils::{format_label, get_zip_codes_from_admins};
use mimir;
use admin_geofinder::AdminGeoFinder;
use std::collections::HashMap;
use std::mem::replace;

const GLOBAL_STOP_INDEX_NAME: &'static str = "munin_global_stops";

pub fn set_weights<'a, It>(stops: It, nb_stop_points: &HashMap<String, u32>)
where
    It: Iterator<Item = &'a mut mimir::Stop>,
{
    let max = *nb_stop_points.values().max().unwrap_or(&1) as f64;
    for stop in stops {
        stop.weight = if let Some(weight) = nb_stop_points.get(&stop.id) {
            *weight as f64 / max
        } else {
            0.
        };
    }
}

pub fn import_stops(mut stops: Vec<mimir::Stop>, connection_string: &str, dataset: &str) {
    info!("creation of indexes");
    let mut rubber = Rubber::new(connection_string);
    rubber.initialize_templates().unwrap();

    attach_stops_to_admins(stops.iter_mut(), &mut rubber);

    for stop in &mut stops {
        stop.coverages.push(dataset.to_string());
    }

    let global_index = update_global_stop_index(&mut rubber, stops.iter(), dataset).unwrap();

    info!("Importing {} stops into Mimir", stops.len());
    let nb_stops = rubber.index(dataset, stops.iter()).unwrap();
    info!("Nb of indexed stops: {}", nb_stops);

    publish_global_index(&mut rubber, &global_index).unwrap();
}

fn attach_stop(stop: &mut mimir::Stop, admins: Vec<Rc<mimir::Admin>>) {
    stop.administrative_regions = admins;
    stop.label = format_label(&stop.administrative_regions, &stop.name);
    stop.zip_codes = get_zip_codes_from_admins(&stop.administrative_regions);
}

/// Attach the stops to administrative regions
///
/// The admins are loaded from Elasticsearch and stored in a quadtree
/// We attach a stop with all the admins that have a boundary containing
/// the coordinate of the stop
fn attach_stops_to_admins<'a, It: Iterator<Item = &'a mut mimir::Stop>>(
    stops: It,
    rubber: &mut Rubber,
) {
    let admins = rubber.get_all_admins().unwrap_or_else(|_| {
        info!("Administratives regions not found in elasticsearch db");
        vec![]
    });

    info!("{} administrative regions loaded from mimir", admins.len());

    let admins_geofinder = admins.into_iter().collect::<AdminGeoFinder>();

    let mut nb_unmatched = 0u32;
    let mut nb_matched = 0u32;
    for mut stop in stops {
        let admins = admins_geofinder.get(&stop.coord);

        if admins.is_empty() {
            nb_unmatched += 1;
        } else {
            nb_matched += 1;
        }

        attach_stop(&mut stop, admins);
    }

    info!(
        "there are {}/{} stops without any admin",
        nb_unmatched,
        nb_matched + nb_unmatched
    );
}

fn merge_codes(es_stop: &mut mimir::Stop, codes: Vec<mimir::Code>) {
	let filtered_codes;
	{
		let is_not_existent = |code: &mimir::Code| -> bool {
			for es_code in &es_stop.codes {
				if code.name == es_code.name && code.value == es_code.value {
					return true
				}
			}
			return true
		};
		filtered_codes = codes.into_iter().filter(is_not_existent).collect::<Vec<mimir::Code>>();
	}
	es_stop.codes.extend(filtered_codes.into_iter());
}

fn merge_physical_modes(es_stop: &mut mimir::Stop, modes: Vec<mimir::PhysicalMode>) {
	let filtered_modes;
	{
		let is_not_existent = |code: &mimir::PhysicalMode| -> bool {
			for es_code in &es_stop.physical_modes {
				if code.id == es_code.id && code.name == es_code.name {
					return true
				}
			}
			return true
		};
		filtered_modes = modes.into_iter().filter(is_not_existent).collect::<Vec<mimir::PhysicalMode>>();
	}
	es_stop.physical_modes.extend(filtered_modes.into_iter());
}

/// merge the stops from all the different indexes
/// for the moment the merge is very simple and uses only the ID
/// (and we take the data from the first stop inserted)
fn merge_stops<It: IntoIterator<Item = mimir::Stop>>(
    stops: It,
) -> Box<Iterator<Item = mimir::Stop>> {
    let mut stops_by_id = HashMap::<String, mimir::Stop>::new();
    for mut stop in stops.into_iter() {
        let cov = replace(&mut stop.coverages, vec![]);
        let mut codes = replace(&mut stop.codes, vec![]);
        let mut physical_modes = replace(&mut stop.physical_modes, vec![]);

        let mut stop_in_map = stops_by_id
            .entry(stop.id.clone())
            .or_insert(stop);

		merge_codes(stop_in_map, codes);
		merge_physical_modes(stop_in_map, physical_modes);

        stop_in_map.coverages
            .extend(cov.into_iter());
    }
    Box::new(stops_by_id.into_iter().map(|(_, v)| v))
}

fn get_all_stops(rubber: &mut Rubber, index: String) -> Result<Vec<mimir::Stop>, String> {
    rubber
        .get_all_objects_from_index(&index)
        .map_err(|e| e.to_string())
}

fn update_global_stop_index<'a, It: Iterator<Item = &'a mimir::Stop>>(
    rubber: &mut Rubber,
    stops: It,
    dataset: &str,
) -> Result<String, String> {
    let dataset_index = mimir::rubber::get_main_type_and_dataset_index::<mimir::Stop>(dataset);
    let stops_indexes = rubber
        .get_all_aliased_index(&mimir::rubber::get_main_type_index::<mimir::Stop>())?
        .into_iter()
        .filter(|&(_, ref aliases)| !aliases.contains(&dataset_index))
        .map(|(index, _)| index);

    let all_other_es_stops: Vec<_> = stops_indexes
        .map(|index| get_all_stops(rubber, index).unwrap())
        .flat_map(|stops| stops.into_iter())
        .collect();

    let all_es_stops = all_other_es_stops
        .into_iter()
        .chain(stops.into_iter().cloned());

    let all_merged_stops = merge_stops(all_es_stops);
    let es_index_name = mimir::rubber::get_date_index_name(GLOBAL_STOP_INDEX_NAME);

    rubber.create_index(&es_index_name)?;
    let typed_index = TypedIndex::new(es_index_name.clone());

    let nb_stops_added = rubber
        .bulk_index(&typed_index, all_merged_stops)
        .map_err(|e| e.to_string())?;
    info!("{} stops added in the global index", nb_stops_added);
    // create global index
    // fill structure for each stop indexes
    Ok(es_index_name)
}

// publish the global stop index
// alias the new index to the global stop alias, and remove the old index
fn publish_global_index(rubber: &mut Rubber, new_global_index: &str) -> Result<(), String> {
    let last_global_indexes: Vec<_> = rubber
        .get_all_aliased_index(GLOBAL_STOP_INDEX_NAME)?
        .into_iter()
        .map(|(k, _)| k)
        .filter(|k| k != new_global_index)
        .collect();
    rubber.alias(
        GLOBAL_STOP_INDEX_NAME,
        &vec![new_global_index.to_string()],
        &last_global_indexes,
    )?;

    for index in last_global_indexes {
        rubber.delete_index(&index)?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use std::fmt::{Display, Formatter, Error};
use std::collections::HashMap;
use core::*;
use core::Instruction::*;
use lex::{lex_program, Label, Line};

#[derive(Debug, PartialEq)]
pub enum ParseProgramError {
    InvalidLabel,
    UndefinedLabel(String),
    DuplicateLabel(String),
    InvalidOpcode(String),
    InvalidExpression(String),
    InvalidRegister(String),
    MissingOperand(String),
    TooManyOperands(String),
}

impl Display for ParseProgramError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match self {
            &InvalidLabel => f.write_str("invalid label"),
            &UndefinedLabel(ref lbl) => f.write_fmt(format_args!("undefined label: '{}'", lbl)),
            &DuplicateLabel(ref lbl) => f.write_fmt(format_args!("label is already defined: '{}'", lbl)),
            &InvalidOpcode(ref op) => f.write_fmt(format_args!("invalid opcode: '{}'", op)),
            &InvalidExpression(ref expr) => f.write_fmt(format_args!("invalid expression: '{}'", expr)),
            &InvalidRegister(ref reg) => f.write_fmt(format_args!("invalid register: '{}'", reg)),
            &MissingOperand(ref op) => f.write_fmt(format_args!("missing operand: '{}'", op)),
            &TooManyOperands(ref ops) => f.write_fmt(format_args!("too many operands: '{}'", ops)),
        }
    }
}

pub type ProgramErrors = Vec<(usize, ParseProgramError)>;

use self::ParseProgramError::*;

type ParseResult<T> = Result<T, ParseProgramError>;

/// Parse the program source code into a list of instructions. If one or more errors are
/// encountered during parsing, then the list of errors will be returned instead.
///
/// Example:
///
/// ```
/// use tis_100::core::Instruction::*;
/// use tis_100::core::Source::*;
/// use tis_100::core::Register::*;
/// use tis_100::core::IoRegister::*;
/// use tis_100::core::Port::*;
/// use tis_100::parse::parse_program;
///
/// let src = "MOV UP ACC\nADD 1\nMOV ACC DOWN\n";
/// let prog = parse_program(src).unwrap();
/// assert_eq!(prog[0], Mov(REG(IO(DIR(UP))), ACC));
/// assert_eq!(prog[1], Add(VAL(1)));
/// assert_eq!(prog[2], Mov(REG(ACC), IO(DIR(DOWN))));
/// ```
pub fn parse_program(src: &str) -> Result<Program, ProgramErrors> {
    let mut label_map = HashMap::new();
    let mut instructions = Vec::new();
    let mut errors = Vec::new();

    let lines = lex_program(src);

    for &Line(line_num, ref maybe_label, _) in lines.iter() {
        if let &Some(Label(ref name, index)) = maybe_label {
            if name.len() == 0 {
                errors.push((line_num, InvalidLabel));
            } else if let None = label_map.get(name) {
                label_map.insert(name.clone(), index as isize);
            } else {
                errors.push((line_num, DuplicateLabel(name.clone())));
            }
        }
    }

    for &Line(line_num, _, ref lexemes) in lines.iter() {
        if lexemes.len() > 0 {
            match parse_instruction(&lexemes[0], &lexemes[1..], &label_map) {
                Ok(instruction) => instructions.push(instruction),
                Err(err) => errors.push((line_num, err)),
            }
        }
    }

    if errors.len() > 0 {
        Err(errors)
    } else {
        Ok(instructions)
    }
}

fn parse_instruction(opcode: &str, operands: &[String], labels: &HashMap<String, isize>) -> ParseResult<Instruction> {
    match str::parse::<Opcode>(opcode) {
        Ok(NOP) => parse_no_operands(Nop, operands),
        Ok(MOV) => parse_two_operands(Mov, opcode, operands),
        Ok(SWP) => parse_no_operands(Swp, operands),
        Ok(SAV) => parse_no_operands(Sav, operands),
        Ok(ADD) => parse_one_operand(Add, opcode, operands),
        Ok(SUB) => parse_one_operand(Sub, opcode, operands),
        Ok(NEG) => parse_no_operands(Neg, operands),
        Ok(JMP) => parse_jump(Jmp, opcode, operands, labels),
        Ok(JEZ) => parse_jump(Jez, opcode, operands, labels),
        Ok(JNZ) => parse_jump(Jnz, opcode, operands, labels),
        Ok(JGZ) => parse_jump(Jgz, opcode, operands, labels),
        Ok(JLZ) => parse_jump(Jlz, opcode, operands, labels),
        Ok(JRO) => parse_one_operand(Jro, opcode, operands),
        _ => Err(InvalidOpcode(opcode.to_string())),
    }
}

fn resolve_label<'a>(label: &str, labels: &'a HashMap<String, isize>) -> ParseResult<&'a isize> {
    labels.get(label).ok_or(UndefinedLabel(label.to_string()))
}

fn parse_jump<F: Fn(isize) -> Instruction>(f: F, opcode: &str, operands: &[String], labels: &HashMap<String, isize>) -> ParseResult<Instruction> {
    if operands.len() < 1 {
        Err(MissingOperand(opcode.to_string()))
    } else if operands.len() == 1 {
        resolve_label(&operands[0], labels).map(|&i| f(i))
    } else {
        Err(TooManyOperands(operands[1..].connect(" ")))
    }
}

fn parse_no_operands(instruction: Instruction, operands: &[String]) -> ParseResult<Instruction> {
    if operands.len() == 0 {
        Ok(instruction)
    } else {
        Err(TooManyOperands(operands.connect(" ")))
    }
}

fn parse_one_operand<T: FromStr, F: Fn(T) -> Instruction>(f: F, opcode: &str, operands: &[String]) -> ParseResult<Instruction> {
    if operands.len() < 1 {
        Err(MissingOperand(opcode.to_string()))
    } else if operands.len() == 1 {
        match str::parse::<T>(&operands[0]) {
            Ok(op) => Ok(f(op)),
            Err(_) => Err(InvalidExpression(operands[0].clone())),
        }
    } else {
        Err(TooManyOperands(operands[1..].connect(" ")))
    }
}

fn parse_two_operands<T: FromStr, U: FromStr, F: Fn(T, U) -> Instruction>(f: F, opcode: &str, operands: &[String]) -> ParseResult<Instruction> {
    if operands.len() < 2 {
        Err(MissingOperand(opcode.to_string() + &operands.connect(" ")))
    } else if operands.len() == 2 {
        match str::parse::<T>(&operands[0]) {
            Ok(op1) => match str::parse::<U>(&operands[1]) {
                Ok(op2) => Ok(f(op1, op2)),
                Err(_) => Err(InvalidRegister(operands[1].clone())),
            },
            Err(_) => Err(InvalidExpression(operands[0].clone())),
        }
    } else {
        Err(TooManyOperands(operands[2..].connect(" ")))
    }
}

/// The opcode component of a TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Opcode {
    NOP,
    MOV,
    SWP,
    SAV,
    ADD,
    SUB,
    NEG,
    JMP,
    JEZ,
    JNZ,
    JGZ,
    JLZ,
    JRO,
}

use self::Opcode::*;

/// An error which can be returned when parsing an opcode.
#[derive(Debug, PartialEq)]
pub struct ParseOpcodeError;

impl FromStr for Opcode {
    type Err = ParseOpcodeError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "NOP" => Ok(NOP),
            "MOV" => Ok(MOV),
            "SWP" => Ok(SWP),
            "SAV" => Ok(SAV),
            "ADD" => Ok(ADD),
            "SUB" => Ok(SUB),
            "NEG" => Ok(NEG),
            "JMP" => Ok(JMP),
            "JEZ" => Ok(JEZ),
            "JNZ" => Ok(JNZ),
            "JGZ" => Ok(JGZ),
            "JLZ" => Ok(JLZ),
            "JRO" => Ok(JRO),
            _ => Err(ParseOpcodeError),
        }
    }
}

#[test]
fn test_parse_opcode() {
    assert_eq!(str::parse::<Opcode>("NOP"), Ok(NOP));
    assert_eq!(str::parse::<Opcode>("MOV"), Ok(MOV));
    assert_eq!(str::parse::<Opcode>("SWP"), Ok(SWP));
    assert_eq!(str::parse::<Opcode>("SAV"), Ok(SAV));
    assert_eq!(str::parse::<Opcode>("ADD"), Ok(ADD));
    assert_eq!(str::parse::<Opcode>("SUB"), Ok(SUB));
    assert_eq!(str::parse::<Opcode>("NEG"), Ok(NEG));
    assert_eq!(str::parse::<Opcode>("JMP"), Ok(JMP));
    assert_eq!(str::parse::<Opcode>("JEZ"), Ok(JEZ));
    assert_eq!(str::parse::<Opcode>("JNZ"), Ok(JNZ));
    assert_eq!(str::parse::<Opcode>("JGZ"), Ok(JGZ));
    assert_eq!(str::parse::<Opcode>("JLZ"), Ok(JLZ));
    assert_eq!(str::parse::<Opcode>("JRO"), Ok(JRO));
    assert_eq!(str::parse::<Opcode>("nop"), Err(ParseOpcodeError));
    assert_eq!(str::parse::<Opcode>("bad"), Err(ParseOpcodeError));
}
<commit_msg>Fix formatting for missing operands error on mov instruction<commit_after>use std::str::FromStr;
use std::fmt::{Display, Formatter, Error};
use std::collections::HashMap;
use core::*;
use core::Instruction::*;
use lex::{lex_program, Label, Line};

#[derive(Debug, PartialEq)]
pub enum ParseProgramError {
    InvalidLabel,
    UndefinedLabel(String),
    DuplicateLabel(String),
    InvalidOpcode(String),
    InvalidExpression(String),
    InvalidRegister(String),
    MissingOperand(String),
    TooManyOperands(String),
}

impl Display for ParseProgramError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match self {
            &InvalidLabel => f.write_str("invalid label"),
            &UndefinedLabel(ref lbl) => f.write_fmt(format_args!("undefined label: '{}'", lbl)),
            &DuplicateLabel(ref lbl) => f.write_fmt(format_args!("label is already defined: '{}'", lbl)),
            &InvalidOpcode(ref op) => f.write_fmt(format_args!("invalid opcode: '{}'", op)),
            &InvalidExpression(ref expr) => f.write_fmt(format_args!("invalid expression: '{}'", expr)),
            &InvalidRegister(ref reg) => f.write_fmt(format_args!("invalid register: '{}'", reg)),
            &MissingOperand(ref op) => f.write_fmt(format_args!("missing operand: '{}'", op)),
            &TooManyOperands(ref ops) => f.write_fmt(format_args!("too many operands: '{}'", ops)),
        }
    }
}

pub type ProgramErrors = Vec<(usize, ParseProgramError)>;

use self::ParseProgramError::*;

type ParseResult<T> = Result<T, ParseProgramError>;

/// Parse the program source code into a list of instructions. If one or more errors are
/// encountered during parsing, then the list of errors will be returned instead.
///
/// Example:
///
/// ```
/// use tis_100::core::Instruction::*;
/// use tis_100::core::Source::*;
/// use tis_100::core::Register::*;
/// use tis_100::core::IoRegister::*;
/// use tis_100::core::Port::*;
/// use tis_100::parse::parse_program;
///
/// let src = "MOV UP ACC\nADD 1\nMOV ACC DOWN\n";
/// let prog = parse_program(src).unwrap();
/// assert_eq!(prog[0], Mov(REG(IO(DIR(UP))), ACC));
/// assert_eq!(prog[1], Add(VAL(1)));
/// assert_eq!(prog[2], Mov(REG(ACC), IO(DIR(DOWN))));
/// ```
pub fn parse_program(src: &str) -> Result<Program, ProgramErrors> {
    let mut label_map = HashMap::new();
    let mut instructions = Vec::new();
    let mut errors = Vec::new();

    let lines = lex_program(src);

    for &Line(line_num, ref maybe_label, _) in lines.iter() {
        if let &Some(Label(ref name, index)) = maybe_label {
            if name.len() == 0 {
                errors.push((line_num, InvalidLabel));
            } else if let None = label_map.get(name) {
                label_map.insert(name.clone(), index as isize);
            } else {
                errors.push((line_num, DuplicateLabel(name.clone())));
            }
        }
    }

    for &Line(line_num, _, ref lexemes) in lines.iter() {
        if lexemes.len() > 0 {
            match parse_instruction(&lexemes[0], &lexemes[1..], &label_map) {
                Ok(instruction) => instructions.push(instruction),
                Err(err) => errors.push((line_num, err)),
            }
        }
    }

    if errors.len() > 0 {
        Err(errors)
    } else {
        Ok(instructions)
    }
}

fn parse_instruction(opcode: &str, operands: &[String], labels: &HashMap<String, isize>) -> ParseResult<Instruction> {
    match str::parse::<Opcode>(opcode) {
        Ok(NOP) => parse_no_operands(Nop, operands),
        Ok(MOV) => parse_two_operands(Mov, opcode, operands),
        Ok(SWP) => parse_no_operands(Swp, operands),
        Ok(SAV) => parse_no_operands(Sav, operands),
        Ok(ADD) => parse_one_operand(Add, opcode, operands),
        Ok(SUB) => parse_one_operand(Sub, opcode, operands),
        Ok(NEG) => parse_no_operands(Neg, operands),
        Ok(JMP) => parse_jump(Jmp, opcode, operands, labels),
        Ok(JEZ) => parse_jump(Jez, opcode, operands, labels),
        Ok(JNZ) => parse_jump(Jnz, opcode, operands, labels),
        Ok(JGZ) => parse_jump(Jgz, opcode, operands, labels),
        Ok(JLZ) => parse_jump(Jlz, opcode, operands, labels),
        Ok(JRO) => parse_one_operand(Jro, opcode, operands),
        _ => Err(InvalidOpcode(opcode.to_string())),
    }
}

fn resolve_label<'a>(label: &str, labels: &'a HashMap<String, isize>) -> ParseResult<&'a isize> {
    labels.get(label).ok_or(UndefinedLabel(label.to_string()))
}

fn parse_jump<F: Fn(isize) -> Instruction>(f: F, opcode: &str, operands: &[String], labels: &HashMap<String, isize>) -> ParseResult<Instruction> {
    if operands.len() < 1 {
        Err(MissingOperand(opcode.to_string()))
    } else if operands.len() == 1 {
        resolve_label(&operands[0], labels).map(|&i| f(i))
    } else {
        Err(TooManyOperands(operands[1..].connect(" ")))
    }
}

fn parse_no_operands(instruction: Instruction, operands: &[String]) -> ParseResult<Instruction> {
    if operands.len() == 0 {
        Ok(instruction)
    } else {
        Err(TooManyOperands(operands.connect(" ")))
    }
}

fn parse_one_operand<T: FromStr, F: Fn(T) -> Instruction>(f: F, opcode: &str, operands: &[String]) -> ParseResult<Instruction> {
    if operands.len() < 1 {
        Err(MissingOperand(opcode.to_string()))
    } else if operands.len() == 1 {
        match str::parse::<T>(&operands[0]) {
            Ok(op) => Ok(f(op)),
            Err(_) => Err(InvalidExpression(operands[0].clone())),
        }
    } else {
        Err(TooManyOperands(operands[1..].connect(" ")))
    }
}

fn parse_two_operands<T: FromStr, U: FromStr, F: Fn(T, U) -> Instruction>(f: F, opcode: &str, operands: &[String]) -> ParseResult<Instruction> {
    if operands.len() < 2 {
        Err(MissingOperand(opcode.to_string() + " " + &operands.connect(" ")))
    } else if operands.len() == 2 {
        match str::parse::<T>(&operands[0]) {
            Ok(op1) => match str::parse::<U>(&operands[1]) {
                Ok(op2) => Ok(f(op1, op2)),
                Err(_) => Err(InvalidRegister(operands[1].clone())),
            },
            Err(_) => Err(InvalidExpression(operands[0].clone())),
        }
    } else {
        Err(TooManyOperands(operands[2..].connect(" ")))
    }
}

/// The opcode component of a TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Opcode {
    NOP,
    MOV,
    SWP,
    SAV,
    ADD,
    SUB,
    NEG,
    JMP,
    JEZ,
    JNZ,
    JGZ,
    JLZ,
    JRO,
}

use self::Opcode::*;

/// An error which can be returned when parsing an opcode.
#[derive(Debug, PartialEq)]
pub struct ParseOpcodeError;

impl FromStr for Opcode {
    type Err = ParseOpcodeError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "NOP" => Ok(NOP),
            "MOV" => Ok(MOV),
            "SWP" => Ok(SWP),
            "SAV" => Ok(SAV),
            "ADD" => Ok(ADD),
            "SUB" => Ok(SUB),
            "NEG" => Ok(NEG),
            "JMP" => Ok(JMP),
            "JEZ" => Ok(JEZ),
            "JNZ" => Ok(JNZ),
            "JGZ" => Ok(JGZ),
            "JLZ" => Ok(JLZ),
            "JRO" => Ok(JRO),
            _ => Err(ParseOpcodeError),
        }
    }
}

#[test]
fn test_parse_opcode() {
    assert_eq!(str::parse::<Opcode>("NOP"), Ok(NOP));
    assert_eq!(str::parse::<Opcode>("MOV"), Ok(MOV));
    assert_eq!(str::parse::<Opcode>("SWP"), Ok(SWP));
    assert_eq!(str::parse::<Opcode>("SAV"), Ok(SAV));
    assert_eq!(str::parse::<Opcode>("ADD"), Ok(ADD));
    assert_eq!(str::parse::<Opcode>("SUB"), Ok(SUB));
    assert_eq!(str::parse::<Opcode>("NEG"), Ok(NEG));
    assert_eq!(str::parse::<Opcode>("JMP"), Ok(JMP));
    assert_eq!(str::parse::<Opcode>("JEZ"), Ok(JEZ));
    assert_eq!(str::parse::<Opcode>("JNZ"), Ok(JNZ));
    assert_eq!(str::parse::<Opcode>("JGZ"), Ok(JGZ));
    assert_eq!(str::parse::<Opcode>("JLZ"), Ok(JLZ));
    assert_eq!(str::parse::<Opcode>("JRO"), Ok(JRO));
    assert_eq!(str::parse::<Opcode>("nop"), Err(ParseOpcodeError));
    assert_eq!(str::parse::<Opcode>("bad"), Err(ParseOpcodeError));
}
<|endoftext|>