<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: 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, UNNESTED_OR_PATTERNS. 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", "OpenDNS",
        "WebGL",
        "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 disallowed methods, written as fully qualified paths.
    (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),
    /// Lint: UPPER_CASE_ACRONYMS. Enables verbose mode. Triggers if there is more than one uppercase char next to each other
    (upper_case_acronyms_aggressive, "upper_case_acronyms_aggressive": bool, false),
    /// Lint: _CARGO_COMMON_METADATA. For internal testing only, ignores the current `publish` settings in the Cargo manifest.
    (cargo_ignore_publish, "cargo_ignore_publish": bool, false),
}

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>Add missing lints to MSRV config doc<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, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, NEEDLESS_QUESTION_MARK, PTR_AS_PTR. 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", "OpenDNS",
        "WebGL",
        "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 disallowed methods, written as fully qualified paths.
    (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),
    /// Lint: UPPER_CASE_ACRONYMS. Enables verbose mode. Triggers if there is more than one uppercase char next to each other
    (upper_case_acronyms_aggressive, "upper_case_acronyms_aggressive": bool, false),
    /// Lint: _CARGO_COMMON_METADATA. For internal testing only, ignores the current `publish` settings in the Cargo manifest.
    (cargo_ignore_publish, "cargo_ignore_publish": bool, false),
}

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 std::{cmp, iter, mem, raw, task};

/// Parallelizes an `operation` over a mutable slice
///
/// The `data` will be divided in chunks of `granularity` size. A new task will be spawned to
/// "operate" over each chunk.
///
/// `operation` will receive two arguments:
///
/// - The mutable chunk of data, and
/// - The offset of this chunk from the start of `data`
///
/// # Panics
///
/// Panics if any of the underlying tasks panics
///
/// # Example
///
/// Parallel map
///
/// ```
/// use std::num::FloatMath;
/// use std::rand::{Rng, XorShiftRng, mod};
///
/// let ref mut rng: XorShiftRng = rand::task_rng().gen();
/// let mut v = Vec::from_fn(1_000, |_| rng.gen::<f32>());
/// # let w = v.iter().map(|x| x.sin()).collect();
/// parallel::divide(v.as_mut_slice(), 100, |data, _| {
///     for x in data.iter_mut() {
///         *x = x.sin();
///     }
/// });
/// # assert_eq!(v, w);
/// ```
// TODO (rust-lang/rfcs#387) Use unboxed closures
pub fn divide<'a, T>(
    data: &mut [T],
    granularity: uint,
    operation: |&mut [T], uint|:'a + Sync,
) where
    T: Send,
{
    assert!(granularity > 0);

    let raw::Slice { data, len } = unsafe { mem::transmute::<_, raw::Slice<T>>(data) };
    let closure = unsafe { mem::transmute::<_, raw::Closure>(operation) };

    let futures = iter::range_step(0, len, granularity).map(|offset| {
        task::try_future(proc() {
            // NB Is safe to send the slice/closure because the task won't outlive this function
            let slice = raw::Slice {
                data: unsafe { data.offset(offset as int) },
                len: cmp::min(granularity, len - offset)
            };
            let data = unsafe { mem::transmute::<_, &mut [T]>(slice) };
            let operation = unsafe { mem::transmute::<_, |&mut [T], uint|:'a + Sync>(closure) };

            operation(data, offset);
        })
    }).collect::<Vec<_>>();

    for future in futures.into_iter() {
        if future.unwrap().is_err() {
            panic!();
        }
    }
}

#[cfg(test)]
mod test {
    use quickcheck::TestResult;
    use std::rand::{Rng, XorShiftRng, mod};

    #[quickcheck]
    fn clone(size: uint, granularity: uint) -> TestResult {
        if granularity == 0 {
            return TestResult::discard();
        }

        let mut rng: XorShiftRng = rand::task_rng().gen();
        let original = Vec::from_fn(size, |_| rng.gen::<f64>());
        let mut clone = Vec::from_elem(size, 0f64);

        let original_slice = original[];
        super::divide(clone[mut], granularity, |data, offset| {
            for (i, x) in data.iter_mut().enumerate() {
                *x = original_slice[offset + i]
            }
        });

        TestResult::from_bool(original == clone)
    }

    #[quickcheck]
    fn new(size: uint, granularity: uint) -> TestResult {
        if granularity == 0 {
            return TestResult::discard();
        }

        let mut v = Vec::from_elem(size, None::<f64>);

        super::divide(v[mut], granularity, |data, _| {
            let mut rng: XorShiftRng = rand::task_rng().gen();

            for x in data.iter_mut() {
                *x = Some(rng.gen())
            }
        });

        TestResult::from_bool(v.iter().all(|&x| match x {
            None => false,
            Some(x) => x > 0. && x < 1.
        }))
    }
}
<commit_msg>feat(divide): divide now accepts unboxed closures<commit_after>use std::{cmp, iter, mem, raw, task};

/// Parallelizes an `operation` over a mutable slice
///
/// The `data` will be divided in chunks of `granularity` size. A new task will be spawned to
/// "operate" over each chunk.
///
/// `operation` will receive two arguments:
///
/// - The mutable chunk of data, and
/// - The offset of this chunk from the start of `data`
///
/// # Panics
///
/// Panics if any of the underlying tasks panics
///
/// # Example
///
/// Parallel map
///
/// ```
/// use std::num::FloatMath;
/// use std::rand::{Rng, XorShiftRng, mod};
///
/// let ref mut rng: XorShiftRng = rand::task_rng().gen();
/// let mut v = Vec::from_fn(1_000, |_| rng.gen::<f32>());
/// # let w = v.iter().map(|x| x.sin()).collect();
/// parallel::divide(v.as_mut_slice(), 100, |data, _| {
///     for x in data.iter_mut() {
///         *x = x.sin();
///     }
/// });
/// # assert_eq!(v, w);
/// ```
pub fn divide<T, F: Fn(&mut [T], uint) + Sync>(
    data: &mut [T],
    granularity: uint,
    operation: F,
) where
    T: Send,
{
    assert!(granularity > 0);

    let raw::Slice { data, len } = unsafe { mem::transmute::<_, raw::Slice<T>>(data) };
    let op = &operation as *const _ as *const ();

    let futures = iter::range_step(0, len, granularity).map(|offset| {
        task::try_future(proc() {
            // NB Is safe to send the slice/closure because the task won't outlive this function
            let slice = raw::Slice {
                data: unsafe { data.offset(offset as int) },
                len: cmp::min(granularity, len - offset)
            };
            let data = unsafe { mem::transmute::<_, &mut [T]>(slice) };
            let operation = unsafe { mem::transmute::<_, &F>(op) };

            (*operation)(data, offset);
        })
    }).collect::<Vec<_>>();

    for future in futures.into_iter() {
        if future.unwrap().is_err() {
            panic!();
        }
    }
}

#[cfg(test)]
mod test {
    use quickcheck::TestResult;
    use std::rand::{Rng, XorShiftRng, mod};

    #[quickcheck]
    fn clone(size: uint, granularity: uint) -> TestResult {
        if granularity == 0 {
            return TestResult::discard();
        }

        let mut rng: XorShiftRng = rand::task_rng().gen();
        let original = Vec::from_fn(size, |_| rng.gen::<f64>());
        let mut clone = Vec::from_elem(size, 0f64);

        let original_slice = original[];
        super::divide(clone[mut], granularity, |data, offset| {
            for (i, x) in data.iter_mut().enumerate() {
                *x = original_slice[offset + i]
            }
        });

        TestResult::from_bool(original == clone)
    }

    #[quickcheck]
    fn new(size: uint, granularity: uint) -> TestResult {
        if granularity == 0 {
            return TestResult::discard();
        }

        let mut v = Vec::from_elem(size, None::<f64>);

        super::divide(v[mut], granularity, |data, _| {
            let mut rng: XorShiftRng = rand::task_rng().gen();

            for x in data.iter_mut() {
                *x = Some(rng.gen())
            }
        });

        TestResult::from_bool(v.iter().all(|&x| match x {
            None => false,
            Some(x) => x > 0. && x < 1.
        }))
    }
}
<|endoftext|>


<commit_before>// Translation of the following Go program into Rust:
//
// ```
// func main() {
//     people := []string{"Anna", "Bob", "Cody", "Dave", "Eva"}
//     match := make(chan string, 1) // Make room for one unmatched send.
//     wg := new(sync.WaitGroup)
//     for _, name := range people {
//         wg.Add(1)
//         go Seek(name, match, wg)
//     }
//     wg.Wait()
//     select {
//     case name := <-match:
//         fmt.Printf("No one received %s’s message.\n", name)
//     default:
//         // There was no pending send operation.
//     }
// }
//
// // Seek either sends or receives, whichever possible, a name on the match
// // channel and notifies the wait group when done.
// func Seek(name string, match chan string, wg *sync.WaitGroup) {
//     select {
//     case peer := <-match:
//         fmt.Printf("%s received a message from %s.\n", name, peer)
//     case match <- name:
//         // Wait for someone to receive my message.
//     }
//     wg.Done()
// }
// ```
//
// Source: https://www.nada.kth.se/~snilsson/concurrency/#Match

extern crate crossbeam;
extern crate channel;

use channel::{select, Receiver, Sender};

fn main() {
    let people = vec!["Anna", "Bob", "Cody", "Dave", "Eva"];
    let (tx, rx) = channel::bounded(1); // Make room for one unmatched send.
    let (tx, rx) = (&tx, &rx);

    crossbeam::scope(|s| for name in people {
        s.spawn(move || seek(name, tx, rx));
    });

    if let Ok(peer) = rx.try_recv() {
        println!("No one received {}’s message.", peer);
    }
}

// Either sends or receives, whichever possible, a name on the channel.
fn seek<'a>(name: &'a str, tx: &Sender<&'a str>, rx: &Receiver<&'a str>) {
    loop {
        if let Ok(peer) = rx.select() {
            println!("{} received a message from {}.", name, peer);
            break;
        }
        if let Ok(_) = tx.select(name) {
            // Wait for someone to receive my message.
            break;
        }
    }
}
<commit_msg>Rename: peer -> name<commit_after>// Translation of the following Go program into Rust:
//
// ```
// func main() {
//     people := []string{"Anna", "Bob", "Cody", "Dave", "Eva"}
//     match := make(chan string, 1) // Make room for one unmatched send.
//     wg := new(sync.WaitGroup)
//     for _, name := range people {
//         wg.Add(1)
//         go Seek(name, match, wg)
//     }
//     wg.Wait()
//     select {
//     case name := <-match:
//         fmt.Printf("No one received %s’s message.\n", name)
//     default:
//         // There was no pending send operation.
//     }
// }
//
// // Seek either sends or receives, whichever possible, a name on the match
// // channel and notifies the wait group when done.
// func Seek(name string, match chan string, wg *sync.WaitGroup) {
//     select {
//     case peer := <-match:
//         fmt.Printf("%s received a message from %s.\n", name, peer)
//     case match <- name:
//         // Wait for someone to receive my message.
//     }
//     wg.Done()
// }
// ```
//
// Source: https://www.nada.kth.se/~snilsson/concurrency/#Match

