<commit_before>//! Exposes the `Middleware` trait which must be implemented by
//! all middleware.

use super::response::Response;
use super::request::Request;
use super::alloy::Alloy;

/// The Status returned by `Middleware's` `enter` and `exit` methods. This indicates
/// to the `Furnace` whether this is a terminal `Middleware` or whether to continue
/// passing the `Request` and `Response` down the `Furnace's` stack.
///
/// Most `Furnaces` will ignore the returned `Status` from the `exit` method of
/// `Middleware`.
pub enum Status {
    /// `Continue` indicates that this is an intermediate `Middleware` in the stack
    /// and the `Furnace` should continue passing requests down the `Furnace's`
    /// stack.
    ///
    /// Most `Middleware` will return `Continue` from both `enter` and `exit`.
    Continue,

    /// `Unwind` indicates that this is a terminal `Middleware` or that something
    /// went wrong. It can be used to immediately stop passing requests down the
    /// `Furnace's` stack and start calling `exit` of all previous `Middleware`.
    ///
    /// For instance, an authorization `Middleware` might return `Unwind` if the
    /// `Request` fails an authentication check, and `Continue` otherwise.
    Unwind
}

/// All middleware should implement `Middleware`, which allows it to be `smelted`
/// to a `Furnace` so that it will be called for each incoming request.
///
/// There are two sorts of data associated with `Middleware`, data internal
/// to the `Middleware` and data that the `Middleware` would like to expose to
/// other `Middleware` further down the stack or to terminal controllers.
///
/// Internal data should be stored on the `struct` that implements `Middleware`
/// itself. All `Middleware` are cloned for each client request, so the object
/// initially smelted on to the `Iron` instance will be provided as `&mut self` to
/// enter for every request. Data stored on a `Middleware` instance does _not_ persist
/// between requests and is _not_ shared between different, concurrent, requests.
/// The same is true for data stored on an `Alloy`.
///
/// External data should be stored in the `Alloy` passed to both `enter` and
/// `exit`. `Alloy` is a thin wrapper around `AnyMap` and is effectively a
/// a key value store from a type to an instance of that type. This means
/// that each `Middleware` can have a unique type that it stores in the `Alloy`.
/// This can either be an instance of that `Middleware` or some other type. Since
/// the same `Alloy` is passed to all further `Middleware` in the `Furnace`, this
/// scheme allows you to expose data or functionality to future `Middleware`.
pub trait Middleware: Send + Clone {
    /// `enter` is called for each `Middleware` in a `Furnace` as a client request
    /// comes down the stack. `Middleware` have their `enter` methods called in the order
    /// in which they were added to the stack, that is, FIFO. `Middleware` should expose
    /// data through `Alloy` and store any data that will persist through the request here.
    ///
    /// Returning `Unwind` from this handler will cause the `Furnace` to stop
    /// going down its stack and start bubbling back up through `Middleware`
    /// and calling `exit` on them.
    fn enter(&mut self,
             _request: &mut Request,
             _response: &mut Response,
             _alloy: &mut Alloy) -> Status {
        Continue
    }

    /// `exit` is called for each `Middleware` in a `Furnace` that has had its `enter`
    /// method called for this client request. A `Middleware's` `exit` method will be called
    /// as the stack is unwound in FILO order - i.e, `Middleware` have their `exit`
    /// methods called in opposite order from which `enter` was called.
    ///
    /// While this method must return a `Status`, most `Furnaces` will ignore
    /// this method's return value.
    fn exit(&mut self,
            _request: &mut Request,
            _response: &mut Response,
            _alloy: &mut Alloy) -> Status {
        Continue
    }

    fn clone_box(&self) -> Box<Middleware> { box self.clone() as Box<Middleware> }
}

impl Clone for Box<Middleware> {
    fn clone(&self) -> Box<Middleware> { self.clone_box() }
}
<commit_msg>(doc) Documented Middleware.<commit_after>//! Exposes the `Middleware` trait which must be implemented by
//! all middleware.

use super::response::Response;
use super::request::Request;
use super::alloy::Alloy;

/// The Status returned by `Middleware's` `enter` and `exit` methods. This indicates
/// to the `Furnace` whether this is a terminal `Middleware` or whether to continue
/// passing the `Request` and `Response` down the `Furnace's` stack.
///
/// Most `Furnaces` will ignore the returned `Status` from the `exit` method of
/// `Middleware`.
pub enum Status {
    /// `Continue` indicates that this is an intermediate `Middleware` in the stack
    /// and the `Furnace` should continue passing requests down the `Furnace's`
    /// stack.
    ///
    /// Most `Middleware` will return `Continue` from both `enter` and `exit`.
    Continue,

    /// `Unwind` indicates that this is a terminal `Middleware` or that something
    /// went wrong. It can be used to immediately stop passing requests down the
    /// `Furnace's` stack and start calling `exit` of all previous `Middleware`.
    ///
    /// For instance, an authorization `Middleware` might return `Unwind` if the
    /// `Request` fails an authentication check, and `Continue` otherwise.
    Unwind
}

/// All middleware should implement `Middleware`, which allows it to be `smelted`
/// to a `Furnace` so that it will be called for each incoming request.
///
/// There are two sorts of data associated with `Middleware`, data internal
/// to the `Middleware` and data that the `Middleware` would like to expose to
/// other `Middleware` further down the stack or to terminal controllers.
///
/// Internal data should be stored on the `struct` that implements `Middleware`
/// itself. All `Middleware` are cloned for each client request, so the object
/// initially smelted on to the `Iron` instance will be provided as `&mut self` to
/// enter for every request. Data stored on a `Middleware` instance does _not_ persist
/// between requests and is _not_ shared between different, concurrent, requests.
/// The same is true for data stored on an `Alloy`.
///
/// External data should be stored in the `Alloy` passed to both `enter` and
/// `exit`. `Alloy` is a thin wrapper around `AnyMap` and is effectively a
/// a key value store from a type to an instance of that type. This means
/// that each `Middleware` can have a unique type that it stores in the `Alloy`.
/// This can either be an instance of that `Middleware` or some other type. Since
/// the same `Alloy` is passed to all further `Middleware` in the `Furnace`, this
/// scheme allows you to expose data or functionality to future `Middleware`.
pub trait Middleware: Send + Clone {
    /// `enter` is called for each `Middleware` in a `Furnace` as a client request
    /// comes down the stack. `Middleware` have their `enter` methods called in the order
    /// in which they were added to the stack, that is, FIFO. `Middleware` should expose
    /// data through `Alloy` and store any data that will persist through the request here.
    ///
    /// Returning `Unwind` from this handler will cause the `Furnace` to stop
    /// going down its stack and start bubbling back up through `Middleware`
    /// and calling `exit` on them.
    fn enter(&mut self,
             _request: &mut Request,
             _response: &mut Response,
             _alloy: &mut Alloy) -> Status {
        Continue
    }

    /// `exit` is called for each `Middleware` in a `Furnace` that has had its `enter`
    /// method called for this client request. A `Middleware's` `exit` method will be called
    /// as the stack is unwound in FILO order - i.e, `Middleware` have their `exit`
    /// methods called in opposite order from which `enter` was called.
    ///
    /// While this method must return a `Status`, most `Furnaces` will ignore
    /// this method's return value.
    fn exit(&mut self,
            _request: &mut Request,
            _response: &mut Response,
            _alloy: &mut Alloy) -> Status {
        Continue
    }

    // Helper function to clone the Middleware.
    #[allow(missing_doc)]
    fn clone_box(&self) -> Box<Middleware> { box self.clone() as Box<Middleware> }
}

impl Clone for Box<Middleware> {
    fn clone(&self) -> Box<Middleware> { self.clone_box() }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use chrono::NaiveDateTime;
use diesel;
use diesel::prelude::*;
use semver;
use serde_json;

use license_exprs;
use util::{human, CargoResult};

use models::{Crate, Dependency};
use schema::*;
use views::{EncodableVersion, EncodableVersionLinks};

// Queryable has a custom implementation below
#[derive(Clone, Identifiable, Associations, Debug, Queryable)]
#[belongs_to(Crate)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: semver::Version,
    pub updated_at: NaiveDateTime,
    pub created_at: NaiveDateTime,
    pub downloads: i32,
    pub features: serde_json::Value,
    pub yanked: bool,
    pub license: Option<String>,
    pub crate_size: Option<i32>,
}

#[derive(Insertable, Debug)]
#[table_name = "versions"]
pub struct NewVersion {
    crate_id: i32,
    num: String,
    features: serde_json::Value,
    license: Option<String>,
    crate_size: Option<i32>,
}

impl Version {
    pub fn encodable(self, crate_name: &str) -> EncodableVersion {
        let Version {
            id,
            num,
            updated_at,
            created_at,
            downloads,
            features,
            yanked,
            license,
            crate_size,
            ..
        } = self;
        let num = num.to_string();
        EncodableVersion {
            dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num),
            readme_path: format!("/api/v1/crates/{}/{}/readme", crate_name, num),
            num: num.clone(),
            id,
            krate: crate_name.to_string(),
            updated_at,
            created_at,
            downloads,
            features,
            yanked,
            license,
            links: EncodableVersionLinks {
                dependencies: format!("/api/v1/crates/{}/{}/dependencies", crate_name, num),
                version_downloads: format!("/api/v1/crates/{}/{}/downloads", crate_name, num),
                authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num),
            },
            crate_size,
        }
    }

    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &PgConnection) -> QueryResult<Vec<(Dependency, String)>> {
        Dependency::belonging_to(self)
            .inner_join(crates::table)
            .select((dependencies::all_columns, crates::name))
            .order((dependencies::optional, crates::name))
            .load(conn)
    }

    pub fn max<T>(versions: T) -> semver::Version
    where
        T: IntoIterator<Item = semver::Version>,
    {
        versions
            .into_iter()
            .max()
            .unwrap_or_else(|| semver::Version {
                major: 0,
                minor: 0,
                patch: 0,
                pre: vec![],
                build: vec![],
            })
    }

    pub fn record_readme_rendering(&self, conn: &PgConnection) -> QueryResult<usize> {
        use diesel::dsl::now;
        use schema::readme_renderings::dsl::*;

        diesel::insert_into(readme_renderings)
            .values(version_id.eq(self.id))
            .on_conflict(version_id)
            .do_update()
            .set(rendered_at.eq(now))
            .execute(conn)
    }
}

impl NewVersion {
    pub fn new(
        crate_id: i32,
        num: &semver::Version,
        features: &HashMap<String, Vec<String>>,
        license: Option<String>,
        license_file: Option<&str>,
        crate_size: Option<i32>,
    ) -> CargoResult<Self> {
        let features = serde_json::to_value(features)?;

        let mut new_version = NewVersion {
            crate_id,
            num: num.to_string(),
            features,
            license,
            crate_size,
        };

        new_version.validate_license(license_file)?;

        Ok(new_version)
    }

    pub fn save(&self, conn: &PgConnection, authors: &[String]) -> CargoResult<Version> {
        use diesel::dsl::exists;
        use diesel::{insert_into, select};
        use schema::version_authors::{name, version_id};
        use schema::versions::dsl::*;

        conn.transaction(|| {
            let already_uploaded = versions
                .filter(crate_id.eq(self.crate_id))
                .filter(num.eq(&self.num));
            if select(exists(already_uploaded)).get_result(conn)? {
                return Err(human(&format_args!(
                    "crate version `{}` is already \
                     uploaded",
                    self.num
                )));
            }

            let version = insert_into(versions)
                .values(self)
                .get_result::<Version>(conn)?;

            let new_authors = authors
                .iter()
                .map(|s| (version_id.eq(version.id), name.eq(s)))
                .collect::<Vec<_>>();

            insert_into(version_authors::table)
                .values(&new_authors)
                .execute(conn)?;
            Ok(version)
        })
    }

    fn validate_license(&mut self, license_file: Option<&str>) -> CargoResult<()> {
        if let Some(ref license) = self.license {
            for part in license.split('/') {
                license_exprs::validate_license_expr(part).map_err(|e| {
                    human(&format_args!(
                        "{}; see http://opensource.org/licenses \
                         for options, and http://spdx.org/licenses/ \
                         for their identifiers",
                        e
                    ))
                })?;
            }
        } else if license_file.is_some() {
            // If no license is given, but a license file is given, flag this
            // crate as having a nonstandard license. Note that we don't
            // actually do anything else with license_file currently.
            self.license = Some(String::from("non-standard"));
        }
        Ok(())
    }
}
<commit_msg>Updates the Version and NewVersion models to add<commit_after>use std::collections::HashMap;

use chrono::NaiveDateTime;
use diesel;
use diesel::prelude::*;
use semver;
use serde_json;

use license_exprs;
use util::{human, CargoResult};

use models::{Crate, Dependency};
use schema::*;
use views::{EncodableVersion, EncodableVersionLinks};

// Queryable has a custom implementation below
#[derive(Clone, Identifiable, Associations, Debug, Queryable)]
#[belongs_to(Crate)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: semver::Version,
    pub updated_at: NaiveDateTime,
    pub created_at: NaiveDateTime,
    pub downloads: i32,
    pub features: serde_json::Value,
    pub yanked: bool,
    pub license: Option<String>,
    pub crate_size: Option<i32>,
    pub published_by: i32,
}

#[derive(Insertable, Debug)]
#[table_name = "versions"]
pub struct NewVersion {
    crate_id: i32,
    num: String,
    features: serde_json::Value,
    license: Option<String>,
    crate_size: Option<i32>,
    published_by: i32,
}

impl Version {
    pub fn encodable(self, crate_name: &str) -> EncodableVersion {
        let Version {
            id,
            num,
            updated_at,
            created_at,
            downloads,
            features,
            yanked,
            license,
            crate_size,
            published_by,
            ..
        } = self;
        let num = num.to_string();
        EncodableVersion {
            dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num),
            readme_path: format!("/api/v1/crates/{}/{}/readme", crate_name, num),
            num: num.clone(),
            id,
            krate: crate_name.to_string(),
            updated_at,
            created_at,
            downloads,
            features,
            yanked,
            license,
            links: EncodableVersionLinks {
                dependencies: format!("/api/v1/crates/{}/{}/dependencies", crate_name, num),
                version_downloads: format!("/api/v1/crates/{}/{}/downloads", crate_name, num),
                authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num),
            },
            crate_size,
            published_by,
        }
    }

    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &PgConnection) -> QueryResult<Vec<(Dependency, String)>> {
        Dependency::belonging_to(self)
            .inner_join(crates::table)
            .select((dependencies::all_columns, crates::name))
            .order((dependencies::optional, crates::name))
            .load(conn)
    }

    pub fn max<T>(versions: T) -> semver::Version
    where
        T: IntoIterator<Item = semver::Version>,
    {
        versions
            .into_iter()
            .max()
            .unwrap_or_else(|| semver::Version {
                major: 0,
                minor: 0,
                patch: 0,
                pre: vec![],
                build: vec![],
            })
    }

    pub fn record_readme_rendering(&self, conn: &PgConnection) -> QueryResult<usize> {
        use diesel::dsl::now;
        use schema::readme_renderings::dsl::*;

        diesel::insert_into(readme_renderings)
            .values(version_id.eq(self.id))
            .on_conflict(version_id)
            .do_update()
            .set(rendered_at.eq(now))
            .execute(conn)
    }
}

impl NewVersion {
    pub fn new(
        crate_id: i32,
        num: &semver::Version,
        features: &HashMap<String, Vec<String>>,
        license: Option<String>,
        license_file: Option<&str>,
        crate_size: Option<i32>,
        published_by: i32,
    ) -> CargoResult<Self> {
        let features = serde_json::to_value(features)?;

        let mut new_version = NewVersion {
            crate_id,
            num: num.to_string(),
            features,
            license,
            crate_size,
            published_by,
        };

        new_version.validate_license(license_file)?;

        Ok(new_version)
    }

    pub fn save(&self, conn: &PgConnection, authors: &[String]) -> CargoResult<Version> {
        use diesel::dsl::exists;
        use diesel::{insert_into, select};
        use schema::version_authors::{name, version_id};
        use schema::versions::dsl::*;

        conn.transaction(|| {
            let already_uploaded = versions
                .filter(crate_id.eq(self.crate_id))
                .filter(num.eq(&self.num));
            if select(exists(already_uploaded)).get_result(conn)? {
                return Err(human(&format_args!(
                    "crate version `{}` is already \
                     uploaded",
                    self.num
                )));
            }

            let version = insert_into(versions)
                .values(self)
                .get_result::<Version>(conn)?;

            let new_authors = authors
                .iter()
                .map(|s| (version_id.eq(version.id), name.eq(s)))
                .collect::<Vec<_>>();

            insert_into(version_authors::table)
                .values(&new_authors)
                .execute(conn)?;
            Ok(version)
        })
    }

    fn validate_license(&mut self, license_file: Option<&str>) -> CargoResult<()> {
        if let Some(ref license) = self.license {
            for part in license.split('/') {
                license_exprs::validate_license_expr(part).map_err(|e| {
                    human(&format_args!(
                        "{}; see http://opensource.org/licenses \
                         for options, and http://spdx.org/licenses/ \
                         for their identifiers",
                        e
                    ))
                })?;
            }
        } else if license_file.is_some() {
            // If no license is given, but a license file is given, flag this
            // crate as having a nonstandard license. Note that we don't
            // actually do anything else with license_file currently.
            self.license = Some(String::from("non-standard"));
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Parse a Rust source file into a `syn::File` and print out a debug
//! representation of the syntax tree.
//!
//! Use the following command from this directory to test this program by
//! running it on its own source code:
//!
//!     cargo run -- main.rs
//!
//! The output will begin with:
//!
//!     File {
//!         shebang: None,
//!         attrs: [
//!             Attribute {
//!                 pound_token: Pound,
//!                 style: Inner(
//!         ...
//!     }

use std::borrow::Cow;
use std::env;
use std::ffi::OsStr;
use std::fmt::{self, Display};
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process;

enum Error {
    IncorrectUsage,
    ReadFile(io::Error),
    ParseFile {
        error: syn::Error,
        filepath: PathBuf,
        source_code: String,
    },
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            IncorrectUsage => write!(f, "Usage: dump-syntax path/to/filename.rs"),
            ReadFile(error) => write!(f, "Unable to read file: {}", error),
            ParseFile {
                error,
                filepath,
                source_code,
            } => render_location(f, error, filepath, source_code),
        }
    }
}

fn main() {
    if let Err(error) = try_main() {
        let _ = writeln!(io::stderr(), "{}", error);
        process::exit(1);
    }
}

fn try_main() -> Result<(), Error> {
    let mut args = env::args_os();
    let _ = args.next(); // executable name

    let filepath = match (args.next(), args.next()) {
        (Some(arg), None) => PathBuf::from(arg),
        _ => return Err(Error::IncorrectUsage),
    };

    let code = fs::read_to_string(&filepath).map_err(Error::ReadFile)?;
    let syntax = syn::parse_file(&code).map_err({
        |error| Error::ParseFile {
            error,
            filepath,
            source_code: code,
        }
    })?;
    println!("{:#?}", syntax);

    Ok(())
}

fn render_location(
    formatter: &mut fmt::Formatter,
    err: &syn::Error,
    filepath: &Path,
    code: &str,
) -> fmt::Result {
    let start = err.span().start();
    let mut end = err.span().end();

    if start.line == end.line && start.column == end.column {
        return render_fallback(formatter, err);
    }

    let code_line = match code.lines().nth(start.line - 1) {
        Some(line) => line,
        None => return render_fallback(formatter, err),
    };

    if end.line > start.line {
        end.line = start.line;
        end.column = code_line.len();
    }

    let filename = filepath
        .file_name()
        .map(OsStr::to_string_lossy)
        .unwrap_or(Cow::Borrowed("main.rs"));

    write!(
        formatter,
        "\n\
         error: Syn unable to parse file\n\
         {indent}--> {filename}:{linenum}:{colnum}\n\
         {indent} | \n\
         {linenum} | {code}\n\
         {indent} | {offset}{underline} {message}\n\
         ",
        filename = filename,
        linenum = start.line,
        colnum = start.column,
        indent = " ".repeat(start.line.to_string().len()),
        code = code_line,
        offset = " ".repeat(start.column),
        underline = "^".repeat(end.column - start.column),
        message = err,
    )
}

fn render_fallback(formatter: &mut fmt::Formatter, err: &syn::Error) -> fmt::Result {
    write!(formatter, "Unable to parse file: {}", err)
}
<commit_msg>Trim trailing whitespace in error message<commit_after>//! Parse a Rust source file into a `syn::File` and print out a debug
//! representation of the syntax tree.
//!
//! Use the following command from this directory to test this program by
//! running it on its own source code:
//!
//!     cargo run -- main.rs
//!
//! The output will begin with:
//!
//!     File {
//!         shebang: None,
//!         attrs: [
//!             Attribute {
//!                 pound_token: Pound,
//!                 style: Inner(
//!         ...
//!     }

use std::borrow::Cow;
use std::env;
use std::ffi::OsStr;
use std::fmt::{self, Display};
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process;

enum Error {
    IncorrectUsage,
    ReadFile(io::Error),
    ParseFile {
        error: syn::Error,
        filepath: PathBuf,
        source_code: String,
    },
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            IncorrectUsage => write!(f, "Usage: dump-syntax path/to/filename.rs"),
            ReadFile(error) => write!(f, "Unable to read file: {}", error),
            ParseFile {
                error,
                filepath,
                source_code,
            } => render_location(f, error, filepath, source_code),
        }
    }
}