extern crate crossbeam;
extern crate channel;

use channel::{select, Receiver, Sender};

fn main() {
    let people = vec!["Anna", "Bob", "Cody", "Dave", "Eva"];
    let (tx, rx) = channel::bounded(1); // Make room for one unmatched send.
    let (tx, rx) = (&tx, &rx);

    crossbeam::scope(|s| for name in people {
        s.spawn(move || seek(name, tx, rx));
    });

    if let Ok(name) = rx.try_recv() {
        println!("No one received {}’s message.", name);
    }
}

// Either sends or receives, whichever possible, a name on the channel.
fn seek<'a>(name: &'a str, tx: &Sender<&'a str>, rx: &Receiver<&'a str>) {
    loop {
        if let Ok(peer) = rx.select() {
            println!("{} received a message from {}.", name, peer);
            break;
        }
        if let Ok(_) = tx.select(name) {
            // Wait for someone to receive my message.
            break;
        }
    }
}
<|endoftext|>


<commit_before>use sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::Color;
use game;
use game::Direction;

pub struct Engine {
    event_pump: sdl2::EventPump,
    renderer: sdl2::render::Renderer<'static>,
    game_state: game::GameState,
}

impl Engine {
    pub fn run(&mut self) -> Result<(), String> {
        loop {
            for event in self.event_pump.poll_iter() {
                match event {
                    Event::Quit { .. } |
                    Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return Ok(()),
                    Event::KeyDown { keycode: Some(Keycode::Up), .. } => {
                        self.game_state.set_snake_dir(Direction::Up)
                    }
                    Event::KeyDown { keycode: Some(Keycode::Down), .. } => {
                        self.game_state.set_snake_dir(Direction::Down)
                    }
                    Event::KeyDown { keycode: Some(Keycode::Left), .. } => {
                        self.game_state.set_snake_dir(Direction::Left)
                    }
                    Event::KeyDown { keycode: Some(Keycode::Right), .. } => {
                        self.game_state.set_snake_dir(Direction::Right)
                    }
                    _ => (),
                }
            }
            self.game_state.update();
            self.render()?;
        }
    }

    fn render(&mut self) -> Result<(), String> {
        self.renderer.set_draw_color(Color::RGB(0, 0, 0));
        self.renderer.clear();
        let scale: u32 = 8;
        for ((y, x), &tile) in self.game_state.tiles().indexed_iter() {
            let color = match tile {
                game::Tile::Floor => Color::RGB(0, 0, 255),
                game::Tile::Wall => Color::RGB(255, 0, 0),
                game::Tile::Food => Color::RGB(255, 255, 0),
                game::Tile::Snake(_) => Color::RGB(0, 255, 0),
            };
            self.renderer.set_draw_color(color);
            self.renderer
                .fill_rect(sdl2::rect::Rect::new(x as i32 * scale as i32,
                                                 y as i32 * scale as i32,
                                                 scale,
                                                 scale))?;
        }
        self.renderer.present();

        Ok(())
    }
}

pub fn init() -> Result<Engine, String> {
    let sdl = sdl2::init()?;
    let video = sdl.video()?;
    let event_pump = sdl.event_pump()?;
    let window = video.window("Snake", 640, 480)
        .build()
        .or_else(|e| Err(format!("{}", e)))?;
    let renderer = window.renderer()
        .present_vsync()
        .build()
        .or_else(|e| Err(format!("{}", e)))?;
    let game_state = game::GameState::new();

    Ok(Engine {
           event_pump: event_pump,
           renderer: renderer,
           game_state: game_state,
       })
}
<commit_msg>Move snake only once every 10 frames<commit_after>use sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::Color;
use game;
use game::Direction;

pub struct Engine {
    event_pump: sdl2::EventPump,
    renderer: sdl2::render::Renderer<'static>,
    game_state: game::GameState,
}

impl Engine {
    pub fn run(&mut self) -> Result<(), String> {
        let mut framecounter = 0;
        loop {
            for event in self.event_pump.poll_iter() {
                match event {
                    Event::Quit { .. } |
                    Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return Ok(()),
                    Event::KeyDown { keycode: Some(Keycode::Up), .. } => {
                        self.game_state.set_snake_dir(Direction::Up)
                    }
                    Event::KeyDown { keycode: Some(Keycode::Down), .. } => {
                        self.game_state.set_snake_dir(Direction::Down)
                    }
                    Event::KeyDown { keycode: Some(Keycode::Left), .. } => {
                        self.game_state.set_snake_dir(Direction::Left)
                    }
                    Event::KeyDown { keycode: Some(Keycode::Right), .. } => {
                        self.game_state.set_snake_dir(Direction::Right)
                    }
                    _ => (),
                }
            }
            if framecounter % 10 == 0 {
                self.game_state.update();
            }
            self.render()?;
            framecounter += 1;
        }
    }

    fn render(&mut self) -> Result<(), String> {
        self.renderer.set_draw_color(Color::RGB(0, 0, 0));
        self.renderer.clear();
        let scale: u32 = 8;
        for ((y, x), &tile) in self.game_state.tiles().indexed_iter() {
            let color = match tile {
                game::Tile::Floor => Color::RGB(0, 0, 255),
                game::Tile::Wall => Color::RGB(255, 0, 0),
                game::Tile::Food => Color::RGB(255, 255, 0),
                game::Tile::Snake(_) => Color::RGB(0, 255, 0),
            };
            self.renderer.set_draw_color(color);
            self.renderer
                .fill_rect(sdl2::rect::Rect::new(x as i32 * scale as i32,
                                                 y as i32 * scale as i32,
                                                 scale,
                                                 scale))?;
        }
        self.renderer.present();

        Ok(())
    }
}