fn main() {
    if let Err(error) = try_main() {
        let _ = writeln!(io::stderr(), "{}", error);
        process::exit(1);
    }
}

fn try_main() -> Result<(), Error> {
    let mut args = env::args_os();
    let _ = args.next(); // executable name

    let filepath = match (args.next(), args.next()) {
        (Some(arg), None) => PathBuf::from(arg),
        _ => return Err(Error::IncorrectUsage),
    };

    let code = fs::read_to_string(&filepath).map_err(Error::ReadFile)?;
    let syntax = syn::parse_file(&code).map_err({
        |error| Error::ParseFile {
            error,
            filepath,
            source_code: code,
        }
    })?;
    println!("{:#?}", syntax);

    Ok(())
}

fn render_location(
    formatter: &mut fmt::Formatter,
    err: &syn::Error,
    filepath: &Path,
    code: &str,
) -> fmt::Result {
    let start = err.span().start();
    let mut end = err.span().end();

    if start.line == end.line && start.column == end.column {
        return render_fallback(formatter, err);
    }

    let code_line = match code.lines().nth(start.line - 1) {
        Some(line) => line,
        None => return render_fallback(formatter, err),
    };

    if end.line > start.line {
        end.line = start.line;
        end.column = code_line.len();
    }

    let filename = filepath
        .file_name()
        .map(OsStr::to_string_lossy)
        .unwrap_or(Cow::Borrowed("main.rs"));

    write!(
        formatter,
        "\n\
         error: Syn unable to parse file\n\
         {indent}--> {filename}:{linenum}:{colnum}\n\
         {indent} | \n\
         {linenum} | {code}\n\
         {indent} | {offset}{underline} {message}\n\
         ",
        filename = filename,
        linenum = start.line,
        colnum = start.column,
        indent = " ".repeat(start.line.to_string().len()),
        code = code_line.trim_end(),
        offset = " ".repeat(start.column),
        underline = "^".repeat(end.column - start.column),
        message = err,
    )
}

fn render_fallback(formatter: &mut fmt::Formatter, err: &syn::Error) -> fmt::Result {
    write!(formatter, "Unable to parse file: {}", err)
}
<|endoftext|>


<commit_before>use rustc_serialize::json;

use std::error::Error;
use std::ffi::OsStr;
use std::fs;
use std::path::{ Path, PathBuf };

use backend::{ download, verify };
use package;

fn update_list<F>(url: &str, path: &Path, and: F) -> Result<bool, String>
    where F: Fn(u64) {
    let mut download_to = PathBuf::new();
        download_to.push(path);
        download_to.push(get_option!(url.split('/').last(), "An error occured while getting package list filename."));

    if download_to.exists() {
        let mut temporary_download_to = PathBuf::new();
            temporary_download_to.push(download_to.as_path());
            temporary_download_to.set_extension(".tmp");
        try!(download::download_file_and(url, temporary_download_to.as_path(), and));

        if try!(verify::verify_file_crc32(download_to.as_path())) == try!(verify::verify_file_crc32(temporary_download_to.as_path())) {
            get!(fs::remove_file(temporary_download_to.as_path()), "An error occured while removing unneeded package list.");
            Ok(false)
        } else {
            get!(fs::remove_file(download_to.as_path()), "An error occured while removing unneeded package list.");
            get!(fs::rename(temporary_download_to.as_path(), download_to.as_path()), "An error occured while renaming package list.");
            Ok(true)
        }
    // Indeed, this function is a giant clusterfuck. Apologies for code-gore.
    } else {
        try!(download::download_file_and(url, download_to.as_path(), and));
        Ok(true)
    }
}<commit_msg>More accurate name.<commit_after>use rustc_serialize::json;

use std::error::Error;
use std::ffi::OsStr;
use std::fs;
use std::path::{ Path, PathBuf };

use backend::{ download, verify };
use package;

fn update_list<F>(url: &str, path: &Path, after_download: F) -> Result<bool, String>
    where F: Fn(u64) {
    let mut download_to = PathBuf::new();
        download_to.push(path);
        download_to.push(get_option!(url.split('/').last(), "An error occured while getting package list filename."));

    if download_to.exists() {
        let mut temporary_download_to = PathBuf::new();
            temporary_download_to.push(download_to.as_path());
            temporary_download_to.set_extension(".tmp");
        try!(download::download_file_and(url, temporary_download_to.as_path(), after_download));

        if try!(verify::verify_file_crc32(download_to.as_path())) == try!(verify::verify_file_crc32(temporary_download_to.as_path())) {
            get!(fs::remove_file(temporary_download_to.as_path()), "An error occured while removing unneeded package list.");
            Ok(false)
        } else {
            get!(fs::remove_file(download_to.as_path()), "An error occured while removing unneeded package list.");
            get!(fs::rename(temporary_download_to.as_path(), download_to.as_path()), "An error occured while renaming package list.");
            Ok(true)
        }
    // Indeed, this function is a giant clusterfuck. Apologies for code-gore.
    } else {
        try!(download::download_file_and(url, download_to.as_path(), after_download));
        Ok(true)
    }
}<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::path::Path;
use std::fmt::{Debug, Formatter, Error as FmtError};
use std::result::Result as RResult;

use toml::Value;

use libimagerror::trace::trace_error;
use libimagstore::hook::Hook;
use libimagstore::hook::accessor::StoreIdAccessor;
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
use libimagstore::hook::position::HookPosition;
use libimagstore::hook::result::HookResult;
use libimagstore::storeid::StoreId;
use libimagutil::debug_result::*;

use vcs::git::error::GitHookErrorKind as GHEK;
use vcs::git::error::MapErrInto;
use vcs::git::runtime::Runtime as GRuntime;

/// The `UpdateHook` type
///
/// Represents a hook which is executed whenever a entry in the store is updated (written to disk).
///
/// # Time of execution
///
/// This hook is executed _after_ the store operation succeeded, so _after_ the file is written to
/// disk.
pub struct UpdateHook {
    storepath: PathBuf,

    runtime: GRuntime,

    position: HookPosition,
}

impl UpdateHook {

    pub fn new(storepath: PathBuf, p: HookPosition) -> UpdateHook {
        UpdateHook {
            runtime: GRuntime::new(&storepath),
            storepath: storepath,
            position: p,
        }
    }

}

impl Debug for UpdateHook {
    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "UpdateHook(storepath={:?}, repository={}, pos={:?}, cfg={:?})",
               self.storepath,
               (if self.runtime.has_repository() { "Some(_)" } else { "None" }),
               self.position,
               self.runtime.has_config())
    }
}

impl Hook for UpdateHook {

    fn name(&self) -> &'static str {
        "stdhook_git_update"
    }

    /// Set the configuration of the hook. See
    /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`.
    ///
    /// This function traces the error (using `trace_error()`) that
    /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`
    /// returns, if any.
    fn set_config(&mut self, config: &Value) {
        if let Err(e) = self.runtime.set_config(config) {
            trace_error(&e);
        }
    }

}

impl HookDataAccessorProvider for UpdateHook {

    fn accessor(&self) -> HookDataAccessor {
        HookDataAccessor::StoreIdAccess(self)
    }
}

impl StoreIdAccessor for UpdateHook {

    /// The implementation of the UpdateHook
    ///
    /// # Scope
    ///
    /// This hook takes the git index and commits it either interactively or with a default message,
    /// if there is no configuration for an interactive commit.
    ///
    fn access(&self, id: &StoreId) -> HookResult<()> {
        use libimagerror::into::IntoError;
        use vcs::git::action::StoreAction;
        use vcs::git::config::commit_message;
        use vcs::git::error::MapIntoHookError;
        use vcs::git::util::fetch_index;
        use vcs::git::config::abort_on_repo_init_err;
        use git2::{ADD_DEFAULT, STATUS_WT_NEW, STATUS_WT_MODIFIED, IndexMatchedPath};

        debug!("[GIT UPDATE HOOK]: {:?}", id);

        let action = StoreAction::Update;

        if !self.runtime.has_repository() {
            debug!("[GIT UPDATE HOOK]: Runtime has no repository...");
            if try!(self.runtime.config_value_or_err(&action).map(|c| abort_on_repo_init_err(c))) {
                // Abort on repo init failure
                debug!("[GIT UPDATE HOOK]: Config says we should abort if we have no repository");
                debug!("[GIT UPDATE HOOK]: Returing Err(_)");
                return Err(GHEK::RepositoryInitError.into_error())
                    .map_err_into(GHEK::RepositoryError)
                    .map_into_hook_error()
            } else {
                debug!("[GIT UPDATE HOOK]: Config says it is okay to not have a repository");
                debug!("[GIT UPDATE HOOK]: Returing Ok(())");
                return Ok(())
            }
        }

        let cfg       = try!(self.runtime.config_value_or_err(&action));
        let repo      = try!(self.runtime.repository(&action));
        let mut index = try!(fetch_index(repo, &action));

        if !self.runtime.repo_is_dirty(&index) {
            debug!("[GIT UPDATE HOOK]: Repository seems to be clean. I'm done.");
            return Ok(())
        } else {
            debug!("[GIT UPDATE HOOK]: Repository seems to be dirty. Continuing.");
        }

        let signature = try!(
            repo.signature()
                .map_err_into(GHEK::MkSignature)
                .map_dbg_err_str("Failed to fetch signature")
                .map_dbg_str("[GIT UPDATE HOOK]: Fetched signature object")
                .map_into_hook_error()
        );

        let head = try!(
            repo.head()
                .map_err_into(GHEK::HeadFetchError)
                .map_dbg_err_str("Failed to fetch HEAD")
                .map_dbg_str("[GIT UPDATE HOOK]: Fetched HEAD")
                .map_into_hook_error()
        );

        let file_status = try!(
            repo
                .status_file(id.local())
                .map_dbg_err_str("Failed to fetch file status")
                .map_dbg_err(|e| format!("\t->  {:?}", e))
                .map_dbg_str("[GIT UPDATE HOOK]: Fetched file status")
                .map_err_into(GHEK::RepositoryFileStatusError)
                .map_into_hook_error()
        );

        let cb = &mut |path: &Path, _matched_spec: &[u8]| -> i32 {
            if file_status.contains(STATUS_WT_NEW) || file_status.contains(STATUS_WT_MODIFIED) {
                debug!("[GIT CREATE HOOK]: File is modified/new: {}", path.display());
                0
            } else {
                debug!("[GIT CREATE HOOK]: Ignoring file: {}", path.display());
                1
            }
        };

        try!(
            index.add_all(&[id.local()], ADD_DEFAULT, Some(cb as &mut IndexMatchedPath))
                .map_err_into(GHEK::RepositoryPathAddingError)
                .map_dbg_err_str("Failed to add to index")
                .map_dbg(|_| format!("[GIT UPDATE HOOK]: Added id ({:?}) to index", id))
                .map_into_hook_error()
        );

        let tree_id = try!(
            index.write_tree()
                .map_err_into(GHEK::RepositoryIndexWritingError)
                .map_dbg_err_str("Failed to write tree")
                .map_dbg_str("[GIT UPDATE HOOK]: Wrote tree")
                .map_into_hook_error()
        );

        let mut parents = Vec::new();
        {
            let commit = try!(
                repo.find_commit(head.target().unwrap())
                    .map_err_into(GHEK::RepositoryParentFetchingError)
                    .map_dbg_err_str("Failed to find commit HEAD")
                    .map_dbg_str("[GIT UPDATE HOOK]: Fetched commit parents of HEAD")
                    .map_into_hook_error()
            );
            parents.push(commit);
        }

        // for converting from Vec<Commit> to Vec<&Commit>
        let parents = parents.iter().collect::<Vec<_>>();

        let tree = try!(
            repo.find_tree(tree_id)
                .map_err_into(GHEK::RepositoryParentFetchingError)
                .map_dbg_err_str("Failed to find tree")
                .map_dbg_str("[GIT UPDATE HOOK]: Found Tree for parents")
                .map_into_hook_error()
        );

        let message = try!(commit_message(&repo, cfg, StoreAction::Update, &id)
                .map_dbg_err_str("Failed to get commit message")
                .map_dbg_str("[GIT UPDATE HOOK]: Fetched commit message"));

        try!(repo.commit(Some("HEAD"), &signature, &signature, &message, &tree, &parents)
            .map_dbg_str("Committed")
            .map_dbg_err_str("Failed to commit")
            .map_err_into(GHEK::RepositoryCommittingError)
            .map_into_hook_error()
        );

        index.write()
            .map_err_into(GHEK::RepositoryIndexWritingError)
            .map_dbg_err_str("Failed to write tree")
            .map_into_hook_error()
            .map(|_| ())
    }

}

<commit_msg>UpdateHook: Ensure the right branch is checked out<commit_after>use std::path::PathBuf;
use std::path::Path;
use std::fmt::{Debug, Formatter, Error as FmtError};
use std::result::Result as RResult;

use toml::Value;

use libimagerror::trace::trace_error;
use libimagstore::hook::Hook;
use libimagstore::hook::accessor::StoreIdAccessor;
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
use libimagstore::hook::position::HookPosition;
use libimagstore::hook::result::HookResult;
use libimagstore::storeid::StoreId;
use libimagutil::debug_result::*;

use vcs::git::error::GitHookErrorKind as GHEK;
use vcs::git::error::MapErrInto;
use vcs::git::runtime::Runtime as GRuntime;

/// The `UpdateHook` type
///
/// Represents a hook which is executed whenever a entry in the store is updated (written to disk).
///
/// # Time of execution
///
/// This hook is executed _after_ the store operation succeeded, so _after_ the file is written to
/// disk.
pub struct UpdateHook {
    storepath: PathBuf,

    runtime: GRuntime,

    position: HookPosition,
}

impl UpdateHook {

    pub fn new(storepath: PathBuf, p: HookPosition) -> UpdateHook {
        UpdateHook {
            runtime: GRuntime::new(&storepath),
            storepath: storepath,
            position: p,
        }
    }

}

impl Debug for UpdateHook {
    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "UpdateHook(storepath={:?}, repository={}, pos={:?}, cfg={:?})",
               self.storepath,
               (if self.runtime.has_repository() { "Some(_)" } else { "None" }),
               self.position,
               self.runtime.has_config())
    }
}

impl Hook for UpdateHook {

    fn name(&self) -> &'static str {
        "stdhook_git_update"
    }

    /// Set the configuration of the hook. See
    /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`.
    ///
    /// This function traces the error (using `trace_error()`) that
    /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`
    /// returns, if any.
    fn set_config(&mut self, config: &Value) {
        if let Err(e) = self.runtime.set_config(config) {
            trace_error(&e);
        }
    }

}

impl HookDataAccessorProvider for UpdateHook {

    fn accessor(&self) -> HookDataAccessor {
        HookDataAccessor::StoreIdAccess(self)
    }
}

impl StoreIdAccessor for UpdateHook {

    /// The implementation of the UpdateHook
    ///
    /// # Scope
    ///
    /// This hook takes the git index and commits it either interactively or with a default message,
    /// if there is no configuration for an interactive commit.
    ///
    fn access(&self, id: &StoreId) -> HookResult<()> {
        use libimagerror::into::IntoError;
        use vcs::git::action::StoreAction;
        use vcs::git::config::commit_message;
        use vcs::git::error::MapIntoHookError;
        use vcs::git::util::fetch_index;
        use vcs::git::config::abort_on_repo_init_err;
        use git2::{ADD_DEFAULT, STATUS_WT_NEW, STATUS_WT_MODIFIED, IndexMatchedPath};

        debug!("[GIT UPDATE HOOK]: {:?}", id);

        let action = StoreAction::Update;

        if !self.runtime.has_repository() {
            debug!("[GIT UPDATE HOOK]: Runtime has no repository...");
            if try!(self.runtime.config_value_or_err(&action).map(|c| abort_on_repo_init_err(c))) {
                // Abort on repo init failure
                debug!("[GIT UPDATE HOOK]: Config says we should abort if we have no repository");
                debug!("[GIT UPDATE HOOK]: Returing Err(_)");
                return Err(GHEK::RepositoryInitError.into_error())
                    .map_err_into(GHEK::RepositoryError)
                    .map_into_hook_error()
            } else {
                debug!("[GIT UPDATE HOOK]: Config says it is okay to not have a repository");
                debug!("[GIT UPDATE HOOK]: Returing Ok(())");
                return Ok(())
            }
        }

        let _         = try!(self.runtime.ensure_cfg_branch_is_checked_out(&action));
        let cfg       = try!(self.runtime.config_value_or_err(&action));
        let repo      = try!(self.runtime.repository(&action));
        let mut index = try!(fetch_index(repo, &action));

        if !self.runtime.repo_is_dirty(&index) {
            debug!("[GIT UPDATE HOOK]: Repository seems to be clean. I'm done.");
            return Ok(())
        } else {
            debug!("[GIT UPDATE HOOK]: Repository seems to be dirty. Continuing.");
        }

        let signature = try!(
            repo.signature()
                .map_err_into(GHEK::MkSignature)
                .map_dbg_err_str("Failed to fetch signature")
                .map_dbg_str("[GIT UPDATE HOOK]: Fetched signature object")
                .map_into_hook_error()
        );

        let head = try!(
            repo.head()
                .map_err_into(GHEK::HeadFetchError)
                .map_dbg_err_str("Failed to fetch HEAD")
                .map_dbg_str("[GIT UPDATE HOOK]: Fetched HEAD")
                .map_into_hook_error()
        );

        let file_status = try!(
            repo
                .status_file(id.local())
                .map_dbg_err_str("Failed to fetch file status")
                .map_dbg_err(|e| format!("\t->  {:?}", e))
                .map_dbg_str("[GIT UPDATE HOOK]: Fetched file status")
                .map_err_into(GHEK::RepositoryFileStatusError)
                .map_into_hook_error()
        );

        let cb = &mut |path: &Path, _matched_spec: &[u8]| -> i32 {
            if file_status.contains(STATUS_WT_NEW) || file_status.contains(STATUS_WT_MODIFIED) {
                debug!("[GIT CREATE HOOK]: File is modified/new: {}", path.display());
                0
            } else {
                debug!("[GIT CREATE HOOK]: Ignoring file: {}", path.display());
                1
            }
        };

        try!(
            index.add_all(&[id.local()], ADD_DEFAULT, Some(cb as &mut IndexMatchedPath))
                .map_err_into(GHEK::RepositoryPathAddingError)
                .map_dbg_err_str("Failed to add to index")
                .map_dbg(|_| format!("[GIT UPDATE HOOK]: Added id ({:?}) to index", id))
                .map_into_hook_error()
        );

        let tree_id = try!(
            index.write_tree()
                .map_err_into(GHEK::RepositoryIndexWritingError)
                .map_dbg_err_str("Failed to write tree")
                .map_dbg_str("[GIT UPDATE HOOK]: Wrote tree")
                .map_into_hook_error()
        );

        let mut parents = Vec::new();
        {
            let commit = try!(
                repo.find_commit(head.target().unwrap())
                    .map_err_into(GHEK::RepositoryParentFetchingError)
                    .map_dbg_err_str("Failed to find commit HEAD")
                    .map_dbg_str("[GIT UPDATE HOOK]: Fetched commit parents of HEAD")
                    .map_into_hook_error()
            );
            parents.push(commit);
        }

        // for converting from Vec<Commit> to Vec<&Commit>
        let parents = parents.iter().collect::<Vec<_>>();

        let tree = try!(
            repo.find_tree(tree_id)
                .map_err_into(GHEK::RepositoryParentFetchingError)
                .map_dbg_err_str("Failed to find tree")
                .map_dbg_str("[GIT UPDATE HOOK]: Found Tree for parents")
                .map_into_hook_error()
        );

        let message = try!(commit_message(&repo, cfg, StoreAction::Update, &id)
                .map_dbg_err_str("Failed to get commit message")
                .map_dbg_str("[GIT UPDATE HOOK]: Fetched commit message"));

        try!(repo.commit(Some("HEAD"), &signature, &signature, &message, &tree, &parents)
            .map_dbg_str("Committed")
            .map_dbg_err_str("Failed to commit")
            .map_err_into(GHEK::RepositoryCommittingError)
            .map_into_hook_error()
        );

        index.write()
            .map_err_into(GHEK::RepositoryIndexWritingError)
            .map_dbg_err_str("Failed to write tree")
            .map_into_hook_error()
            .map(|_| ())
    }

}

<|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/. */

//! A data structure to efficiently index structs containing selectors by local
//! name, ids and hash.

use {Atom, LocalName};
use applicable_declarations::ApplicableDeclarationBlock;
use context::QuirksMode;
use dom::TElement;
use fnv::FnvHashMap;
use pdqsort::sort_by;
use rule_tree::CascadeLevel;
use selector_parser::SelectorImpl;
use selectors::matching::{matches_selector, MatchingContext, ElementSelectorFlags};
use selectors::parser::{Component, Combinator, SelectorIter};
use selectors::parser::LocalName as LocalNameSelector;
use smallvec::VecLike;
use std::collections::HashMap;
use std::collections::hash_map;
use std::hash::Hash;
use stylist::Rule;