pub fn init() -> Result<Engine, String> {
    let sdl = sdl2::init()?;
    let video = sdl.video()?;
    let event_pump = sdl.event_pump()?;
    let window = video.window("Snake", 640, 480)
        .build()
        .or_else(|e| Err(format!("{}", e)))?;
    let renderer = window.renderer()
        .present_vsync()
        .build()
        .or_else(|e| Err(format!("{}", e)))?;
    let game_state = game::GameState::new();

    Ok(Engine {
           event_pump: event_pump,
           renderer: renderer,
           game_state: game_state,
       })
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate extra;

use std::env;
use std::fs::File;
use std::io::{self, stdout, stderr, Read, Write, Stderr};
use std::iter;
use std::ops::{Add, AddAssign};
use std::process::exit;
use extra::option::OptionalExt;
use extra::io::WriteExt;

static MAN_PAGE: &'static str = /* @MANSTART{wc} */ r#"
NAME
    wc - count words, bytes and lines of a file or byte stream.

SYNOPSIS
    wc [-h | --help] [-c | --bytes] [-w | --words] [-l | --lines] [FILE 1] [FILE 2]...

DESCRIPTION
    This utility will dump word count, line count, and byte count of a file or byte stream. If
    multiple files are given, it will print a total count. If no file name is given, 'wc' reads
    from stdin until EOF.

    Flags can be arbitrarily combined into a single flag, for example, '-c -w' (count bytes and
    count words) can be reduced to '-cw'.

    If no flags are given, 'wc' defaults to '-cwl'.

OPTIONS
    -h
    --help
        Print this manual page.

    -c
    --bytes
        Count bytes.

    -w
    --words
        Count words (i.e. contiguous strings seperated by whitespaces).

    -l
    --lines
        Count lines (seperated by NL).

AUTHOR
    This program was written mainly by Alice Maz.
"#; /* @MANEND */

#[derive(Copy, Clone, Default)]
struct Counts {
    lines: u64,
    words: u64,
    bytes: u64,
}

impl Counts {
    #[inline]
    fn new<T: Read>(input: T) -> Self {
        let mut line_count = 0;
        let mut word_count = 0;
        let mut byte_count = 0;
        let mut got_space = true;
        let mut input_bytes = input.bytes();

        while let Some(Ok(byte)) = input_bytes.next() {
            if byte == b'\n' {
                line_count += 1;
            }

            if byte.is_whitespace() {
                got_space = true;
            } else if got_space {
                got_space = false;
                word_count += 1;
            }

            byte_count += 1;
        }

        Counts { lines: line_count, words: word_count, bytes: byte_count }
    }
}

impl Add for Counts {
    type Output = Counts;

    fn add(self, other: Self) -> Self {
        Counts {
            lines: self.lines + other.lines,
            words: self.words + other.words,
            bytes: self.bytes + other.bytes
        }
    }
}

impl AddAssign for Counts {
    fn add_assign(&mut self, _rhs: Self) {
        self.lines += _rhs.lines;
        self.words += _rhs.words;
        self.bytes += _rhs.bytes;
    }
}

#[derive(Copy, Clone, Default)]
struct Flags {
    count_lines: bool,
    count_words: bool,
    count_bytes: bool,
}

fn u64_num_digits(val: u64) -> usize {
    if val < 10 {
        1
    } else {
        1 + u64_num_digits(val / 10)
    }
}

impl Flags {
    fn print_counts<W: Write>(self, mut counts: Vec<(Counts, String)>, stdout: &mut W, stderr: &mut Stderr) {
        use std::cmp::max;

        let mut max_lines_digits = 0;
        let mut max_words_digits = 0;
        let mut max_bytes_digits = 0;

        for &mut (count, _) in &mut counts {
            if self.count_lines {
                max_lines_digits = max(max_lines_digits, u64_num_digits(count.lines));
            }
            if self.count_words {
                max_words_digits = max(max_words_digits, u64_num_digits(count.words));
            }
            if self.count_bytes {
                max_bytes_digits = max(max_bytes_digits, u64_num_digits(count.bytes));
            }
        }

        for &mut (count, ref mut path) in &mut counts {
            self.print_count(count, path,
                max_lines_digits - u64_num_digits(count.lines) + 1,
                max_words_digits - u64_num_digits(count.words) + 1,
                max_bytes_digits - u64_num_digits(count.bytes) + 1,
                stdout, stderr)
        }
    }

    fn print_count<'a, W: Write>(self, count: Counts, path: &'a str, lines_padding: usize, words_padding: usize, bytes_padding: usize, stdout: &mut W, stderr: &mut Stderr) {
        stdout.write(b"    ").try(stderr);

        if self.count_lines {
            stdout.write(count.lines.to_string().as_bytes()).try(stderr);
            for _ in 0..lines_padding {
                stdout.write(b" ").try(stderr);
            }
        }
        if self.count_words {
            stdout.write(count.words.to_string().as_bytes()).try(stderr);
            for _ in 0..words_padding {
                stdout.write(b" ").try(stderr);
            }
        }
        if self.count_bytes {
            stdout.write(count.bytes.to_string().as_bytes()).try(stderr);
            for _ in 0..bytes_padding {
                stdout.write(b" ").try(stderr);
            }
        }

        stdout.writeln(path.as_bytes()).try(&mut *stderr);
    }

    fn default_to(&mut self) {
        // Defaults to behavior of -lwc
        if !(self.count_lines || self.count_words || self.count_bytes) {
            self.count_lines = true;
            self.count_words = true;
            self.count_bytes = true;
        }
    }
}

fn main() {
    let mut opts = Flags::default();
    let mut first_file = String::new();
    let mut args = env::args().skip(1);
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();

    while let Some(arg) = args.next() {
        // TODO add -m, maybe add -L
        if arg.starts_with("-") {
            match arg.as_str() {
                "--lines" | "-l" => opts.count_lines = true,
                "--words" | "-w" => opts.count_words = true,
                "--bytes" | "-c" => opts.count_bytes = true,
                "--help"  | "-h" => {
                    stdout.writeln(MAN_PAGE.as_bytes()).try(&mut stderr);
                    return;
                },
                _ => {
                    stderr.write(b"error: unknown flag, ").try(&mut stderr);
                    stderr.write(arg.as_bytes()).try(&mut stderr);
                    stderr.flush().try(&mut stderr);
                    exit(1);
                },
            }
        } else { // This is a file name
            first_file = arg;
            break;
        }
    }

    opts.default_to();

    if first_file.is_empty() {
        let stdin = io::stdin();
        let stdin = stdin.lock();

        opts.print_count(Counts::new(stdin), "stdin", 1, 1, 1, &mut stdout, &mut stderr);
    } else {
        let mut files = Vec::new();
        let mut total_count = Counts::default();
        let more_than_one: bool = args.len() > 0;

        for path in iter::once(first_file).chain(args) {
            //TODO would be easy to use stdin for - but
            //that is probably something the shell should handle?
            //unix it's all just fds so it's whatever dunno here tho
            //(also - is specific to sh/bash fwiw).

            let file = File::open(&path).try(&mut stderr);
            let file_count = Counts::new(file);
            total_count += file_count;

            files.push((file_count, path.to_owned()));
        }

        if more_than_one {
            files.push((total_count, "total".to_owned()));
        }

        opts.print_counts(files, &mut stdout, &mut stderr);
    }
}

pub trait AsciiWhitespace { fn is_whitespace(self) -> bool; }

impl AsciiWhitespace for u8 {
    fn is_whitespace(self) -> bool {
        //FIXME this works like iswspace w/ default C locale
        //but not good enough for en_US.UTF8 among others

        self == b'\n' // newline
        || self == b'\t' // tab
        || self == b'\r' // cr
        || self == 0xc // formfeed
        || self == 0xb // vtab
        || self == b' ' // space
    }
}
<commit_msg>Rename `Counts` to `Counter`<commit_after>#![deny(warnings)]

extern crate extra;

use std::env;
use std::fs::File;
use std::io::{self, stdout, stderr, Read, Write, Stderr};
use std::iter;
use std::ops::{Add, AddAssign};
use std::process::exit;
use extra::option::OptionalExt;
use extra::io::WriteExt;

static MAN_PAGE: &'static str = /* @MANSTART{wc} */ r#"
NAME
    wc - count words, bytes and lines of a file or byte stream.

SYNOPSIS
    wc [-h | --help] [-c | --bytes] [-w | --words] [-l | --lines] [FILE 1] [FILE 2]...

DESCRIPTION
    This utility will dump word count, line count, and byte count of a file or byte stream. If
    multiple files are given, it will print a total count. If no file name is given, 'wc' reads
    from stdin until EOF.

    Flags can be arbitrarily combined into a single flag, for example, '-c -w' (count bytes and
    count words) can be reduced to '-cw'.

    If no flags are given, 'wc' defaults to '-cwl'.

OPTIONS
    -h
    --help
        Print this manual page.

    -c
    --bytes
        Count bytes.

    -w
    --words
        Count words (i.e. contiguous strings seperated by whitespaces).

    -l
    --lines
        Count lines (seperated by NL).

AUTHOR
    This program was written mainly by Alice Maz.
"#; /* @MANEND */

#[derive(Copy, Clone, Debug, Default)]
struct Counter {
    lines: u64,
    words: u64,
    bytes: u64,
}

impl Counter {
    #[inline]
    fn new<T: Read>(input: T) -> Self {
        let mut line_count = 0;
        let mut word_count = 0;
        let mut byte_count = 0;
        let mut got_space = true;
        let mut input_bytes = input.bytes();

        while let Some(Ok(byte)) = input_bytes.next() {
            if byte == b'\n' {
                line_count += 1;
            }

            if byte.is_whitespace() {
                got_space = true;
            } else if got_space {
                got_space = false;
                word_count += 1;
            }

            byte_count += 1;
        }

        Counter { lines: line_count, words: word_count, bytes: byte_count }
    }
}

impl Add for Counter {
    type Output = Counter;

    fn add(self, other: Self) -> Self {
        Counter {
            lines: self.lines + other.lines,
            words: self.words + other.words,
            bytes: self.bytes + other.bytes
        }
    }
}

impl AddAssign for Counter {
    fn add_assign(&mut self, _rhs: Self) {
        self.lines += _rhs.lines;
        self.words += _rhs.words;
        self.bytes += _rhs.bytes;
    }
}

#[derive(Copy, Clone, Default)]
struct Flags {
    count_lines: bool,
    count_words: bool,
    count_bytes: bool,
}

fn u64_num_digits(val: u64) -> usize {
    if val < 10 {
        1
    } else {
        1 + u64_num_digits(val / 10)
    }
}

impl Flags {
    fn print_counts<W: Write>(self, mut counts: Vec<(Counter, String)>, stdout: &mut W, stderr: &mut Stderr) {
        use std::cmp::max;

        let mut max_lines_digits = 0;
        let mut max_words_digits = 0;
        let mut max_bytes_digits = 0;

        for &mut (count, _) in &mut counts {
            if self.count_lines {
                max_lines_digits = max(max_lines_digits, u64_num_digits(count.lines));
            }
            if self.count_words {
                max_words_digits = max(max_words_digits, u64_num_digits(count.words));
            }
            if self.count_bytes {
                max_bytes_digits = max(max_bytes_digits, u64_num_digits(count.bytes));
            }
        }

        for &mut (count, ref mut path) in &mut counts {
            self.print_count(count, path,
                max_lines_digits - u64_num_digits(count.lines) + 1,
                max_words_digits - u64_num_digits(count.words) + 1,
                max_bytes_digits - u64_num_digits(count.bytes) + 1,
                stdout, stderr)
        }
    }