/// A trait to abstract over a given selector map entry.
pub trait SelectorMapEntry : Sized + Clone {
    /// Gets the selector we should use to index in the selector map.
    fn selector(&self) -> SelectorIter<SelectorImpl>;
}

/// Map element data to selector-providing objects for which the last simple
/// selector starts with them.
///
/// e.g.,
/// "p > img" would go into the set of selectors corresponding to the
/// element "img"
/// "a .foo .bar.baz" would go into the set of selectors corresponding to
/// the class "bar"
///
/// Because we match selectors right-to-left (i.e., moving up the tree
/// from an element), we need to compare the last simple selector in the
/// selector with the element.
///
/// So, if an element has ID "id1" and classes "foo" and "bar", then all
/// the rules it matches will have their last simple selector starting
/// either with "#id1" or with ".foo" or with ".bar".
///
/// Hence, the union of the rules keyed on each of element's classes, ID,
/// element name, etc. will contain the Selectors that actually match that
/// element.
///
/// TODO: Tune the initial capacity of the HashMap
#[derive(Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SelectorMap<T> {
    /// A hash from an ID to rules which contain that ID selector.
    pub id_hash: MaybeCaseInsensitiveHashMap<Atom, Vec<T>>,
    /// A hash from a class name to rules which contain that class selector.
    pub class_hash: MaybeCaseInsensitiveHashMap<Atom, Vec<T>>,
    /// A hash from local name to rules which contain that local name selector.
    pub local_name_hash: FnvHashMap<LocalName, Vec<T>>,
    /// Rules that don't have ID, class, or element selectors.
    pub other: Vec<T>,
    /// The number of entries in this map.
    pub count: usize,
}

#[inline]
fn sort_by_key<T, F: Fn(&T) -> K, K: Ord>(v: &mut [T], f: F) {
    sort_by(v, |a, b| f(a).cmp(&f(b)))
}

impl<T> SelectorMap<T> {
    /// Trivially constructs an empty `SelectorMap`.
    pub fn new() -> Self {
        SelectorMap {
            id_hash: MaybeCaseInsensitiveHashMap::new(),
            class_hash: MaybeCaseInsensitiveHashMap::new(),
            local_name_hash: HashMap::default(),
            other: Vec::new(),
            count: 0,
        }
    }

    /// Returns whether there are any entries in the map.
    pub fn is_empty(&self) -> bool {
        self.count == 0
    }

    /// Returns the number of entries.
    pub fn len(&self) -> usize {
        self.count
    }
}

impl SelectorMap<Rule> {
    /// Append to `rule_list` all Rules in `self` that match element.
    ///
    /// Extract matching rules as per element's ID, classes, tag name, etc..
    /// Sort the Rules at the end to maintain cascading order.
    pub fn get_all_matching_rules<E, V, F>(&self,
                                           element: &E,
                                           rule_hash_target: &E,
                                           matching_rules_list: &mut V,
                                           context: &mut MatchingContext,
                                           quirks_mode: QuirksMode,
                                           flags_setter: &mut F,
                                           cascade_level: CascadeLevel)
        where E: TElement,
              V: VecLike<ApplicableDeclarationBlock>,
              F: FnMut(&E, ElementSelectorFlags),
    {
        if self.is_empty() {
            return
        }

        // At the end, we're going to sort the rules that we added, so remember where we began.
        let init_len = matching_rules_list.len();
        if let Some(id) = rule_hash_target.get_id() {
            if let Some(rules) = self.id_hash.get(&id, quirks_mode) {
                SelectorMap::get_matching_rules(element,
                                                rules,
                                                matching_rules_list,
                                                context,
                                                flags_setter,
                                                cascade_level)
            }
        }

        rule_hash_target.each_class(|class| {
            if let Some(rules) = self.class_hash.get(&class, quirks_mode) {
                SelectorMap::get_matching_rules(element,
                                                rules,
                                                matching_rules_list,
                                                context,
                                                flags_setter,
                                                cascade_level)
            }
        });

        if let Some(rules) = self.local_name_hash.get(rule_hash_target.get_local_name()) {
            SelectorMap::get_matching_rules(element,
                                            rules,
                                            matching_rules_list,
                                            context,
                                            flags_setter,
                                            cascade_level)
        }

        SelectorMap::get_matching_rules(element,
                                        &self.other,
                                        matching_rules_list,
                                        context,
                                        flags_setter,
                                        cascade_level);

        // Sort only the rules we just added.
        sort_by_key(&mut matching_rules_list[init_len..],
                    |block| (block.specificity, block.source_order()));
    }

    /// Append to `rule_list` all universal Rules (rules with selector `*|*`) in
    /// `self` sorted by specificity and source order.
    pub fn get_universal_rules(&self,
                               cascade_level: CascadeLevel)
                               -> Vec<ApplicableDeclarationBlock> {
        debug_assert!(!cascade_level.is_important());
        if self.is_empty() {
            return vec![];
        }

        let mut rules_list = vec![];
        for rule in self.other.iter() {
            if rule.selector.is_universal() {
                rules_list.push(rule.to_applicable_declaration_block(cascade_level))
            }
        }

        sort_by_key(&mut rules_list,
                    |block| (block.specificity, block.source_order()));

        rules_list
    }

    /// Adds rules in `rules` that match `element` to the `matching_rules` list.
    fn get_matching_rules<E, V, F>(element: &E,
                                   rules: &[Rule],
                                   matching_rules: &mut V,
                                   context: &mut MatchingContext,
                                   flags_setter: &mut F,
                                   cascade_level: CascadeLevel)
        where E: TElement,
              V: VecLike<ApplicableDeclarationBlock>,
              F: FnMut(&E, ElementSelectorFlags),
    {
        for rule in rules {
            if matches_selector(&rule.selector,
                                0,
                                Some(&rule.hashes),
                                element,
                                context,
                                flags_setter) {
                matching_rules.push(
                    rule.to_applicable_declaration_block(cascade_level));
            }
        }
    }
}

impl<T: SelectorMapEntry> SelectorMap<T> {
    /// Inserts into the correct hash, trying id, class, and localname.
    pub fn insert(&mut self, entry: T, quirks_mode: QuirksMode) {
        self.count += 1;

        if let Some(id_name) = get_id_name(entry.selector()) {
            self.id_hash.entry(id_name, quirks_mode).or_insert_with(Vec::new).push(entry);
            return;
        }

        if let Some(class_name) = get_class_name(entry.selector()) {
            self.class_hash.entry(class_name, quirks_mode).or_insert_with(Vec::new).push(entry);
            return;
        }

        if let Some(LocalNameSelector { name, lower_name }) = get_local_name(entry.selector()) {
            // If the local name in the selector isn't lowercase, insert it into
            // the rule hash twice. This means that, during lookup, we can always
            // find the rules based on the local name of the element, regardless
            // of whether it's an html element in an html document (in which case
            // we match against lower_name) or not (in which case we match against
            // name).
            //
            // In the case of a non-html-element-in-html-document with a
            // lowercase localname and a non-lowercase selector, the rulehash
            // lookup may produce superfluous selectors, but the subsequent
            // selector matching work will filter them out.
            if name != lower_name {
                find_push(&mut self.local_name_hash, lower_name, entry.clone());
            }
            find_push(&mut self.local_name_hash, name, entry);

            return;
        }

        self.other.push(entry);
    }

    /// Looks up entries by id, class, local name, and other (in order).
    ///
    /// Each entry is passed to the callback, which returns true to continue
    /// iterating entries, or false to terminate the lookup.
    ///
    /// Returns false if the callback ever returns false.
    ///
    /// FIXME(bholley) This overlaps with SelectorMap<Rule>::get_all_matching_rules,
    /// but that function is extremely hot and I'd rather not rearrange it.
    #[inline]
    pub fn lookup<E, F>(&self, element: E, quirks_mode: QuirksMode, f: &mut F) -> bool
        where E: TElement,
              F: FnMut(&T) -> bool
    {
        // Id.
        if let Some(id) = element.get_id() {
            if let Some(v) = self.id_hash.get(&id, quirks_mode) {
                for entry in v.iter() {
                    if !f(&entry) {
                        return false;
                    }
                }
            }
        }

        // Class.
        let mut done = false;
        element.each_class(|class| {
            if !done {
                if let Some(v) = self.class_hash.get(class, quirks_mode) {
                    for entry in v.iter() {
                        if !f(&entry) {
                            done = true;
                            return;
                        }
                    }
                }
            }
        });
        if done {
            return false;
        }

        // Local name.
        if let Some(v) = self.local_name_hash.get(element.get_local_name()) {
            for entry in v.iter() {
                if !f(&entry) {
                    return false;
                }
            }
        }

        // Other.
        for entry in self.other.iter() {
            if !f(&entry) {
                return false;
            }
        }

        true
    }

    /// Performs a normal lookup, and also looks up entries for the passed-in
    /// id and classes.
    ///
    /// Each entry is passed to the callback, which returns true to continue
    /// iterating entries, or false to terminate the lookup.
    ///
    /// Returns false if the callback ever returns false.
    #[inline]
    pub fn lookup_with_additional<E, F>(&self,
                                        element: E,
                                        quirks_mode: QuirksMode,
                                        additional_id: Option<&Atom>,
                                        additional_classes: &[Atom],
                                        f: &mut F)
                                        -> bool
        where E: TElement,
              F: FnMut(&T) -> bool
    {
        // Do the normal lookup.
        if !self.lookup(element, quirks_mode, f) {
            return false;
        }

        // Check the additional id.
        if let Some(id) = additional_id {
            if let Some(v) = self.id_hash.get(id, quirks_mode) {
                for entry in v.iter() {
                    if !f(&entry) {
                        return false;
                    }
                }
            }
        }

        // Check the additional classes.
        for class in additional_classes {
            if let Some(v) = self.class_hash.get(class, quirks_mode) {
                for entry in v.iter() {
                    if !f(&entry) {
                        return false;
                    }
                }
            }
        }

        true
    }
}

/// Searches a compound selector from left to right. If the compound selector
/// is a pseudo-element, it's ignored.
///
/// The first non-None value returned from |f| is returned.
#[inline(always)]
fn find_from_left<F, R>(mut iter: SelectorIter<SelectorImpl>,
                         mut f: F)
                         -> Option<R>
    where F: FnMut(&Component<SelectorImpl>) -> Option<R>,
{
    for ss in &mut iter {
        if let Some(r) = f(ss) {
            return Some(r)
        }
    }

    // Effectively, pseudo-elements are ignored, given only state pseudo-classes
    // may appear before them.
    if iter.next_sequence() == Some(Combinator::PseudoElement) {
        for ss in &mut iter {
            if let Some(r) = f(ss) {
                return Some(r)
            }
        }
    }

    None
}

/// Retrieve the first ID name in the selector, or None otherwise.
#[inline(always)]
pub fn get_id_name(iter: SelectorIter<SelectorImpl>)
                   -> Option<Atom> {
    find_from_left(iter, |ss| {
        // TODO(pradeep): Implement case-sensitivity based on the
        // document type and quirks mode.
        if let Component::ID(ref id) = *ss {
            return Some(id.clone());
        }
        None
    })
}

/// Retrieve the FIRST class name in the selector, or None otherwise.
#[inline(always)]
pub fn get_class_name(iter: SelectorIter<SelectorImpl>)
                      -> Option<Atom> {
    find_from_left(iter, |ss| {
        // TODO(pradeep): Implement case-sensitivity based on the
        // document type and quirks mode.
        if let Component::Class(ref class) = *ss {
            return Some(class.clone());
        }
        None
    })
}

/// Retrieve the name if it is a type selector, or None otherwise.
#[inline(always)]
pub fn get_local_name(iter: SelectorIter<SelectorImpl>)
                      -> Option<LocalNameSelector<SelectorImpl>> {
    find_from_left(iter, |ss| {
        if let Component::LocalName(ref n) = *ss {
            return Some(LocalNameSelector {
                name: n.name.clone(),
                lower_name: n.lower_name.clone(),
            })
        }
        None
    })
}

#[inline]
fn find_push<Str: Eq + Hash, V>(map: &mut FnvHashMap<Str, Vec<V>>,
                                key: Str,
                                value: V) {
    map.entry(key).or_insert_with(Vec::new).push(value)
}

/// Wrapper for FnvHashMap that does ASCII-case-insensitive lookup in quirks mode.
#[derive(Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct MaybeCaseInsensitiveHashMap<K: Hash + Eq, V>(FnvHashMap<K, V>);

impl<V> MaybeCaseInsensitiveHashMap<Atom, V> {
    /// Empty map
    pub fn new() -> Self {
        MaybeCaseInsensitiveHashMap(FnvHashMap::default())
    }

    /// HashMap::entry
    pub fn entry(&mut self, mut key: Atom, quirks_mode: QuirksMode) -> hash_map::Entry<Atom, V> {
        if quirks_mode == QuirksMode::Quirks {
            key = key.to_ascii_lowercase()
        }
        self.0.entry(key)
    }

    /// HashMap::iter
    pub fn iter(&self) -> hash_map::Iter<Atom, V> {
        self.0.iter()
    }

    /// HashMap::clear
    pub fn clear(&mut self) {
        self.0.clear()
    }

    /// HashMap::get
    pub fn get(&self, key: &Atom, quirks_mode: QuirksMode) -> Option<&V> {
        if quirks_mode == QuirksMode::Quirks {
            self.0.get(&key.to_ascii_lowercase())
        } else {
            self.0.get(key)
        }
    }
}
<commit_msg>Use a 1-entry smallvec in the selector maps.<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/. */

//! A data structure to efficiently index structs containing selectors by local
//! name, ids and hash.

use {Atom, LocalName};
use applicable_declarations::ApplicableDeclarationBlock;
use context::QuirksMode;
use dom::TElement;
use fnv::FnvHashMap;
use pdqsort::sort_by;
use rule_tree::CascadeLevel;
use selector_parser::SelectorImpl;
use selectors::matching::{matches_selector, MatchingContext, ElementSelectorFlags};
use selectors::parser::{Component, Combinator, SelectorIter};
use selectors::parser::LocalName as LocalNameSelector;
use smallvec::{SmallVec, VecLike};
use std::collections::HashMap;
use std::collections::hash_map;
use std::hash::Hash;
use stylist::Rule;

/// A trait to abstract over a given selector map entry.
pub trait SelectorMapEntry : Sized + Clone {
    /// Gets the selector we should use to index in the selector map.
    fn selector(&self) -> SelectorIter<SelectorImpl>;
}

/// Map element data to selector-providing objects for which the last simple
/// selector starts with them.
///
/// e.g.,
/// "p > img" would go into the set of selectors corresponding to the
/// element "img"
/// "a .foo .bar.baz" would go into the set of selectors corresponding to
/// the class "bar"
///
/// Because we match selectors right-to-left (i.e., moving up the tree
/// from an element), we need to compare the last simple selector in the
/// selector with the element.
///
/// So, if an element has ID "id1" and classes "foo" and "bar", then all
/// the rules it matches will have their last simple selector starting
/// either with "#id1" or with ".foo" or with ".bar".
///
/// Hence, the union of the rules keyed on each of element's classes, ID,
/// element name, etc. will contain the Selectors that actually match that
/// element.
///
/// We use a 1-entry SmallVec to avoid a separate heap allocation in the case
/// where we only have one entry, which is quite common. See measurements in:
/// * https://bugzilla.mozilla.org/show_bug.cgi?id=1363789#c5
/// * https://bugzilla.mozilla.org/show_bug.cgi?id=681755
///
/// TODO: Tune the initial capacity of the HashMap
#[derive(Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SelectorMap<T> {
    /// A hash from an ID to rules which contain that ID selector.
    pub id_hash: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[T; 1]>>,
    /// A hash from a class name to rules which contain that class selector.
    pub class_hash: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[T; 1]>>,
    /// A hash from local name to rules which contain that local name selector.
    pub local_name_hash: FnvHashMap<LocalName, SmallVec<[T; 1]>>,
    /// Rules that don't have ID, class, or element selectors.
    pub other: Vec<T>,
    /// The number of entries in this map.
    pub count: usize,
}

#[inline]
fn sort_by_key<T, F: Fn(&T) -> K, K: Ord>(v: &mut [T], f: F) {
    sort_by(v, |a, b| f(a).cmp(&f(b)))
}

impl<T> SelectorMap<T> {
    /// Trivially constructs an empty `SelectorMap`.
    pub fn new() -> Self {
        SelectorMap {
            id_hash: MaybeCaseInsensitiveHashMap::new(),
            class_hash: MaybeCaseInsensitiveHashMap::new(),
            local_name_hash: HashMap::default(),
            other: Vec::new(),
            count: 0,
        }
    }

    /// Returns whether there are any entries in the map.
    pub fn is_empty(&self) -> bool {
        self.count == 0
    }

    /// Returns the number of entries.
    pub fn len(&self) -> usize {
        self.count
    }
}

impl SelectorMap<Rule> {
    /// Append to `rule_list` all Rules in `self` that match element.
    ///
    /// Extract matching rules as per element's ID, classes, tag name, etc..
    /// Sort the Rules at the end to maintain cascading order.
    pub fn get_all_matching_rules<E, V, F>(&self,
                                           element: &E,
                                           rule_hash_target: &E,
                                           matching_rules_list: &mut V,
                                           context: &mut MatchingContext,
                                           quirks_mode: QuirksMode,
                                           flags_setter: &mut F,
                                           cascade_level: CascadeLevel)
        where E: TElement,
              V: VecLike<ApplicableDeclarationBlock>,
              F: FnMut(&E, ElementSelectorFlags),
    {
        if self.is_empty() {
            return
        }

        // At the end, we're going to sort the rules that we added, so remember where we began.
        let init_len = matching_rules_list.len();
        if let Some(id) = rule_hash_target.get_id() {
            if let Some(rules) = self.id_hash.get(&id, quirks_mode) {
                SelectorMap::get_matching_rules(element,
                                                rules,
                                                matching_rules_list,
                                                context,
                                                flags_setter,
                                                cascade_level)
            }
        }

        rule_hash_target.each_class(|class| {
            if let Some(rules) = self.class_hash.get(&class, quirks_mode) {
                SelectorMap::get_matching_rules(element,
                                                rules,
                                                matching_rules_list,
                                                context,
                                                flags_setter,
                                                cascade_level)
            }
        });

        if let Some(rules) = self.local_name_hash.get(rule_hash_target.get_local_name()) {
            SelectorMap::get_matching_rules(element,
                                            rules,
                                            matching_rules_list,
                                            context,
                                            flags_setter,
                                            cascade_level)
        }

        SelectorMap::get_matching_rules(element,
                                        &self.other,
                                        matching_rules_list,
                                        context,
                                        flags_setter,
                                        cascade_level);

        // Sort only the rules we just added.
        sort_by_key(&mut matching_rules_list[init_len..],
                    |block| (block.specificity, block.source_order()));
    }

    /// Append to `rule_list` all universal Rules (rules with selector `*|*`) in
    /// `self` sorted by specificity and source order.
    pub fn get_universal_rules(&self,
                               cascade_level: CascadeLevel)
                               -> Vec<ApplicableDeclarationBlock> {
        debug_assert!(!cascade_level.is_important());
        if self.is_empty() {
            return vec![];
        }

        let mut rules_list = vec![];
        for rule in self.other.iter() {
            if rule.selector.is_universal() {
                rules_list.push(rule.to_applicable_declaration_block(cascade_level))
            }
        }

        sort_by_key(&mut rules_list,
                    |block| (block.specificity, block.source_order()));

        rules_list
    }

    /// Adds rules in `rules` that match `element` to the `matching_rules` list.
    fn get_matching_rules<E, V, F>(element: &E,
                                   rules: &[Rule],
                                   matching_rules: &mut V,
                                   context: &mut MatchingContext,
                                   flags_setter: &mut F,
                                   cascade_level: CascadeLevel)
        where E: TElement,
              V: VecLike<ApplicableDeclarationBlock>,
              F: FnMut(&E, ElementSelectorFlags),
    {
        for rule in rules {
            if matches_selector(&rule.selector,
                                0,
                                Some(&rule.hashes),
                                element,
                                context,
                                flags_setter) {
                matching_rules.push(
                    rule.to_applicable_declaration_block(cascade_level));
            }
        }
    }
}

impl<T: SelectorMapEntry> SelectorMap<T> {
    /// Inserts into the correct hash, trying id, class, and localname.
    pub fn insert(&mut self, entry: T, quirks_mode: QuirksMode) {
        self.count += 1;

        if let Some(id_name) = get_id_name(entry.selector()) {
            self.id_hash.entry(id_name, quirks_mode).or_insert_with(SmallVec::new).push(entry);
            return;
        }

        if let Some(class_name) = get_class_name(entry.selector()) {
            self.class_hash.entry(class_name, quirks_mode).or_insert_with(SmallVec::new).push(entry);
            return;
        }

        if let Some(LocalNameSelector { name, lower_name }) = get_local_name(entry.selector()) {
            // If the local name in the selector isn't lowercase, insert it into
            // the rule hash twice. This means that, during lookup, we can always
            // find the rules based on the local name of the element, regardless
            // of whether it's an html element in an html document (in which case
            // we match against lower_name) or not (in which case we match against
            // name).
            //
            // In the case of a non-html-element-in-html-document with a
            // lowercase localname and a non-lowercase selector, the rulehash
            // lookup may produce superfluous selectors, but the subsequent
            // selector matching work will filter them out.
            if name != lower_name {
                find_push(&mut self.local_name_hash, lower_name, entry.clone());
            }
            find_push(&mut self.local_name_hash, name, entry);

            return;
        }

        self.other.push(entry);
    }