    fn print_count<'a, W: Write>(self, count: Counter, path: &'a str, lines_padding: usize, words_padding: usize, bytes_padding: usize, stdout: &mut W, stderr: &mut Stderr) {
        stdout.write(b"    ").try(stderr);

        if self.count_lines {
            stdout.write(count.lines.to_string().as_bytes()).try(stderr);
            for _ in 0..lines_padding {
                stdout.write(b" ").try(stderr);
            }
        }
        if self.count_words {
            stdout.write(count.words.to_string().as_bytes()).try(stderr);
            for _ in 0..words_padding {
                stdout.write(b" ").try(stderr);
            }
        }
        if self.count_bytes {
            stdout.write(count.bytes.to_string().as_bytes()).try(stderr);
            for _ in 0..bytes_padding {
                stdout.write(b" ").try(stderr);
            }
        }

        stdout.writeln(path.as_bytes()).try(&mut *stderr);
    }

    fn default_to(&mut self) {
        // Defaults to behavior of -lwc
        if !(self.count_lines || self.count_words || self.count_bytes) {
            self.count_lines = true;
            self.count_words = true;
            self.count_bytes = true;
        }
    }
}

fn main() {
    let mut opts = Flags::default();
    let mut first_file = String::new();
    let mut args = env::args().skip(1);
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();

    while let Some(arg) = args.next() {
        // TODO add -m, maybe add -L
        if arg.starts_with("-") {
            match arg.as_str() {
                "--lines" | "-l" => opts.count_lines = true,
                "--words" | "-w" => opts.count_words = true,
                "--bytes" | "-c" => opts.count_bytes = true,
                "--help"  | "-h" => {
                    stdout.writeln(MAN_PAGE.as_bytes()).try(&mut stderr);
                    return;
                },
                _ => {
                    stderr.write(b"error: unknown flag, ").try(&mut stderr);
                    stderr.write(arg.as_bytes()).try(&mut stderr);
                    stderr.flush().try(&mut stderr);
                    exit(1);
                },
            }
        } else { // This is a file name
            first_file = arg;
            break;
        }
    }

    opts.default_to();

    if first_file.is_empty() {
        let stdin = io::stdin();
        let stdin = stdin.lock();

        opts.print_count(Counter::new(stdin), "stdin", 1, 1, 1, &mut stdout, &mut stderr);
    } else {
        let mut files = Vec::new();
        let mut total_count = Counter::default();
        let more_than_one: bool = args.len() > 0;

        for path in iter::once(first_file).chain(args) {
            //TODO would be easy to use stdin for - but
            //that is probably something the shell should handle?
            //unix it's all just fds so it's whatever dunno here tho
            //(also - is specific to sh/bash fwiw).

            let file = File::open(&path).try(&mut stderr);
            let file_count = Counter::new(file);
            total_count += file_count;

            files.push((file_count, path.to_owned()));
        }

        if more_than_one {
            files.push((total_count, "total".to_owned()));
        }

        opts.print_counts(files, &mut stdout, &mut stderr);
    }
}

pub trait AsciiWhitespace { fn is_whitespace(self) -> bool; }

impl AsciiWhitespace for u8 {
    fn is_whitespace(self) -> bool {
        //FIXME this works like iswspace w/ default C locale
        //but not good enough for en_US.UTF8 among others

        self == b'\n' // newline
        || self == b'\t' // tab
        || self == b'\r' // cr
        || self == 0xc // formfeed
        || self == 0xb // vtab
        || self == b' ' // space
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::str;

use encoding::label::encoding_from_whatwg_label;
use encoding::all::UTF_8;
use encoding::{EncodingObj, DecodeReplace, decode};

use tokenizer::{tokenize, Tokenizer};
use parser::{parse_stylesheet_rules, StylesheetParser};

/// Determine the character encoding of a CSS stylesheet and decode it.
///
/// This is based on the presence of a :abbr:`BOM (Byte Order Mark)`,
/// an `@charset` rule,
/// and encoding meta-information.
///
/// :param css_bytes: A byte string.
/// :param protocol_encoding:
///     The encoding label, if any, defined by HTTP or equivalent protocol.
///     (e.g. via the `charset` parameter of the `Content-Type` header.)
/// :param environment_encoding:
///     An optional `Encoding` object
///     for the `environment encoding
///     <http://www.w3.org/TR/css-syntax/#environment-encoding>`_,
///     if any.
/// :returns:
///     A 2-tuple of a decoded Unicode string
///     and the `Encoding` object that was used.
pub fn decode_stylesheet_bytes(css: &[u8], protocol_encoding_label: Option<&str>,
                               environment_encoding: Option<EncodingObj>)
                            -> (~str, EncodingObj) {
    // http://dev.w3.org/csswg/css-syntax/#the-input-byte-stream
    match protocol_encoding_label {
        None => (),
        Some(label) => match encoding_from_whatwg_label(label) {
            None => (),
            Some(fallback) => return decode_replace(css, fallback)
        }
    }
    if css.starts_with("@charset \"".as_bytes()) {
        // 10 is "@charset \"".len()
        // 100 is arbitrary so that no encoding label is more than 100-10 bytes.
        match css.slice(10, css.len().min(&100)).position_elem(&('"' as u8)) {
            None => (),
            Some(label_length)
            => if css.slice_from(10 + label_length).starts_with("\";".as_bytes()) {
                let label = css.slice(10, 10 + label_length);
                let label = str::from_chars(label.iter().map(|&b| b as char).to_owned_vec());
                match encoding_from_whatwg_label(label) {
                    None => (),
                    Some(fallback) => match fallback.name() {
                        "utf-16be" | "utf-16le"
                        => return decode_replace(css, UTF_8 as EncodingObj),
                        _ => return decode_replace(css, fallback),
                    }
                }
            }
        }
    }
    match environment_encoding {
        None => (),
        Some(fallback) => return decode_replace(css, fallback)
    }
    return decode_replace(css, UTF_8 as EncodingObj)
}

#[inline]
fn decode_replace(input: &[u8], fallback_encoding: EncodingObj)-> (~str, EncodingObj) {
    let (result, used_encoding) = decode(input, DecodeReplace, fallback_encoding);
    (result.unwrap(), used_encoding)
}

/// Parse stylesheet from bytes.
///
/// :param css_bytes: A byte string.
/// :param protocol_encoding:
///     The encoding label, if any, defined by HTTP or equivalent protocol.
///     (e.g. via the `charset` parameter of the `Content-Type` header.)
/// :param environment_encoding:
///     An optional `Encoding` object
///     for the `environment encoding
///     <http://www.w3.org/TR/css-syntax/#environment-encoding>`_,
///     if any.
/// :returns:
///     A 2-tuple of a Iterator<Result<Rule, SyntaxError>>
///     and the `Encoding` object that was used.
pub fn parse_stylesheet_rules_from_bytes(
        css_bytes: &[u8], protocol_encoding_label: Option<&str>,
        environment_encoding: Option<EncodingObj>)
     -> (StylesheetParser<Tokenizer>, EncodingObj) {
    let (css_unicode, encoding) = decode_stylesheet_bytes(
        css_bytes, protocol_encoding_label, environment_encoding);
    (parse_stylesheet_rules(tokenize(css_unicode)), encoding)
}
<commit_msg>Update to upstream rust-encoding, that renamed EncodingObj to EncodingRef<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::str;

use encoding::label::encoding_from_whatwg_label;
use encoding::all::UTF_8;
use encoding::{EncodingRef, DecodeReplace, decode};

use tokenizer::{tokenize, Tokenizer};
use parser::{parse_stylesheet_rules, StylesheetParser};

/// Determine the character encoding of a CSS stylesheet and decode it.
///
/// This is based on the presence of a :abbr:`BOM (Byte Order Mark)`,
/// an `@charset` rule,
/// and encoding meta-information.
///
/// :param css_bytes: A byte string.
/// :param protocol_encoding:
///     The encoding label, if any, defined by HTTP or equivalent protocol.
///     (e.g. via the `charset` parameter of the `Content-Type` header.)
/// :param environment_encoding:
///     An optional `Encoding` object
///     for the `environment encoding
///     <http://www.w3.org/TR/css-syntax/#environment-encoding>`_,
///     if any.
/// :returns:
///     A 2-tuple of a decoded Unicode string
///     and the `Encoding` object that was used.
pub fn decode_stylesheet_bytes(css: &[u8], protocol_encoding_label: Option<&str>,
                               environment_encoding: Option<EncodingRef>)
                            -> (~str, EncodingRef) {
    // http://dev.w3.org/csswg/css-syntax/#the-input-byte-stream
    match protocol_encoding_label {
        None => (),
        Some(label) => match encoding_from_whatwg_label(label) {
            None => (),
            Some(fallback) => return decode_replace(css, fallback)
        }
    }
    if css.starts_with("@charset \"".as_bytes()) {
        // 10 is "@charset \"".len()
        // 100 is arbitrary so that no encoding label is more than 100-10 bytes.
        match css.slice(10, css.len().min(&100)).position_elem(&('"' as u8)) {
            None => (),
            Some(label_length)
            => if css.slice_from(10 + label_length).starts_with("\";".as_bytes()) {
                let label = css.slice(10, 10 + label_length);
                let label = str::from_chars(label.iter().map(|&b| b as char).to_owned_vec());
                match encoding_from_whatwg_label(label) {
                    None => (),
                    Some(fallback) => match fallback.name() {
                        "utf-16be" | "utf-16le"
                        => return decode_replace(css, UTF_8 as EncodingRef),
                        _ => return decode_replace(css, fallback),
                    }
                }
            }
        }
    }
    match environment_encoding {
        None => (),
        Some(fallback) => return decode_replace(css, fallback)
    }
    return decode_replace(css, UTF_8 as EncodingRef)
}

#[inline]
fn decode_replace(input: &[u8], fallback_encoding: EncodingRef)-> (~str, EncodingRef) {
    let (result, used_encoding) = decode(input, DecodeReplace, fallback_encoding);
    (result.unwrap(), used_encoding)
}

/// Parse stylesheet from bytes.
///
/// :param css_bytes: A byte string.
/// :param protocol_encoding:
///     The encoding label, if any, defined by HTTP or equivalent protocol.
///     (e.g. via the `charset` parameter of the `Content-Type` header.)
/// :param environment_encoding:
///     An optional `Encoding` object
///     for the `environment encoding
///     <http://www.w3.org/TR/css-syntax/#environment-encoding>`_,
///     if any.
/// :returns:
///     A 2-tuple of a Iterator<Result<Rule, SyntaxError>>
///     and the `Encoding` object that was used.
pub fn parse_stylesheet_rules_from_bytes(
        css_bytes: &[u8], protocol_encoding_label: Option<&str>,
        environment_encoding: Option<EncodingRef>)
     -> (StylesheetParser<Tokenizer>, EncodingRef) {
    let (css_unicode, encoding) = decode_stylesheet_bytes(
        css_bytes, protocol_encoding_label, environment_encoding);
    (parse_stylesheet_rules(tokenize(css_unicode)), encoding)
}
<|endoftext|>


<commit_before>use std::result;

use futures::sync::oneshot;

use request::ParsedRequest;
use serde::de::{self, Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};

use super::{DeviceState, SyncRequest};
use net_util::MacAddr;

// used to serialize an Option<MacAddr>
fn mac_serialize_with<S>(what: &Option<MacAddr>, serializer: S) -> result::Result<S::Ok, S::Error>
where
    S: Serializer,
{
    if let Some(ref mac) = *what {
        mac.to_string().serialize(serializer)
    } else {
        "".serialize(serializer)
    }
}

// used to deserialize an Option<MacAddr>
fn mac_deserialize_with<'de, D>(deserializer: D) -> result::Result<Option<MacAddr>, D::Error>
where
    D: Deserializer<'de>,
{
    // TODO: is there a more efficient way around this? (i.e. deserialize to a slice
    // instead of a String?!)
    if let Some(ref s) = Option::<String>::deserialize(deserializer)? {
        MacAddr::parse_str(s)
            .map(|mac_addr| Some(mac_addr))
            .map_err(|_| de::Error::custom("invalid MAC address."))
    } else {
        Ok(None)
    }
}

// This struct represents the strongly typed equivalent of the json body from net iface
// related requests.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct NetworkInterfaceBody {
    pub iface_id: String,
    pub state: DeviceState,
    pub host_dev_name: String,
    #[serde(serialize_with = "self::mac_serialize_with",
            deserialize_with = "self::mac_deserialize_with")]
    pub guest_mac: Option<MacAddr>,
}

impl NetworkInterfaceBody {
    pub fn into_parsed_request(self, id_from_path: &str) -> result::Result<ParsedRequest, String> {
        if id_from_path != self.iface_id {
            return Err(String::from(
                "The id from the path does not match the id from the body!",
            ));
        }

        let (sender, receiver) = oneshot::channel();
        Ok(ParsedRequest::Sync(
            SyncRequest::PutNetworkInterface(self, sender),
            receiver,
        ))
    }
}

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

    #[test]
    fn test_netif_into_parsed_request() {
        let netif = NetworkInterfaceBody {
            iface_id: String::from("foo"),
            state: DeviceState::Attached,
            host_dev_name: String::from("bar"),
            guest_mac: Some(MacAddr::parse_str("12:34:56:78:9A:BC").unwrap()),
        };

        assert!(netif.clone().into_parsed_request("bar").is_err());
        let (sender, receiver) = oneshot::channel();
        assert!(
            netif
                .clone()
                .into_parsed_request("foo")
                .eq(&Ok(ParsedRequest::Sync(
                    SyncRequest::PutNetworkInterface(netif, sender),
                    receiver
                )))
        );
    }
}
<commit_msg>NetworkInterfaceBody: reworked de/serialization<commit_after>use std::result;

use futures::sync::oneshot;

use super::{DeviceState, SyncRequest};
use net_util::MacAddr;
use request::ParsedRequest;

// This struct represents the strongly typed equivalent of the json body from net iface
// related requests.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct NetworkInterfaceBody {
    pub iface_id: String,
    pub state: DeviceState,
    pub host_dev_name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub guest_mac: Option<MacAddr>,
}

impl NetworkInterfaceBody {
    pub fn into_parsed_request(self, id_from_path: &str) -> result::Result<ParsedRequest, String> {
        if id_from_path != self.iface_id {
            return Err(String::from(
                "The id from the path does not match the id from the body!",
            ));
        }

        let (sender, receiver) = oneshot::channel();
        Ok(ParsedRequest::Sync(
            SyncRequest::PutNetworkInterface(self, sender),
            receiver,
        ))
    }
}

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

    #[test]
    fn test_netif_into_parsed_request() {
        let netif = NetworkInterfaceBody {
            iface_id: String::from("foo"),
            state: DeviceState::Attached,
            host_dev_name: String::from("bar"),
            guest_mac: Some(MacAddr::parse_str("12:34:56:78:9A:BC").unwrap()),
        };

        assert!(netif.clone().into_parsed_request("bar").is_err());
        let (sender, receiver) = oneshot::channel();
        assert!(
            netif
                .clone()
                .into_parsed_request("foo")
                .eq(&Ok(ParsedRequest::Sync(
                    SyncRequest::PutNetworkInterface(netif, sender),
                    receiver
                )))
        );
    }

    #[test]
    fn test_network_interface_body_serialization_and_deserialization() {
        let netif = NetworkInterfaceBody {
            iface_id: String::from("foo"),
            state: DeviceState::Attached,
            host_dev_name: String::from("bar"),
            guest_mac: Some(MacAddr::parse_str("12:34:56:78:9A:BC").unwrap()),
        };

        // This is the json encoding of the netif variable.
        let jstr = r#"{
            "iface_id": "foo",
            "host_dev_name": "bar",
            "state": "Attached",
            "guest_mac": "12:34:56:78:9A:bc"
        }"#;

        let x = serde_json::from_str(jstr).expect("deserialization failed.");
        assert_eq!(netif, x);

        let y = serde_json::to_string(&netif).expect("serialization failed.");
        let z = serde_json::from_str(y.as_ref()).expect("deserialization (2) failed.");
        assert_eq!(x, z);

        // Check that guest_mac is truly optional.
        let jstr_no_mac = r#"{
            "iface_id": "foo",
            "host_dev_name": "bar",
            "state": "Attached"
        }"#;

        assert!(serde_json::from_str::<NetworkInterfaceBody>(jstr_no_mac).is_ok())
    }
}
<|endoftext|>


<commit_before>// This file is released under the same terms as Rust itself.

use db::{Db, PendingEntry, QueueEntry, RunningEntry};
use hyper::Url;
use postgres::{Connection, IntoConnectParams, SslMode};
use std::error::Error;
use std::marker::PhantomData;
use std::str::FromStr;
use ui::Pr;
use pipeline::PipelineId;

pub struct PostgresDb

    where P: Pr + Into<String> + FromStr
{
    _pr: PhantomData
,
    conn: Connection,
}