    /// Looks up entries by id, class, local name, and other (in order).
    ///
    /// Each entry is passed to the callback, which returns true to continue
    /// iterating entries, or false to terminate the lookup.
    ///
    /// Returns false if the callback ever returns false.
    ///
    /// FIXME(bholley) This overlaps with SelectorMap<Rule>::get_all_matching_rules,
    /// but that function is extremely hot and I'd rather not rearrange it.
    #[inline]
    pub fn lookup<E, F>(&self, element: E, quirks_mode: QuirksMode, f: &mut F) -> bool
        where E: TElement,
              F: FnMut(&T) -> bool
    {
        // Id.
        if let Some(id) = element.get_id() {
            if let Some(v) = self.id_hash.get(&id, quirks_mode) {
                for entry in v.iter() {
                    if !f(&entry) {
                        return false;
                    }
                }
            }
        }

        // Class.
        let mut done = false;
        element.each_class(|class| {
            if !done {
                if let Some(v) = self.class_hash.get(class, quirks_mode) {
                    for entry in v.iter() {
                        if !f(&entry) {
                            done = true;
                            return;
                        }
                    }
                }
            }
        });
        if done {
            return false;
        }

        // Local name.
        if let Some(v) = self.local_name_hash.get(element.get_local_name()) {
            for entry in v.iter() {
                if !f(&entry) {
                    return false;
                }
            }
        }

        // Other.
        for entry in self.other.iter() {
            if !f(&entry) {
                return false;
            }
        }

        true
    }

    /// Performs a normal lookup, and also looks up entries for the passed-in
    /// id and classes.
    ///
    /// Each entry is passed to the callback, which returns true to continue
    /// iterating entries, or false to terminate the lookup.
    ///
    /// Returns false if the callback ever returns false.
    #[inline]
    pub fn lookup_with_additional<E, F>(&self,
                                        element: E,
                                        quirks_mode: QuirksMode,
                                        additional_id: Option<&Atom>,
                                        additional_classes: &[Atom],
                                        f: &mut F)
                                        -> bool
        where E: TElement,
              F: FnMut(&T) -> bool
    {
        // Do the normal lookup.
        if !self.lookup(element, quirks_mode, f) {
            return false;
        }

        // Check the additional id.
        if let Some(id) = additional_id {
            if let Some(v) = self.id_hash.get(id, quirks_mode) {
                for entry in v.iter() {
                    if !f(&entry) {
                        return false;
                    }
                }
            }
        }

        // Check the additional classes.
        for class in additional_classes {
            if let Some(v) = self.class_hash.get(class, quirks_mode) {
                for entry in v.iter() {
                    if !f(&entry) {
                        return false;
                    }
                }
            }
        }

        true
    }
}

/// Searches a compound selector from left to right. If the compound selector
/// is a pseudo-element, it's ignored.
///
/// The first non-None value returned from |f| is returned.
#[inline(always)]
fn find_from_left<F, R>(mut iter: SelectorIter<SelectorImpl>,
                         mut f: F)
                         -> Option<R>
    where F: FnMut(&Component<SelectorImpl>) -> Option<R>,
{
    for ss in &mut iter {
        if let Some(r) = f(ss) {
            return Some(r)
        }
    }

    // Effectively, pseudo-elements are ignored, given only state pseudo-classes
    // may appear before them.
    if iter.next_sequence() == Some(Combinator::PseudoElement) {
        for ss in &mut iter {
            if let Some(r) = f(ss) {
                return Some(r)
            }
        }
    }

    None
}

/// Retrieve the first ID name in the selector, or None otherwise.
#[inline(always)]
pub fn get_id_name(iter: SelectorIter<SelectorImpl>)
                   -> Option<Atom> {
    find_from_left(iter, |ss| {
        // TODO(pradeep): Implement case-sensitivity based on the
        // document type and quirks mode.
        if let Component::ID(ref id) = *ss {
            return Some(id.clone());
        }
        None
    })
}

/// Retrieve the FIRST class name in the selector, or None otherwise.
#[inline(always)]
pub fn get_class_name(iter: SelectorIter<SelectorImpl>)
                      -> Option<Atom> {
    find_from_left(iter, |ss| {
        // TODO(pradeep): Implement case-sensitivity based on the
        // document type and quirks mode.
        if let Component::Class(ref class) = *ss {
            return Some(class.clone());
        }
        None
    })
}

/// Retrieve the name if it is a type selector, or None otherwise.
#[inline(always)]
pub fn get_local_name(iter: SelectorIter<SelectorImpl>)
                      -> Option<LocalNameSelector<SelectorImpl>> {
    find_from_left(iter, |ss| {
        if let Component::LocalName(ref n) = *ss {
            return Some(LocalNameSelector {
                name: n.name.clone(),
                lower_name: n.lower_name.clone(),
            })
        }
        None
    })
}

#[inline]
fn find_push<Str: Eq + Hash, V, VL>(map: &mut FnvHashMap<Str, VL>,
                                    key: Str,
                                    value: V)
    where VL: VecLike<V> + Default
{
    map.entry(key).or_insert_with(VL::default).push(value)
}

/// Wrapper for FnvHashMap that does ASCII-case-insensitive lookup in quirks mode.
#[derive(Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct MaybeCaseInsensitiveHashMap<K: Hash + Eq, V>(FnvHashMap<K, V>);

impl<V> MaybeCaseInsensitiveHashMap<Atom, V> {
    /// Empty map
    pub fn new() -> Self {
        MaybeCaseInsensitiveHashMap(FnvHashMap::default())
    }

    /// HashMap::entry
    pub fn entry(&mut self, mut key: Atom, quirks_mode: QuirksMode) -> hash_map::Entry<Atom, V> {
        if quirks_mode == QuirksMode::Quirks {
            key = key.to_ascii_lowercase()
        }
        self.0.entry(key)
    }

    /// HashMap::iter
    pub fn iter(&self) -> hash_map::Iter<Atom, V> {
        self.0.iter()
    }

    /// HashMap::clear
    pub fn clear(&mut self) {
        self.0.clear()
    }

    /// HashMap::get
    pub fn get(&self, key: &Atom, quirks_mode: QuirksMode) -> Option<&V> {
        if quirks_mode == QuirksMode::Quirks {
            self.0.get(&key.to_ascii_lowercase())
        } else {
            self.0.get(key)
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
extern crate chrono;
use chrono::prelude::*;

fn usage() {
    println!("\nERROR: Usage: ./getweekday-rs <MONTH> <YEAR>");
}

fn main() {
    let args: Vec<String> = env::args().collect();
    match args.len() {
        3 => {
            let m = &args[1];
            let y = &args[2];

            let month:u32 = match m.parse() {
                Ok(n)  => {
                    n
                },
                Err(_) => {
                    usage();
                    return;
                }
            };

            let year:i32 = match y.parse() {
                Ok(n)  => {
                    n
                },
                Err(_) => {
                    usage();
                    return;
                },
            };

            let mut d = NaiveDate::from_ymd(year, month, 1);
            let mut wds = Vec::new();
            for _ in 0..days_in_month(d.year(), d.month()) {
                if d.weekday().number_from_monday() <= 5 {
                    wds.push(d);
                }
                d = d.succ();
            }

            let num_wd = wds.len() as u32;
            let p:f64 = (year as f64 / month as f64) as f64;
            let q:f64 = p % (num_wd as f64);

            // awk's %0.f does banker rounding, or rounds all ties to
            // closet even number, rust's round function uses llvm's
            // intrinsics, away from zero, so we must roll our own

            let frac = q - q.trunc();
            let index:usize;
            if (frac == 0.5) && (q.trunc() as u32 % 2 == 0) {
                index = q.trunc() as usize;
            } else {
                index = q.round() as usize;
            }
            println!("{}", wds[index].format("%a %Y-%m-%d").to_string());
        },
        _ => {
            usage();
        },
    }
}

fn days_in_month(year: i32, month: u32) -> u32 {
    let (y, m) = if month == 12 {
        (year + 1, 1)
    } else {
        (year, month + 1)
    };
    let d = NaiveDate::from_ymd(y, m, 1);
    d.pred().day()
}
<commit_msg>rust-ify the assignment of index<commit_after>use std::env;
extern crate chrono;
use chrono::prelude::*;

fn usage() {
    println!("\nERROR: Usage: ./getweekday-rs <MONTH> <YEAR>");
}

fn main() {
    let args: Vec<String> = env::args().collect();
    match args.len() {
        3 => {
            let m = &args[1];
            let y = &args[2];

            let month:u32 = match m.parse() {
                Ok(n)  => {
                    n
                },
                Err(_) => {
                    usage();
                    return;
                }
            };

            let year:i32 = match y.parse() {
                Ok(n)  => {
                    n
                },
                Err(_) => {
                    usage();
                    return;
                },
            };

            let mut d = NaiveDate::from_ymd(year, month, 1);
            let mut wds = Vec::new();
            for _ in 0..days_in_month(d.year(), d.month()) {
                if d.weekday().number_from_monday() <= 5 {
                    wds.push(d);
                }
                d = d.succ();
            }

            let num_wd = wds.len() as u32;
            let p:f64 = (year as f64 / month as f64) as f64;
            let q:f64 = p % (num_wd as f64);

            // awk's %0.f does banker rounding, or rounds all ties to
            // closet even number, rust's round function uses llvm's
            // intrinsics, away from zero, so we must roll our own

            let frac = q - q.trunc();
            let index:usize =
                if (frac == 0.5) && (q.trunc() as u32 % 2 == 0) {
                    q.trunc() as usize
                } else {
                    q.round() as usize
                };

            println!("{}", wds[index].format("%a %Y-%m-%d").to_string());
        },
        _ => {
            usage();
        },
    }
}

fn days_in_month(year: i32, month: u32) -> u32 {
    let (y, m) = if month == 12 {
        (year + 1, 1)
    } else {
        (year, month + 1)
    };
    let d = NaiveDate::from_ymd(y, m, 1);
    d.pred().day()
}
<|endoftext|>


<commit_before>//! This modules contains an implementation of [r2d2](https://github.com/sfackler/r2d2)
//! functionality of connection pools. To get more details about creating r2d2 pools
//! please refer to original documentation.
use std::iter::Iterator;
use query::QueryBuilder;
use client::{CDRS, Session};
use error::{Error as CError, Result as CResult};
use authenticators::Authenticator;
use compression::Compression;
use r2d2;
use transport::CDRSTransport;
use rand;
use std::sync::atomic::{AtomicUsize, Ordering};

/// Load balancing strategy
#[derive(PartialEq)]
pub enum LoadBalancingStrategy {
    /// Round Robin balancing strategy
    RoundRobin,
    /// Random balancing strategy
    Random,
}

impl LoadBalancingStrategy {
    /// Returns next value for selected load balancing strategy
    pub fn next<'a, N>(&'a self, nodes: &'a Vec<N>, i: usize) -> Option<&N> {
        match *self {
            LoadBalancingStrategy::Random => nodes.get(self.rnd_idx((0, Some(nodes.len())))),
            LoadBalancingStrategy::RoundRobin => {
                let mut cycle = nodes.iter().cycle().skip(i);
                cycle.next()
            }
        }
    }

    /// Returns random number from a range
    fn rnd_idx(&self, bounds: (usize, Option<usize>)) -> usize {
        let min = bounds.0;
        let max = bounds.1.unwrap_or(u8::max_value() as usize);
        let rnd = rand::random::<usize>();
        rnd % (max - min) + min
    }
}

/// Load balancer
///
/// #Example
///
/// ```no_run
/// use cdrs::cluster::{LoadBalancingStrategy, LoadBalancer};
/// use cdrs::transport::TransportTcp;
/// let transports = vec![TransportTcp::new("127.0.0.1:9042"), TransportTcp::new("127.0.0.1:9042")];
/// let load_balancer = LoadBalancer::new(transports, LoadBalancingStrategy::RoundRobin);
/// let node = load_balancer.next().unwrap();
/// ```
pub struct LoadBalancer<T> {
    strategy: LoadBalancingStrategy,
    nodes: Vec<T>,
    i: AtomicUsize,
}

impl<T> LoadBalancer<T> {
    /// Factory function which creates new `LoadBalancer` with provided strategy.
    pub fn new(nodes: Vec<T>, strategy: LoadBalancingStrategy) -> LoadBalancer<T> {
        LoadBalancer {
            nodes: nodes,
            strategy: strategy,
            i: AtomicUsize::new(0),
        }
    }

    /// Returns next node basing on provided strategy.
    pub fn next(&self) -> Option<&T> {
        let next = self.strategy
            .next(&self.nodes, self.i.load(Ordering::Relaxed) as usize);
        if self.strategy == LoadBalancingStrategy::RoundRobin {
            self.i.fetch_add(1, Ordering::Relaxed);
            // prevent overflow
            let i = self.i.load(Ordering::Relaxed);
            match i.checked_rem(self.nodes.len() as usize) {
                Some(rem) => self.i.store(rem, Ordering::Relaxed),
                None => return None,
            }
        }
        next
    }
}

/// [r2d2](https://github.com/sfackler/r2d2) `ManageConnection`.
pub struct ClusterConnectionManager<T, X> {
    load_balancer: LoadBalancer<X>,
    authenticator: T,
    compression: Compression,
}

impl<T, X> ClusterConnectionManager<T, X>
    where T: Authenticator + Send + Sync + 'static
{
    /// Creates a new instance of `ConnectionManager`.
    /// It requires transport, authenticator and compression as inputs.
    pub fn new(load_balancer: LoadBalancer<X>,
               authenticator: T,
               compression: Compression)
               -> ClusterConnectionManager<T, X> {
        ClusterConnectionManager {
            load_balancer: load_balancer,
            authenticator: authenticator,
            compression: compression,
        }
    }
}

impl<T: Authenticator + Send + Sync + 'static,
     X: CDRSTransport + Send + Sync + 'static> r2d2::ManageConnection
    for ClusterConnectionManager<T, X> {
    type Connection = Session<T, X>;
    type Error = CError;

    fn connect(&self) -> Result<Self::Connection, Self::Error> {
        let transport_res: CResult<X> = self.load_balancer
            .next()
            .ok_or_else(|| "Cannot get next node".into())
            .and_then(|x| x.try_clone().map_err(|e| e.into()));
        let transport = try!(transport_res);
        let compression = self.compression;
        let cdrs = CDRS::new(transport, self.authenticator.clone());

        cdrs.start(compression)
    }

    fn is_valid(&self, connection: &mut Self::Connection) -> Result<(), Self::Error> {
        let query = QueryBuilder::new("SELECT * FROM system.peers;").finalize();

        connection.query(query, false, false).map(|_| ())
    }

    fn has_broken(&self, _connection: &mut Self::Connection) -> bool {
        false
    }
}

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

    #[test]
    fn round_robin() {
        let nodes = vec!["a", "b", "c"];
        let nodes_c = nodes.clone();
        let load_balancer = LoadBalancer::new(nodes, LoadBalancingStrategy::RoundRobin);
        for i in 0..10 {
            assert_eq!(&nodes_c[i % 3], load_balancer.next().unwrap());
        }
    }
}
<commit_msg>added unit test<commit_after>//! This modules contains an implementation of [r2d2](https://github.com/sfackler/r2d2)
//! functionality of connection pools. To get more details about creating r2d2 pools
//! please refer to original documentation.
use std::iter::Iterator;
use query::QueryBuilder;
use client::{CDRS, Session};
use error::{Error as CError, Result as CResult};
use authenticators::Authenticator;
use compression::Compression;
use r2d2;
use transport::CDRSTransport;
use rand;
use std::sync::atomic::{AtomicUsize, Ordering};

/// Load balancing strategy
#[derive(PartialEq)]
pub enum LoadBalancingStrategy {
    /// Round Robin balancing strategy
    RoundRobin,
    /// Random balancing strategy
    Random,
}

impl LoadBalancingStrategy {
    /// Returns next value for selected load balancing strategy
    pub fn next<'a, N>(&'a self, nodes: &'a Vec<N>, i: usize) -> Option<&N> {
        match *self {
            LoadBalancingStrategy::Random => nodes.get(self.rnd_idx((0, Some(nodes.len())))),
            LoadBalancingStrategy::RoundRobin => {
                let mut cycle = nodes.iter().cycle().skip(i);
                cycle.next()
            }
        }
    }

    /// Returns random number from a range
    fn rnd_idx(&self, bounds: (usize, Option<usize>)) -> usize {
        let min = bounds.0;
        let max = bounds.1.unwrap_or(u8::max_value() as usize);
        let rnd = rand::random::<usize>();
        rnd % (max - min) + min
    }
}

/// Load balancer
///
/// #Example
///
/// ```no_run
/// use cdrs::cluster::{LoadBalancingStrategy, LoadBalancer};
/// use cdrs::transport::TransportTcp;
/// let transports = vec![TransportTcp::new("127.0.0.1:9042"), TransportTcp::new("127.0.0.1:9042")];
/// let load_balancer = LoadBalancer::new(transports, LoadBalancingStrategy::RoundRobin);
/// let node = load_balancer.next().unwrap();
/// ```
pub struct LoadBalancer<T> {
    strategy: LoadBalancingStrategy,
    nodes: Vec<T>,
    i: AtomicUsize,
}

impl<T> LoadBalancer<T> {
    /// Factory function which creates new `LoadBalancer` with provided strategy.
    pub fn new(nodes: Vec<T>, strategy: LoadBalancingStrategy) -> LoadBalancer<T> {
        LoadBalancer {
            nodes: nodes,
            strategy: strategy,
            i: AtomicUsize::new(0),
        }
    }

    /// Returns next node basing on provided strategy.
    pub fn next(&self) -> Option<&T> {
        let next = self.strategy
            .next(&self.nodes, self.i.load(Ordering::Relaxed) as usize);
        if self.strategy == LoadBalancingStrategy::RoundRobin {
            self.i.fetch_add(1, Ordering::Relaxed);
            // prevent overflow
            let i = self.i.load(Ordering::Relaxed);
            match i.checked_rem(self.nodes.len() as usize) {
                Some(rem) => self.i.store(rem, Ordering::Relaxed),
                None => return None,
            }
        }
        next
    }
}

/// [r2d2](https://github.com/sfackler/r2d2) `ManageConnection`.
pub struct ClusterConnectionManager<T, X> {
    load_balancer: LoadBalancer<X>,
    authenticator: T,
    compression: Compression,
}

impl<T, X> ClusterConnectionManager<T, X>
    where T: Authenticator + Send + Sync + 'static
{
    /// Creates a new instance of `ConnectionManager`.
    /// It requires transport, authenticator and compression as inputs.
    pub fn new(load_balancer: LoadBalancer<X>,
               authenticator: T,
               compression: Compression)
               -> ClusterConnectionManager<T, X> {
        ClusterConnectionManager {
            load_balancer: load_balancer,
            authenticator: authenticator,
            compression: compression,
        }
    }
}

impl<T: Authenticator + Send + Sync + 'static,
     X: CDRSTransport + Send + Sync + 'static> r2d2::ManageConnection
    for ClusterConnectionManager<T, X> {
    type Connection = Session<T, X>;
    type Error = CError;

    fn connect(&self) -> Result<Self::Connection, Self::Error> {
        let transport_res: CResult<X> = self.load_balancer
            .next()
            .ok_or_else(|| "Cannot get next node".into())
            .and_then(|x| x.try_clone().map_err(|e| e.into()));
        let transport = try!(transport_res);
        let compression = self.compression;
        let cdrs = CDRS::new(transport, self.authenticator.clone());

        cdrs.start(compression)
    }

    fn is_valid(&self, connection: &mut Self::Connection) -> Result<(), Self::Error> {
        let query = QueryBuilder::new("SELECT * FROM system.peers;").finalize();

        connection.query(query, false, false).map(|_| ())
    }

    fn has_broken(&self, _connection: &mut Self::Connection) -> bool {
        false
    }
}

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

    #[test]
    fn round_robin() {
        let nodes = vec!["a", "b", "c"];
        let nodes_c = nodes.clone();
        let load_balancer = LoadBalancer::new(nodes, LoadBalancingStrategy::RoundRobin);
        for i in 0..10 {
            assert_eq!(&nodes_c[i % 3], load_balancer.next().unwrap());
        }
    }

    #[test]
    fn lb_random() {
        let nodes = vec!["a", "b", "c", "d", "e", "f", "g"];
        let nodes_c = nodes.clone();
        let load_balancer = LoadBalancer::new(nodes, LoadBalancingStrategy::Random);
        for _ in 0..100 {
            let s = load_balancer.next();
            assert!(s.is_some());
        }
    }
}
<|endoftext|>