impl
 PostgresDb

    where P: Pr + Into<String> + FromStr
{
    pub fn open<Q: IntoConnectParams>(
        params: Q
    ) -> Result<Self, Box<Error + Send + Sync>> {
        let conn = try!(Connection::connect(params, SslMode::None));
        try!(conn.batch_execute(r###"
            CREATE TABLE IF NOT EXISTS queue (
                id SERIAL PRIMARY KEY,
                pipeline_id INTEGER,
                pr TEXT,
                message TEXT,
                pull_commit TEXT
            );
            CREATE TABLE IF NOT EXISTS running (
                pipeline_id INTEGER PRIMARY KEY,
                pr TEXT,
                message TEXT,
                pull_commit TEXT,
                merge_commit TEXT,
                canceled BOOLEAN,
                built BOOLEAN
            );
            CREATE TABLE IF NOT EXISTS pending (
                id SERIAL PRIMARY KEY,
                pipeline_id INTEGER,
                pr TEXT,
                pull_commit TEXT,
                title TEXT,
                url TEXT
            );
        "###));
        Ok(PostgresDb{
            conn: conn,
            _pr: PhantomData,
        })
    }
}

impl
 Db
 for PostgresDb

    where P: Pr + Into<String> + FromStr,

::Err: ::std::error::Error,

::Err: ::std::error::Error,
{
    fn push_queue(
        &mut self,
        pipeline_id: PipelineId,
        QueueEntry{pr, commit, message}: QueueEntry

    ) {
        let sql = r###"
            INSERT INTO queue (pr, pipeline_id, pull_commit, message)
            VALUES ($1, $2, $3, $4)
        "###;
        self.conn.execute(sql, &[
            &pr.into(),
            &pipeline_id.0,
            &commit.into(),
            &message,
        ]).expect("Push-to-queue");
    }
    fn pop_queue(
        &mut self,
        pipeline_id: PipelineId,
    ) -> Option<QueueEntry
> {
        let trans = self.conn
            .transaction()
            .expect("Start pop-from-queue transaction");
        let sql = r###"
            SELECT id, pr, pull_commit, message
            FROM queue
            WHERE pipeline_id = $1
            ORDER BY id ASC LIMIT 1
        "###;
        let item = {
            let stmt = trans.prepare(sql).expect("Pop from queue");
            let rows = stmt.query(&[&pipeline_id.0]).expect("pop from queue");
            let rows = rows.iter();
            let mut rows = rows.map(|row| (
                row.get::<_, i32>(0),
                QueueEntry {
                    pr: P::from_str(&row.get::<_, String>(1)).unwrap(),
                    commit: P::C::from_str(&row.get::<_, String>(2)).unwrap(),
                    message: row.get::<_, String>(3),
                },
            ));
            rows.next()
        };
        if let Some((id, _)) = item {
            let sql = r###"
                DELETE FROM queue WHERE id = $1
            "###;
            trans.execute(sql, &[&id]).expect("Delete pop-from-queue row");
        }
        trans.commit().expect("Commit pop-from-queue transaction");
        item.map(|item| item.1)
    }
    fn list_queue(
        &mut self,
        pipeline_id: PipelineId,
    ) -> Vec<QueueEntry
> {
        let sql = r###"
            SELECT pr, pull_commit, message
            FROM queue
            WHERE pipeline_id = $1
            ORDER BY id ASC
        "###;
        let stmt = self.conn.prepare(&sql)
            .expect("Prepare list-queue query");
        let rows = stmt.query(&[&pipeline_id.0])
            .expect("Get queue entry");
        let rows = rows.iter();
        let rows = rows.map(|row| QueueEntry {
            pr: P::from_str(&row.get::<_, String>(0)).unwrap(),
            commit: P::C::from_str(&row.get::<_, String>(1)).unwrap(),
            message: row.get::<_, String>(2),
        });
        let rows: Vec<QueueEntry
> = rows.collect();
        rows
    }
    fn put_running(
        &mut self,
        pipeline_id: PipelineId,
        RunningEntry{
            pr,
            pull_commit,
            merge_commit,
            message,
            canceled,
            built,
        }: RunningEntry

    ) {
        let sql = r###"
            INSERT INTO running
                (
                    pipeline_id,
                    pr,
                    pull_commit,
                    merge_commit,
                    message,
                    canceled,
                    built
                )
            VALUES
                ($1, $2, $3, $4, $5, $6, $7)
            ON CONFLICT (pipeline_id) DO UPDATE SET
                pr = $2,
                pull_commit = $3,
                merge_commit = $4,
                message = $5,
                canceled = $6,
                built = $7
        "###;
        self.conn.execute(sql, &[
            &pipeline_id.0,
            &<P as Into<String>>::into(pr),
            &<P::C as Into<String>>::into(pull_commit),
            &merge_commit.map(|m| <P::C as Into<String>>::into(m)),
            &message,
            &canceled,
            &built,
        ]).expect("Put running");
    }
    fn take_running(
        &mut self,
        pipeline_id: PipelineId,
    ) -> Option<RunningEntry
> {
        let trans = self.conn.transaction()
            .expect("Start take-running transaction");
        let sql = r###"
            SELECT pr, pull_commit, merge_commit, message, canceled, built
            FROM running
            WHERE pipeline_id = $1
        "###;
        let entry = {
            let stmt = trans.prepare(&sql)
                .expect("Prepare take-running query");
            let rows = stmt.query(&[&pipeline_id.0])
                .expect("To take running");
            let rows = rows.iter();
            let mut rows = rows.map(|row| RunningEntry {
                pr: P::from_str(&row.get::<_, String>(0)[..]).unwrap(),
                pull_commit: P::C::from_str(&row.get::<_, String>(1)[..])
                    .unwrap(),
                merge_commit: row.get::<_, Option<String>>(2).map(
                    |v| P::C::from_str(&v).unwrap()
                ),
                message: row.get(3),
                canceled: row.get(4),
                built: row.get(5),
            });
            rows.next()
        };
        let sql = r###"
            DELETE FROM running WHERE pipeline_id = $1
        "###;
        trans.execute(sql, &[&pipeline_id.0]).expect("Remove running entry");
        trans.commit().expect("Commit take-running transaction");
        entry
    }
    fn peek_running(
        &mut self,
        pipeline_id: PipelineId,
    ) -> Option<RunningEntry
> {
        let sql = r###"
            SELECT pr, pull_commit, merge_commit, message, canceled, built
            FROM running
            WHERE pipeline_id = $1
        "###;
        let stmt = self.conn.prepare(&sql)
            .expect("Prepare peek-running query");
        let rows = stmt.query(&[&pipeline_id.0]);
        let rows = rows.expect("Get running query");
        let rows = rows.iter();
        let mut rows = rows.map(|row| RunningEntry {
            pr: P::from_str(&row.get::<_, String>(0)[..]).unwrap(),
            pull_commit: P::C::from_str(&row.get::<_, String>(1)[..])
                .unwrap(),
            merge_commit: row.get::<_, Option<String>>(2).map(
                |v| P::C::from_str(&v).unwrap()
            ),
            message: row.get(3),
            canceled: row.get(4),
            built: row.get(5),
        });
        rows.next()
    }
    fn add_pending(
        &mut self,
        pipeline_id: PipelineId,
        entry: PendingEntry
,
    ) {
        let trans = self.conn.transaction()
            .expect("Start add-pending transaction");
        let sql = r###"
            DELETE FROM pending WHERE pipeline_id = $1 AND pr = $2
        "###;
        trans.execute(sql, &[
            &pipeline_id.0,
            &<P as Into<String>>::into(entry.pr.clone()),
        ]).expect("Remove pending entry");
        let sql = r###"
            INSERT INTO pending (pipeline_id, pr, pull_commit, title, url)
            VALUES ($1, $2, $3, $4, $5)
        "###;
        trans.execute(sql, &[
            &pipeline_id.0,
            &<P as Into<String>>::into(entry.pr.clone()),
            &<P::C as Into<String>>::into(entry.commit.clone()),
            &entry.title,
            &entry.url.as_str(),
        ]).expect("Add pending entry");
        trans.commit().expect("Commit add-pending transaction");
    }
    fn take_pending_by_pr(
        &mut self,
        pipeline_id: PipelineId,
        pr: &P,
    ) -> Option<PendingEntry
> {
        let trans = self.conn.transaction()
            .expect("Start take-pending transaction");
        let sql = r###"
            SELECT id, pr, pull_commit, title, url
            FROM pending
            WHERE pipeline_id = $1 AND pr = $2
        "###;
        let entry = {
            let stmt = trans.prepare(&sql)
                .expect("Prepare take-pending query");
            let rows = stmt.query(&[
                &pipeline_id.0,
                &<P as Into<String>>::into(pr.clone()),
            ]);
            let rows = rows.expect("Get pending entry");
            let rows = rows.iter();
            let mut rows = rows.map(|row| (row.get::<_, i64>(0), PendingEntry {
                pr: P::from_str(&row.get::<_, String>(1)[..]).unwrap(),
                commit: P::C::from_str(&row.get::<_, String>(2)[..])
                    .unwrap(),
                title: row.get(3),
                url: Url::parse(&row.get::<_, String>(4)).unwrap(),
            }));
            rows.next()
        };
        if let Some(ref entry) = entry {
            let sql = r###"
                DELETE FROM pending WHERE id = $1
            "###;
            trans.execute(sql, &[&entry.0]).expect("Remove pending entry");
            trans.commit().expect("Commit take-pending transaction");
        }
        entry.map(|entry| entry.1)
    }
    fn peek_pending_by_pr(
        &mut self,
        pipeline_id: PipelineId,
        pr: &P,
    ) -> Option<PendingEntry
> {
        let sql = r###"
            SELECT pr, pull_commit, title, url
            FROM pending
            WHERE pipeline_id = $1 AND pr = $2
        "###;
        let stmt = self.conn.prepare(&sql)
            .expect("Prepare peek-pending query");
        let rows = stmt.query(&[
            &pipeline_id.0,
            &<P as Into<String>>::into(pr.clone()),
        ]);
        let rows = rows.expect("Get pending entry");
        let rows = rows.iter();
        let mut rows = rows.map(|row| PendingEntry {
            pr: P::from_str(&row.get::<_, String>(0)[..]).unwrap(),
            commit: P::C::from_str(&row.get::<_, String>(1)[..])
                .unwrap(),
            title: row.get(2),
            url: Url::parse(&row.get::<_, String>(3)).unwrap(),
        });
        rows.next()
    }
    fn list_pending(
        &mut self,
        pipeline_id: PipelineId,
    ) -> Vec<PendingEntry
> {
        let sql = r###"
            SELECT pr, pull_commit, title, url
            FROM pending
            WHERE pipeline_id = $1
        "###;
        let stmt = self.conn.prepare(&sql)
            .expect("Prepare peek-pending query");
        let rows = stmt.query(&[&pipeline_id.0]);
        let rows = rows.expect("Get pending entry");
        let rows = rows.iter();
        let rows = rows.map(|row| PendingEntry {
            pr: P::from_str(&row.get::<_, String>(0)[..]).unwrap(),
            commit: P::C::from_str(&row.get::<_, String>(1)[..])
                .unwrap(),
            title: row.get(2),
            url: Url::parse(&row.get::<_, String>(3)).unwrap(),
        });
        let rows: Vec<PendingEntry
> = rows.collect();
        rows
    }
    fn cancel_by_pr(&mut self, pipeline_id: PipelineId, pr: &P) {
        let sql = r###"
            UPDATE running
            SET canceled = TRUE
            WHERE pipeline_id = $1 AND pr = $2
        "###;
        self.conn.execute(sql, &[
            &pipeline_id.0,
            &<P as Into<String>>::into(pr.clone()),
        ]).expect("Cancel running PR");
        let sql = r###"
            DELETE FROM queue
            WHERE pipeline_id = $1 AND pr = $2
        "###;
        self.conn.execute(sql, &[
            &pipeline_id.0,
            &<P as Into<String>>::into(pr.clone()),
        ]).expect("Cancel queue entries");
    }
    fn cancel_by_pr_different_commit(
        &mut self,
        pipeline_id: PipelineId,
        pr: &P,
        commit: &P::C,
    ) -> bool {
        let sql = r###"
            UPDATE running
            SET canceled = TRUE
            WHERE pipeline_id = $1 AND pr = $2 AND pull_commit <> $3
        "###;
        let affected_rows_running = self.conn.execute(sql, &[
            &pipeline_id.0,
            &<P as Into<String>>::into(pr.clone()),
            &<P::C as Into<String>>::into(commit.clone()),
        ]).expect("Cancel running PR");
        let sql = r###"
            DELETE FROM queue
            WHERE pipeline_id = $1 AND pr = $2 AND pull_commit <> $3
        "###;
        let affected_rows_queue = self.conn.execute(sql, &[
            &pipeline_id.0,
            &<P as Into<String>>::into(pr.clone()),
            &<P::C as Into<String>>::into(commit.clone()),
        ]).expect("Cancel queue entries");
        affected_rows_queue != 0 || affected_rows_running != 0
    }
}<commit_msg>Fix a dumb postgres bug<commit_after>// This file is released under the same terms as Rust itself.

use db::{Db, PendingEntry, QueueEntry, RunningEntry};
use hyper::Url;
use postgres::{Connection, IntoConnectParams, SslMode};
use std::error::Error;
use std::marker::PhantomData;
use std::str::FromStr;
use ui::Pr;
use pipeline::PipelineId;

pub struct PostgresDb

    where P: Pr + Into<String> + FromStr
{
    _pr: PhantomData
,
    conn: Connection,
}

impl
 PostgresDb

    where P: Pr + Into<String> + FromStr
{
    pub fn open<Q: IntoConnectParams>(
        params: Q
    ) -> Result<Self, Box<Error + Send + Sync>> {
        let conn = try!(Connection::connect(params, SslMode::None));
        try!(conn.batch_execute(r###"
            CREATE TABLE IF NOT EXISTS queue (
                id SERIAL PRIMARY KEY,
                pipeline_id INTEGER,
                pr TEXT,
                message TEXT,
                pull_commit TEXT
            );
            CREATE TABLE IF NOT EXISTS running (
                pipeline_id INTEGER PRIMARY KEY,
                pr TEXT,
                message TEXT,
                pull_commit TEXT,
                merge_commit TEXT,
                canceled BOOLEAN,
                built BOOLEAN
            );
            CREATE TABLE IF NOT EXISTS pending (
                id SERIAL PRIMARY KEY,
                pipeline_id INTEGER,
                pr TEXT,
                pull_commit TEXT,
                title TEXT,
                url TEXT
            );
        "###));
        Ok(PostgresDb{
            conn: conn,
            _pr: PhantomData,
        })
    }
}

impl
 Db
 for PostgresDb

    where P: Pr + Into<String> + FromStr,

::Err: ::std::error::Error,

::Err: ::std::error::Error,
{
    fn push_queue(
        &mut self,
        pipeline_id: PipelineId,
        QueueEntry{pr, commit, message}: QueueEntry

    ) {
        let sql = r###"
            INSERT INTO queue (pr, pipeline_id, pull_commit, message)
            VALUES ($1, $2, $3, $4)
        "###;
        self.conn.execute(sql, &[
            &pr.into(),
            &pipeline_id.0,
            &commit.into(),
            &message,
        ]).expect("Push-to-queue");
    }
    fn pop_queue(
        &mut self,
        pipeline_id: PipelineId,
    ) -> Option<QueueEntry
> {
        let trans = self.conn
            .transaction()
            .expect("Start pop-from-queue transaction");
        let sql = r###"
            SELECT id, pr, pull_commit, message
            FROM queue
            WHERE pipeline_id = $1
            ORDER BY id ASC LIMIT 1
        "###;
        let item = {
            let stmt = trans.prepare(sql).expect("Pop from queue");
            let rows = stmt.query(&[&pipeline_id.0]).expect("pop from queue");
            let rows = rows.iter();
            let mut rows = rows.map(|row| (
                row.get::<_, i32>(0),
                QueueEntry {
                    pr: P::from_str(&row.get::<_, String>(1)).unwrap(),
                    commit: P::C::from_str(&row.get::<_, String>(2)).unwrap(),
                    message: row.get::<_, String>(3),
                },
            ));
            rows.next()
        };
        if let Some((id, _)) = item {
            let sql = r###"
                DELETE FROM queue WHERE id = $1
            "###;
            trans.execute(sql, &[&id]).expect("Delete pop-from-queue row");
        }
        trans.commit().expect("Commit pop-from-queue transaction");
        item.map(|item| item.1)
    }
    fn list_queue(
        &mut self,
        pipeline_id: PipelineId,
    ) -> Vec<QueueEntry
> {
        let sql = r###"
            SELECT pr, pull_commit, message
            FROM queue
            WHERE pipeline_id = $1
            ORDER BY id ASC
        "###;
        let stmt = self.conn.prepare(&sql)
            .expect("Prepare list-queue query");
        let rows = stmt.query(&[&pipeline_id.0])
            .expect("Get queue entry");
        let rows = rows.iter();
        let rows = rows.map(|row| QueueEntry {
            pr: P::from_str(&row.get::<_, String>(0)).unwrap(),
            commit: P::C::from_str(&row.get::<_, String>(1)).unwrap(),
            message: row.get::<_, String>(2),
        });
        let rows: Vec<QueueEntry
> = rows.collect();
        rows
    }
    fn put_running(
        &mut self,
        pipeline_id: PipelineId,
        RunningEntry{
            pr,
            pull_commit,
            merge_commit,
            message,
            canceled,
            built,
        }: RunningEntry

    ) {
        let sql = r###"
            INSERT INTO running
                (
                    pipeline_id,
                    pr,
                    pull_commit,
                    merge_commit,
                    message,
                    canceled,
                    built
                )
            VALUES
                ($1, $2, $3, $4, $5, $6, $7)
            ON CONFLICT (pipeline_id) DO UPDATE SET
                pr = $2,
                pull_commit = $3,
                merge_commit = $4,
                message = $5,
                canceled = $6,
                built = $7
        "###;
        self.conn.execute(sql, &[
            &pipeline_id.0,
            &<P as Into<String>>::into(pr),
            &<P::C as Into<String>>::into(pull_commit),
            &merge_commit.map(|m| <P::C as Into<String>>::into(m)),
            &message,
            &canceled,
            &built,
        ]).expect("Put running");
    }
    fn take_running(
        &mut self,
        pipeline_id: PipelineId,
    ) -> Option<RunningEntry
> {
        let trans = self.conn.transaction()
            .expect("Start take-running transaction");
        let sql = r###"
            SELECT pr, pull_commit, merge_commit, message, canceled, built
            FROM running
            WHERE pipeline_id = $1
        "###;
        let entry = {
            let stmt = trans.prepare(&sql)
                .expect("Prepare take-running query");
            let rows = stmt.query(&[&pipeline_id.0])
                .expect("To take running");
            let rows = rows.iter();
            let mut rows = rows.map(|row| RunningEntry {
                pr: P::from_str(&row.get::<_, String>(0)[..]).unwrap(),
                pull_commit: P::C::from_str(&row.get::<_, String>(1)[..])
                    .unwrap(),
                merge_commit: row.get::<_, Option<String>>(2).map(
                    |v| P::C::from_str(&v).unwrap()
                ),
                message: row.get(3),
                canceled: row.get(4),
                built: row.get(5),
            });
            rows.next()
        };
        let sql = r###"
            DELETE FROM running WHERE pipeline_id = $1
        "###;
        trans.execute(sql, &[&pipeline_id.0]).expect("Remove running entry");
        trans.commit().expect("Commit take-running transaction");
        entry
    }
    fn peek_running(
        &mut self,
        pipeline_id: PipelineId,
    ) -> Option<RunningEntry
> {
        let sql = r###"
            SELECT pr, pull_commit, merge_commit, message, canceled, built
            FROM running
            WHERE pipeline_id = $1
        "###;
        let stmt = self.conn.prepare(&sql)
            .expect("Prepare peek-running query");
        let rows = stmt.query(&[&pipeline_id.0]);
        let rows = rows.expect("Get running query");
        let rows = rows.iter();
        let mut rows = rows.map(|row| RunningEntry {
            pr: P::from_str(&row.get::<_, String>(0)[..]).unwrap(),
            pull_commit: P::C::from_str(&row.get::<_, String>(1)[..])
                .unwrap(),
            merge_commit: row.get::<_, Option<String>>(2).map(
                |v| P::C::from_str(&v).unwrap()
            ),
            message: row.get(3),
            canceled: row.get(4),
            built: row.get(5),
        });
        rows.next()
    }
    fn add_pending(
        &mut self,
        pipeline_id: PipelineId,
        entry: PendingEntry
,
    ) {
        let trans = self.conn.transaction()
            .expect("Start add-pending transaction");
        let sql = r###"
            DELETE FROM pending WHERE pipeline_id = $1 AND pr = $2
        "###;
        trans.execute(sql, &[
            &pipeline_id.0,
            &<P as Into<String>>::into(entry.pr.clone()),
        ]).expect("Remove pending entry");
        let sql = r###"
            INSERT INTO pending (pipeline_id, pr, pull_commit, title, url)
            VALUES ($1, $2, $3, $4, $5)
        "###;
        trans.execute(sql, &[
            &pipeline_id.0,
            &<P as Into<String>>::into(entry.pr.clone()),
            &<P::C as Into<String>>::into(entry.commit.clone()),
            &entry.title,
            &entry.url.as_str(),
        ]).expect("Add pending entry");
        trans.commit().expect("Commit add-pending transaction");
    }
    fn take_pending_by_pr(
        &mut self,
        pipeline_id: PipelineId,
        pr: &P,
    ) -> Option<PendingEntry
> {
        let trans = self.conn.transaction()
            .expect("Start take-pending transaction");
        let sql = r###"
            SELECT id, pr, pull_commit, title, url
            FROM pending
            WHERE pipeline_id = $1 AND pr = $2
        "###;
        let entry = {
            let stmt = trans.prepare(&sql)
                .expect("Prepare take-pending query");
            let rows = stmt.query(&[
                &pipeline_id.0,
                &<P as Into<String>>::into(pr.clone()),
            ]);
            let rows = rows.expect("Get pending entry");
            let rows = rows.iter();
            let mut rows = rows.map(|row| (row.get::<_, i32>(0), PendingEntry {
                pr: P::from_str(&row.get::<_, String>(1)[..]).unwrap(),
                commit: P::C::from_str(&row.get::<_, String>(2)[..])
                    .unwrap(),
                title: row.get(3),
                url: Url::parse(&row.get::<_, String>(4)).unwrap(),
            }));
            rows.next()
        };
        if let Some(ref entry) = entry {
            let sql = r###"
                DELETE FROM pending WHERE id = $1
            "###;
            trans.execute(sql, &[&entry.0]).expect("Remove pending entry");
            trans.commit().expect("Commit take-pending transaction");
        }
        entry.map(|entry| entry.1)
    }
    fn peek_pending_by_pr(
        &mut self,
        pipeline_id: PipelineId,
        pr: &P,
    ) -> Option<PendingEntry
> {
        let sql = r###"
            SELECT pr, pull_commit, title, url
            FROM pending
            WHERE pipeline_id = $1 AND pr = $2
        "###;
        let stmt = self.conn.prepare(&sql)
            .expect("Prepare peek-pending query");
        let rows = stmt.query(&[
            &pipeline_id.0,
            &<P as Into<String>>::into(pr.clone()),
        ]);
        let rows = rows.expect("Get pending entry");
        let rows = rows.iter();
        let mut rows = rows.map(|row| PendingEntry {
            pr: P::from_str(&row.get::<_, String>(0)[..]).unwrap(),
            commit: P::C::from_str(&row.get::<_, String>(1)[..])
                .unwrap(),
            title: row.get(2),
            url: Url::parse(&row.get::<_, String>(3)).unwrap(),
        });
        rows.next()
    }
    fn list_pending(
        &mut self,
        pipeline_id: PipelineId,
    ) -> Vec<PendingEntry
> {
        let sql = r###"
            SELECT pr, pull_commit, title, url
            FROM pending
            WHERE pipeline_id = $1
        "###;
        let stmt = self.conn.prepare(&sql)
            .expect("Prepare peek-pending query");
        let rows = stmt.query(&[&pipeline_id.0]);
        let rows = rows.expect("Get pending entry");
        let rows = rows.iter();
        let rows = rows.map(|row| PendingEntry {
            pr: P::from_str(&row.get::<_, String>(0)[..]).unwrap(),
            commit: P::C::from_str(&row.get::<_, String>(1)[..])
                .unwrap(),
            title: row.get(2),
            url: Url::parse(&row.get::<_, String>(3)).unwrap(),
        });
        let rows: Vec<PendingEntry
> = rows.collect();
        rows
    }
    fn cancel_by_pr(&mut self, pipeline_id: PipelineId, pr: &P) {
        let sql = r###"
            UPDATE running
            SET canceled = TRUE
            WHERE pipeline_id = $1 AND pr = $2
        "###;
        self.conn.execute(sql, &[
            &pipeline_id.0,
            &<P as Into<String>>::into(pr.clone()),
        ]).expect("Cancel running PR");
        let sql = r###"
            DELETE FROM queue
            WHERE pipeline_id = $1 AND pr = $2
        "###;
        self.conn.execute(sql, &[
            &pipeline_id.0,
            &<P as Into<String>>::into(pr.clone()),
        ]).expect("Cancel queue entries");
    }
    fn cancel_by_pr_different_commit(
        &mut self,
        pipeline_id: PipelineId,
        pr: &P,
        commit: &P::C,
    ) -> bool {
        let sql = r###"
            UPDATE running
            SET canceled = TRUE
            WHERE pipeline_id = $1 AND pr = $2 AND pull_commit <> $3
        "###;
        let affected_rows_running = self.conn.execute(sql, &[
            &pipeline_id.0,
            &<P as Into<String>>::into(pr.clone()),
            &<P::C as Into<String>>::into(commit.clone()),
        ]).expect("Cancel running PR");
        let sql = r###"
            DELETE FROM queue
            WHERE pipeline_id = $1 AND pr = $2 AND pull_commit <> $3
        "###;
        let affected_rows_queue = self.conn.execute(sql, &[
            &pipeline_id.0,
            &<P as Into<String>>::into(pr.clone()),
            &<P::C as Into<String>>::into(commit.clone()),
        ]).expect("Cancel queue entries");
        affected_rows_queue != 0 || affected_rows_running != 0
    }
}<|endoftext|>


<commit_before>//! Unimplemented.
//! automatically generated by rust-bindgen

pub use super::libextern::*;

#[link(name = "R")]
extern {
    pub static mut R_NaN: ::libc::c_double;
    pub static mut R_PosInf: ::libc::c_double;
    pub static mut R_NegInf: ::libc::c_double;
    pub static mut R_NaReal: ::libc::c_double;
    pub static mut R_NaInt: ::libc::c_int;
}
#[link(name = "R")]
extern {
    pub fn isnan(__value: ::libc::c_double) -> ::libc::c_int;
    pub fn finite(__value: ::libc::c_double) -> ::libc::c_int;
    pub fn R_IsNA(arg1: ::libc::c_double) -> ::libc::c_int;
    pub fn R_IsNaN(arg1: ::libc::c_double) -> ::libc::c_int;
    pub fn R_finite(arg1: ::libc::c_double) -> ::libc::c_int;
}

pub unsafe fn ISNA(x: ::libc::c_double) -> ::libc::c_int {
    R_IsNA(x)
}
pub unsafe fn ISNAN(x: ::libc::c_double) -> ::libc::c_int {
    (isnan(x) != 0) as ::libc::c_int
}

pub unsafe fn R_FINITE(x: ::libc::c_double) -> ::libc::c_int {
    R_finite(x)
}
<commit_msg>Remove unimplemented document mark for ext/arith<commit_after>//! automatically generated by rust-bindgen

pub use super::libextern::*;

#[link(name = "R")]
extern {
    pub static mut R_NaN: ::libc::c_double;
    pub static mut R_PosInf: ::libc::c_double;
    pub static mut R_NegInf: ::libc::c_double;
    pub static mut R_NaReal: ::libc::c_double;
    pub static mut R_NaInt: ::libc::c_int;
}
#[link(name = "R")]
extern {
    pub fn isnan(__value: ::libc::c_double) -> ::libc::c_int;
    pub fn finite(__value: ::libc::c_double) -> ::libc::c_int;
    pub fn R_IsNA(arg1: ::libc::c_double) -> ::libc::c_int;
    pub fn R_IsNaN(arg1: ::libc::c_double) -> ::libc::c_int;
    pub fn R_finite(arg1: ::libc::c_double) -> ::libc::c_int;
}

pub unsafe fn ISNA(x: ::libc::c_double) -> ::libc::c_int {
    R_IsNA(x)
}
pub unsafe fn ISNAN(x: ::libc::c_double) -> ::libc::c_int {
    (isnan(x) != 0) as ::libc::c_int
}

pub unsafe fn R_FINITE(x: ::libc::c_double) -> ::libc::c_int {
    R_finite(x)
}
<|endoftext|>