<commit_before>//! rustdoc handler

use super::pool::Pool;
use super::file::File;
use super::{latest_version, redirect_base};
use super::crate_details::CrateDetails;
use iron::prelude::*;
use iron::{status, Url};
use iron::modifiers::Redirect;
use router::Router;
use super::{match_version, MatchVersion};
use super::error::Nope;
use super::page::Page;
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective};
use time;
use iron::Handler;
use utils;

#[derive(Debug)]
struct RustdocPage {
    pub head: String,
    pub body: String,
    pub body_class: String,
    pub name: String,
    pub full: String,
    pub version: String,
    pub description: Option<String>,
    pub crate_details: Option<CrateDetails>,
}

impl Default for RustdocPage {
    fn default() -> RustdocPage {
        RustdocPage {
            head: String::new(),
            body: String::new(),
            body_class: String::new(),
            name: String::new(),
            full: String::new(),
            version: String::new(),
            description: None,
            crate_details: None,
        }
    }
}

impl ToJson for RustdocPage {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("rustdoc_head".to_string(), self.head.to_json());
        m.insert("rustdoc_body".to_string(), self.body.to_json());
        m.insert("rustdoc_body_class".to_string(), self.body_class.to_json());
        m.insert("rustdoc_full".to_string(), self.full.to_json());
        m.insert("rustdoc_status".to_string(), true.to_json());
        m.insert("name".to_string(), self.name.to_json());
        m.insert("version".to_string(), self.version.to_json());
        m.insert("description".to_string(), self.description.to_json());
        m.insert("crate_details".to_string(), self.crate_details.to_json());
        m.to_json()
    }
}

pub struct RustLangRedirector {
    target: &'static str,
}

impl RustLangRedirector {
    pub fn new(target: &'static str) -> Self {
        Self { target }
    }
}

impl iron::Handler for RustLangRedirector {
    fn handle(&self, _req: &mut Request) -> IronResult<Response> {
        let url = url::Url::parse("https://doc.rust-lang.org/stable/")
            .expect("failed to parse rust-lang.org base URL")
            .join(self.target)
            .expect("failed to append crate name to rust-lang.org base URL");
        let url = Url::from_generic_url(url)
            .expect("failed to convert url::Url to iron::Url");
        Ok(Response::with((status::Found, Redirect(url))))
    }
}

/// Handler called for `/:crate` and `/:crate/:version` URLs. Automatically redirects to the docs
/// or crate details page based on whether the given crate version was successfully built.
pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult<Response> {

    fn redirect_to_doc(req: &Request,
                       name: &str,
                       vers: &str,
                       target_name: &str)
                       -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/{}/{}/{}/",
                                            redirect_base(req),
                                            name,
                                            vers,
                                            target_name)[..]));
        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    fn redirect_to_crate(req: &Request,
                         name: &str,
                         vers: &str)
                         -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/crate/{}/{}",
                                            redirect_base(req),
                                            name,
                                            vers)[..]));

        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    // this unwrap is safe because iron urls are always able to use `path_segments`
    // i'm using this instead of `req.url.path()` to avoid allocating the Vec, and also to avoid
    // keeping the borrow alive into the return statement
    if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".js")) {
        // javascript files should be handled by the file server instead of erroneously
        // redirecting to the crate root page
        if req.url.as_ref().path_segments().unwrap().count() > 2 {
            // this URL is actually from a crate-internal path, serve it there instead
            return rustdoc_html_server_handler(req);
        } else {
            let path = req.url.path();
            let path = path.join("/");
            let conn = extension!(req, Pool);
            match File::from_path(&conn, &path) {
                Some(f) => return Ok(f.serve()),
                None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
            }
        }
    } else if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".ico")) {
        // route .ico files into their dedicated handler so that docs.rs's favicon is always
        // displayed
        return super::ico_handler(req);
    }

    let router = extension!(req, Router);
    // this handler should never called without crate pattern
    let crate_name = cexpect!(router.find("crate"));
    let req_version = router.find("version");

    let conn = extension!(req, Pool);

    // it doesn't matter if the version that was given was exact or not, since we're redirecting
    // anyway
    let version = match match_version(&conn, &crate_name, req_version).into_option() {
        Some(v) => v,
        None => return Err(IronError::new(Nope::CrateNotFound, status::NotFound)),
    };

    // get target name and whether it has docs
    // FIXME: This is a bit inefficient but allowing us to use less code in general
    let (target_name, has_docs): (String, bool) = {
        let rows = ctry!(conn.query("SELECT target_name, rustdoc_status
                                     FROM releases
                                     INNER JOIN crates ON crates.id = releases.crate_id
                                     WHERE crates.name = $1 AND releases.version = $2",
                                    &[&crate_name, &version]));

        (rows.get(0).get(0), rows.get(0).get(1))
    };

    if has_docs {
        redirect_to_doc(req, &crate_name, &version, &target_name)
    } else {
        redirect_to_crate(req, &crate_name, &version)
    }
}

/// Serves documentation generated by rustdoc.
///
/// This includes all HTML files for an individual crate, as well as the `search-index.js`, which is
/// also crate-specific.
pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {

    let router = extension!(req, Router);
    let name = router.find("crate").unwrap_or("").to_string();
    let url_version = router.find("version");
    let version; // pre-declaring it to enforce drop order relative to `req_path`
    let conn = extension!(req, Pool);

    let mut req_path = req.url.path();

    // remove name and version from path
    for _ in 0..2 {
        req_path.remove(0);
    }

    version = match match_version(&conn, &name, url_version) {
        MatchVersion::Exact(v) => v,
        MatchVersion::Semver(v) => {
            // to prevent cloudfront caching the wrong artifacts on URLs with loose semver
            // versions, redirect the browser to the returned version instead of loading it
            // immediately
            let url = ctry!(Url::parse(&format!("{}/{}/{}/{}",
                                                redirect_base(req),
                                                name,
                                                v,
                                                req_path.join("/"))[..]));
            return Ok(super::redirect(url));
        }
        MatchVersion::None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // docs have "rustdoc" prefix in database
    req_path.insert(0, "rustdoc");

    // add crate name and version
    req_path.insert(1, &name);
    req_path.insert(2, &version);

    let path = {
        let mut path = req_path.join("/");
        if path.ends_with("/") {
            path.push_str("index.html");
            req_path.push("index.html");
        }
        path
    };

    let file = match File::from_path(&conn, &path) {
        Some(f) => f,
        None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // serve file directly if it's not html
    if !path.ends_with(".html") {
        return Ok(file.serve());
    }

    let mut content = RustdocPage::default();

    let file_content = ctry!(String::from_utf8(file.0.content));

    let (head, body, mut body_class) = ctry!(utils::extract_head_and_body(&file_content));
    content.head = head;
    content.body = body;

    if body_class.is_empty() {
        body_class = "rustdoc container-rustdoc".to_string();
    } else {
        // rustdoc adds its own "rustdoc" class to the body
        body_class.push_str(" container-rustdoc");
    }
    content.body_class = body_class;

    content.full = file_content;
    let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version));
    let latest_version = latest_version(&crate_details.versions, &version);

    content.crate_details = Some(crate_details);

    Page::new(content)
        .set_true("show_package_navigation")
        .set_true("package_navigation_documentation_tab")
        .set_true("package_navigation_show_platforms_tab")
        .set_bool("is_latest_version", latest_version.is_none())
        .set("latest_version", &latest_version.unwrap_or(String::new()))
        .to_resp("rustdoc")
}

pub fn badge_handler(req: &mut Request) -> IronResult<Response> {
    use iron::headers::ContentType;
    use params::{Params, Value};
    use badge::{Badge, BadgeOptions};

    let version = {
        let params = ctry!(req.get_ref::<Params>());
        match params.find(&["version"]) {
            Some(&Value::String(ref version)) => version.clone(),
            _ => "*".to_owned(),
        }
    };

    let name = cexpect!(extension!(req, Router).find("crate"));
    let conn = extension!(req, Pool);

    let options = match match_version(&conn, &name, Some(&version)) {
        MatchVersion::Exact(version) => {
            let rows = ctry!(conn.query("SELECT rustdoc_status
                                         FROM releases
                                         INNER JOIN crates ON crates.id = releases.crate_id
                                         WHERE crates.name = $1 AND releases.version = $2",
                                        &[&name, &version]));
            if rows.len() > 0 && rows.get(0).get(0) {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#4d76ae".to_owned(),
                }
            } else {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#e05d44".to_owned(),
                }
            }
        }
        MatchVersion::Semver(version) => {
            let url = ctry!(Url::parse(&format!("{}/{}/badge.svg?version={}",
                                                redirect_base(req),
                                                name,
                                                version)[..]));

            return Ok(super::redirect(url));
        }
        MatchVersion::None => {
            BadgeOptions {
                subject: "docs".to_owned(),
                status: "no builds".to_owned(),
                color: "#e05d44".to_owned(),
            }
        }
    };

    let mut resp = Response::with((status::Ok, ctry!(Badge::new(options)).to_svg()));
    resp.headers.set(ContentType("image/svg+xml".parse().unwrap()));
    resp.headers.set(Expires(HttpDate(time::now())));
    resp.headers.set(CacheControl(vec![CacheDirective::NoCache,
                                       CacheDirective::NoStore,
                                       CacheDirective::MustRevalidate]));
    Ok(resp)
}

/// Serves shared web resources used by rustdoc-generated documentation.
///
/// This includes common `css` and `js` files that only change when the compiler is updated, but are
/// otherwise the same for all crates documented with that compiler. Those have a custom handler to
/// deduplicate them and save space.
pub struct SharedResourceHandler;

impl Handler for SharedResourceHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path();
        let filename = path.last().unwrap();  // unwrap is fine: vector is non-empty
        let suffix = filename.split('.').last().unwrap();  // unwrap is fine: split always works
        if ["js", "css", "woff", "svg"].contains(&suffix) {
            let conn = extension!(req, Pool);

            if let Some(file) = File::from_path(conn, filename) {
                return Ok(file.serve());
            }
        }

        // Just always return a 404 here - the main handler will then try the other handlers
        Err(IronError::new(Nope::ResourceNotFound, status::NotFound))
    }
}
<commit_msg>Parse URL for rustlang.org redirector once.<commit_after>//! rustdoc handler

use super::pool::Pool;
use super::file::File;
use super::{latest_version, redirect_base};
use super::crate_details::CrateDetails;
use iron::prelude::*;
use iron::{status, Url};
use iron::modifiers::Redirect;
use router::Router;
use super::{match_version, MatchVersion};
use super::error::Nope;
use super::page::Page;
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective};
use time;
use iron::Handler;
use utils;

#[derive(Debug)]
struct RustdocPage {
    pub head: String,
    pub body: String,
    pub body_class: String,
    pub name: String,
    pub full: String,
    pub version: String,
    pub description: Option<String>,
    pub crate_details: Option<CrateDetails>,
}

impl Default for RustdocPage {
    fn default() -> RustdocPage {
        RustdocPage {
            head: String::new(),
            body: String::new(),
            body_class: String::new(),
            name: String::new(),
            full: String::new(),
            version: String::new(),
            description: None,
            crate_details: None,
        }
    }
}

impl ToJson for RustdocPage {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("rustdoc_head".to_string(), self.head.to_json());
        m.insert("rustdoc_body".to_string(), self.body.to_json());
        m.insert("rustdoc_body_class".to_string(), self.body_class.to_json());
        m.insert("rustdoc_full".to_string(), self.full.to_json());
        m.insert("rustdoc_status".to_string(), true.to_json());
        m.insert("name".to_string(), self.name.to_json());
        m.insert("version".to_string(), self.version.to_json());
        m.insert("description".to_string(), self.description.to_json());
        m.insert("crate_details".to_string(), self.crate_details.to_json());
        m.to_json()
    }
}

pub struct RustLangRedirector {
    url: Url,
}

impl RustLangRedirector {
    pub fn new(target: &'static str) -> Self {
        let url = url::Url::parse("https://doc.rust-lang.org/stable/")
            .expect("failed to parse rust-lang.org base URL")
            .join(target)
            .expect("failed to append crate name to rust-lang.org base URL");
        let url = Url::from_generic_url(url)
            .expect("failed to convert url::Url to iron::Url");
        Self { url }
    }
}

impl iron::Handler for RustLangRedirector {
    fn handle(&self, _req: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Found, Redirect(self.url.clone()))))
    }
}

/// Handler called for `/:crate` and `/:crate/:version` URLs. Automatically redirects to the docs
/// or crate details page based on whether the given crate version was successfully built.
pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult<Response> {

    fn redirect_to_doc(req: &Request,
                       name: &str,
                       vers: &str,
                       target_name: &str)
                       -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/{}/{}/{}/",
                                            redirect_base(req),
                                            name,
                                            vers,
                                            target_name)[..]));
        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    fn redirect_to_crate(req: &Request,
                         name: &str,
                         vers: &str)
                         -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/crate/{}/{}",
                                            redirect_base(req),
                                            name,
                                            vers)[..]));

        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    // this unwrap is safe because iron urls are always able to use `path_segments`
    // i'm using this instead of `req.url.path()` to avoid allocating the Vec, and also to avoid
    // keeping the borrow alive into the return statement
    if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".js")) {
        // javascript files should be handled by the file server instead of erroneously
        // redirecting to the crate root page
        if req.url.as_ref().path_segments().unwrap().count() > 2 {
            // this URL is actually from a crate-internal path, serve it there instead
            return rustdoc_html_server_handler(req);
        } else {
            let path = req.url.path();
            let path = path.join("/");
            let conn = extension!(req, Pool);
            match File::from_path(&conn, &path) {
                Some(f) => return Ok(f.serve()),
                None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
            }
        }
    } else if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".ico")) {
        // route .ico files into their dedicated handler so that docs.rs's favicon is always
        // displayed
        return super::ico_handler(req);
    }

    let router = extension!(req, Router);
    // this handler should never called without crate pattern
    let crate_name = cexpect!(router.find("crate"));
    let req_version = router.find("version");

    let conn = extension!(req, Pool);

    // it doesn't matter if the version that was given was exact or not, since we're redirecting
    // anyway
    let version = match match_version(&conn, &crate_name, req_version).into_option() {
        Some(v) => v,
        None => return Err(IronError::new(Nope::CrateNotFound, status::NotFound)),
    };

    // get target name and whether it has docs
    // FIXME: This is a bit inefficient but allowing us to use less code in general
    let (target_name, has_docs): (String, bool) = {
        let rows = ctry!(conn.query("SELECT target_name, rustdoc_status
                                     FROM releases
                                     INNER JOIN crates ON crates.id = releases.crate_id
                                     WHERE crates.name = $1 AND releases.version = $2",
                                    &[&crate_name, &version]));

        (rows.get(0).get(0), rows.get(0).get(1))
    };

    if has_docs {
        redirect_to_doc(req, &crate_name, &version, &target_name)
    } else {
        redirect_to_crate(req, &crate_name, &version)
    }
}

/// Serves documentation generated by rustdoc.
///
/// This includes all HTML files for an individual crate, as well as the `search-index.js`, which is
/// also crate-specific.
pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {

    let router = extension!(req, Router);
    let name = router.find("crate").unwrap_or("").to_string();
    let url_version = router.find("version");
    let version; // pre-declaring it to enforce drop order relative to `req_path`
    let conn = extension!(req, Pool);

    let mut req_path = req.url.path();

    // remove name and version from path
    for _ in 0..2 {
        req_path.remove(0);
    }

    version = match match_version(&conn, &name, url_version) {
        MatchVersion::Exact(v) => v,
        MatchVersion::Semver(v) => {
            // to prevent cloudfront caching the wrong artifacts on URLs with loose semver
            // versions, redirect the browser to the returned version instead of loading it
            // immediately
            let url = ctry!(Url::parse(&format!("{}/{}/{}/{}",
                                                redirect_base(req),
                                                name,
                                                v,
                                                req_path.join("/"))[..]));
            return Ok(super::redirect(url));
        }
        MatchVersion::None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // docs have "rustdoc" prefix in database
    req_path.insert(0, "rustdoc");

    // add crate name and version
    req_path.insert(1, &name);
    req_path.insert(2, &version);

    let path = {
        let mut path = req_path.join("/");
        if path.ends_with("/") {
            path.push_str("index.html");
            req_path.push("index.html");
        }
        path
    };

    let file = match File::from_path(&conn, &path) {
        Some(f) => f,
        None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // serve file directly if it's not html
    if !path.ends_with(".html") {
        return Ok(file.serve());
    }

    let mut content = RustdocPage::default();

    let file_content = ctry!(String::from_utf8(file.0.content));

    let (head, body, mut body_class) = ctry!(utils::extract_head_and_body(&file_content));
    content.head = head;
    content.body = body;

    if body_class.is_empty() {
        body_class = "rustdoc container-rustdoc".to_string();
    } else {
        // rustdoc adds its own "rustdoc" class to the body
        body_class.push_str(" container-rustdoc");
    }
    content.body_class = body_class;

    content.full = file_content;
    let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version));
    let latest_version = latest_version(&crate_details.versions, &version);

    content.crate_details = Some(crate_details);

    Page::new(content)
        .set_true("show_package_navigation")
        .set_true("package_navigation_documentation_tab")
        .set_true("package_navigation_show_platforms_tab")
        .set_bool("is_latest_version", latest_version.is_none())
        .set("latest_version", &latest_version.unwrap_or(String::new()))
        .to_resp("rustdoc")
}

pub fn badge_handler(req: &mut Request) -> IronResult<Response> {
    use iron::headers::ContentType;
    use params::{Params, Value};
    use badge::{Badge, BadgeOptions};

    let version = {
        let params = ctry!(req.get_ref::<Params>());
        match params.find(&["version"]) {
            Some(&Value::String(ref version)) => version.clone(),
            _ => "*".to_owned(),
        }
    };

    let name = cexpect!(extension!(req, Router).find("crate"));
    let conn = extension!(req, Pool);

    let options = match match_version(&conn, &name, Some(&version)) {
        MatchVersion::Exact(version) => {
            let rows = ctry!(conn.query("SELECT rustdoc_status
                                         FROM releases
                                         INNER JOIN crates ON crates.id = releases.crate_id
                                         WHERE crates.name = $1 AND releases.version = $2",
                                        &[&name, &version]));
            if rows.len() > 0 && rows.get(0).get(0) {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#4d76ae".to_owned(),
                }
            } else {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#e05d44".to_owned(),
                }
            }
        }
        MatchVersion::Semver(version) => {
            let url = ctry!(Url::parse(&format!("{}/{}/badge.svg?version={}",
                                                redirect_base(req),
                                                name,
                                                version)[..]));

            return Ok(super::redirect(url));
        }
        MatchVersion::None => {
            BadgeOptions {
                subject: "docs".to_owned(),
                status: "no builds".to_owned(),
                color: "#e05d44".to_owned(),
            }
        }
    };

    let mut resp = Response::with((status::Ok, ctry!(Badge::new(options)).to_svg()));
    resp.headers.set(ContentType("image/svg+xml".parse().unwrap()));
    resp.headers.set(Expires(HttpDate(time::now())));
    resp.headers.set(CacheControl(vec![CacheDirective::NoCache,
                                       CacheDirective::NoStore,
                                       CacheDirective::MustRevalidate]));
    Ok(resp)
}

/// Serves shared web resources used by rustdoc-generated documentation.
///
/// This includes common `css` and `js` files that only change when the compiler is updated, but are
/// otherwise the same for all crates documented with that compiler. Those have a custom handler to
/// deduplicate them and save space.
pub struct SharedResourceHandler;

impl Handler for SharedResourceHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path();
        let filename = path.last().unwrap();  // unwrap is fine: vector is non-empty
        let suffix = filename.split('.').last().unwrap();  // unwrap is fine: split always works
        if ["js", "css", "woff", "svg"].contains(&suffix) {
            let conn = extension!(req, Pool);

            if let Some(file) = File::from_path(conn, filename) {
                return Ok(file.serve());
            }
        }

        // Just always return a 404 here - the main handler will then try the other handlers
        Err(IronError::new(Nope::ResourceNotFound, status::NotFound))
    }
}
<|endoftext|>


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

//! Common storage-related types
use memmap;

use std::cmp;
use std::fs::{self, File, OpenOptions};
use std::io::{self, BufRead, BufReader, BufWriter, ErrorKind, Read, Write};
use std::path::Path;

use core::core::hash::Hash;
use core::ser::{self, FixedLength};

/// A no-op function for doing nothing with some pruned data.
pub fn prune_noop(_pruned_data: &[u8]) {}

/// Hash file (MMR) wrapper around an append only file.
pub struct HashFile {
	file: AppendOnlyFile,
}

impl HashFile {
	/// Open (or create) a hash file at the provided path on disk.
	pub fn open(path: &str) -> io::Result<HashFile> {
		let file = AppendOnlyFile::open(path)?;
		Ok(HashFile { file })
	}

	/// Append a hash to this hash file.
	/// Will not be written to disk until flush() is subsequently called.
	/// Alternatively discard() may be called to discard any pending changes.
	pub fn append(&mut self, hash: &Hash) -> io::Result<()> {
		let mut bytes = ser::ser_vec(hash).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
		self.file.append(&mut bytes);
		Ok(())
	}

	/// Read a hash from the hash file by position.
	pub fn read(&self, position: u64) -> Option<Hash> {
		// The MMR starts at 1, our binary backend starts at 0.
		let pos = position - 1;

		// Must be on disk, doing a read at the correct position
		let file_offset = (pos as usize) * Hash::LEN;
		let data = self.file.read(file_offset, Hash::LEN);
		match ser::deserialize(&mut &data[..]) {
			Ok(h) => Some(h),
			Err(e) => {
				error!(
					"Corrupted storage, could not read an entry from hash file: {:?}",
					e
				);
				None
			}
		}
	}

	/// Rewind the backend file to the specified position.
	pub fn rewind(&mut self, position: u64) -> io::Result<()> {
		self.file.rewind(position * Hash::LEN as u64);
		Ok(())
	}

	/// Flush unsynced changes to the hash file to disk.
	pub fn flush(&mut self) -> io::Result<()> {
		self.file.flush()
	}

	/// Discard any unsynced changes to the hash file.
	pub fn discard(&mut self) {
		self.file.discard()
	}

	/// Size of the hash file in number of hashes (not bytes).
	pub fn size(&self) -> u64 {
		self.file.size() / Hash::LEN as u64
	}

	/// Size of the unsync'd hash file, in hashes (not bytes).
	pub fn size_unsync(&self) -> u64 {
		self.file.size_unsync() / Hash::LEN as u64
	}

	/// Rewrite the hash file out to disk, pruning removed hashes.
	pub fn save_prune<T>(&self, target: String, prune_offs: &[u64], prune_cb: T) -> io::Result<()>
	where
		T: Fn(&[u8]),
	{
		let prune_offs = prune_offs
			.iter()
			.map(|x| x * Hash::LEN as u64)
			.collect::<Vec<_>>();
		self.file
			.save_prune(target, prune_offs.as_slice(), Hash::LEN as u64, prune_cb)
	}
}

/// Wrapper for a file that can be read at any position (random read) but for
/// which writes are append only. Reads are backed by a memory map (mmap(2)),
/// relying on the operating system for fast access and caching. The memory
/// map is reallocated to expand it when new writes are flushed.
///
/// Despite being append-only, the file can still be pruned and truncated. The
/// former simply happens by rewriting it, ignoring some of the data. The
/// latter by truncating the underlying file and re-creating the mmap.
pub struct AppendOnlyFile {
	path: String,
	file: File,
	mmap: Option<memmap::Mmap>,
	buffer_start: usize,
	buffer: Vec<u8>,
	buffer_start_bak: usize,
}

impl AppendOnlyFile {
	/// Open a file (existing or not) as append-only, backed by a mmap.
	pub fn open(path: &str) -> io::Result<AppendOnlyFile> {
		let file = OpenOptions::new()
			.read(true)
			.append(true)
			.create(true)
			.open(&path)?;
		let mut aof = AppendOnlyFile {
			file,
			path: path.to_string(),
			mmap: None,
			buffer_start: 0,
			buffer: vec![],
			buffer_start_bak: 0,
		};
		// If we have a non-empty file then mmap it.
		let sz = aof.size();
		if sz > 0 {
			aof.buffer_start = sz as usize;
			aof.mmap = Some(unsafe { memmap::Mmap::map(&aof.file)? });
		}
		Ok(aof)
	}

	/// Append data to the file. Until the append-only file is synced, data is
	/// only written to memory.
	pub fn append(&mut self, buf: &mut Vec<u8>) {
		self.buffer.append(buf);
	}

	/// Rewinds the data file back to a lower position. The new position needs
	/// to be the one of the first byte the next time data is appended.
	/// Supports two scenarios currently -
	///   * rewind from a clean state (rewinding to handle a forked block)
	///   * rewind within the buffer itself (raw_tx fails to validate)
	/// Note: we do not currently support a rewind() that
	/// crosses the buffer boundary.
	pub fn rewind(&mut self, file_pos: u64) {
		if self.buffer.is_empty() {
			// rewinding from clean state, no buffer, not already rewound anything
			if self.buffer_start_bak == 0 {
				self.buffer_start_bak = self.buffer_start;
			}
			self.buffer_start = file_pos as usize;
		} else {
			// rewinding (within) the buffer
			if self.buffer_start as u64 > file_pos {
				panic!("cannot rewind buffer beyond buffer_start");
			} else {
				let buffer_len = file_pos - self.buffer_start as u64;
				self.buffer.truncate(buffer_len as usize);
			}
		}
	}

	/// Syncs all writes (fsync), reallocating the memory map to make the newly
	/// written data accessible.
	pub fn flush(&mut self) -> io::Result<()> {
		if self.buffer_start_bak > 0 {
			// Flushing a rewound state, we need to truncate via set_len() before applying.
			self.file.set_len(self.buffer_start as u64)?;
			self.buffer_start_bak = 0;
		}

		self.buffer_start += self.buffer.len();
		self.file.write_all(&self.buffer[..])?;
		self.file.sync_all()?;

		self.buffer = vec![];

		// Note: file must be non-empty to memory map it
		if self.file.metadata()?.len() == 0 {
			self.mmap = None;
		} else {
			self.mmap = Some(unsafe { memmap::Mmap::map(&self.file)? });
		}

		Ok(())
	}

	/// Returns the last position (in bytes), taking into account whether data
	/// has been rewound
	pub fn last_buffer_pos(&self) -> usize {
		self.buffer_start
	}

	/// Discard the current non-flushed data.
	pub fn discard(&mut self) {
		if self.buffer_start_bak > 0 {
			// discarding a rewound state, restore the buffer start
			self.buffer_start = self.buffer_start_bak;
			self.buffer_start_bak = 0;
		}
		self.buffer = vec![];
	}

	/// Read length bytes of data at offset from the file.
	/// Leverages the memory map.
	pub fn read(&self, offset: usize, length: usize) -> Vec<u8> {
		if offset >= self.buffer_start {
			let buffer_offset = offset - self.buffer_start;
			return self.read_from_buffer(buffer_offset, length);
		}
		if self.mmap.is_none() {
			return vec![];
		}
		let mmap = self.mmap.as_ref().unwrap();

		if mmap.len() < (offset + length) {
			return vec![];
		}

		(&mmap[offset..(offset + length)]).to_vec()
	}

	// Read length bytes from the buffer, from offset.
	// Return empty vec if we do not have enough bytes in the buffer to read a full
	// vec.
	fn read_from_buffer(&self, offset: usize, length: usize) -> Vec<u8> {
		if self.buffer.len() < (offset + length) {
			vec![]
		} else {
			self.buffer[offset..(offset + length)].to_vec()
		}
	}

	// /// Truncates the underlying file to the provided offset
	// pub fn truncate(&self, offs: usize) -> io::Result<()> {
	// 	let fd = self.file.as_raw_fd();
	// 	let res = unsafe { ftruncate64(fd, offs as off64_t) };
	// 	if res == -1 {
	// 		Err(io::Error::last_os_error())
	// 	} else {
	// 		Ok(())
	// 	}
	// }

	/// Saves a copy of the current file content, skipping data at the provided
	/// prune indices. The prune Vec must be ordered.
	pub fn save_prune<T>(
		&self,
		target: String,
		prune_offs: &[u64],
		prune_len: u64,
		prune_cb: T,
	) -> io::Result<()>
	where
		T: Fn(&[u8]),
	{
		if prune_offs.is_empty() {
			fs::copy(&self.path, &target)?;
			Ok(())
		} else {
			let mut reader = File::open(&self.path)?;
			let mut writer = BufWriter::new(File::create(&target)?);

			// align the buffer on prune_len to avoid misalignments
			let mut buf = vec![0; (prune_len * 256) as usize];
			let mut read = 0;
			let mut prune_pos = 0;
			loop {
				// fill our buffer
				let len = match reader.read(&mut buf) {
					Ok(0) => return Ok(()),
					Ok(len) => len,
					Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
					Err(e) => return Err(e),
				} as u64;

				// write the buffer, except if we prune offsets in the current span,
				// in which case we skip
				let mut buf_start = 0;
				while prune_offs[prune_pos] >= read && prune_offs[prune_pos] < read + len {
					let prune_at = (prune_offs[prune_pos] - read) as usize;
					if prune_at != buf_start {
						writer.write_all(&buf[buf_start..prune_at])?;
					} else {
						prune_cb(&buf[buf_start..prune_at]);
					}
					buf_start = prune_at + (prune_len as usize);
					if prune_offs.len() > prune_pos + 1 {
						prune_pos += 1;
					} else {
						break;
					}
				}
				writer.write_all(&buf[buf_start..(len as usize)])?;
				read += len;
			}
		}
	}

	/// Current size of the file in bytes.
	pub fn size(&self) -> u64 {
		fs::metadata(&self.path).map(|md| md.len()).unwrap_or(0)
	}

	/// Current size of the (unsynced) file in bytes.
	pub fn size_unsync(&self) -> u64 {
		(self.buffer_start + self.buffer.len()) as u64
	}

	/// Path of the underlying file
	pub fn path(&self) -> String {
		self.path.clone()
	}
}

/// Read an ordered vector of scalars from a file.
pub fn read_ordered_vec<T>(path: &str, elmt_len: usize) -> io::Result<Vec<T>>
where
	T: ser::Readable + cmp::Ord,
{
	let file_path = Path::new(&path);
	let mut ovec = Vec::with_capacity(1000);
	if file_path.exists() {
		let mut file = BufReader::with_capacity(elmt_len * 1000, File::open(&path)?);
		loop {
			// need a block to end mutable borrow before consume
			let buf_len = {
				let buf = file.fill_buf()?;
				if buf.len() == 0 {
					break;
				}
				let elmts_res: Result<Vec<T>, ser::Error> = ser::deserialize(&mut &buf[..]);
				match elmts_res {
					Ok(elmts) => for elmt in elmts {
						if let Err(idx) = ovec.binary_search(&elmt) {
							ovec.insert(idx, elmt);
						}
					},
					Err(_) => {
						return Err(io::Error::new(
							io::ErrorKind::InvalidData,
							format!("Corrupted storage, could not read file at {}", path),
						));
					}
				}
				buf.len()
			};
			file.consume(buf_len);
		}
	}
	Ok(ovec)
}

/// Writes an ordered vector to a file
pub fn write_vec<T>(path: &str, v: &Vec<T>) -> io::Result<()>
where
	T: ser::Writeable,
{
	let mut file_path = File::create(&path)?;
	ser::serialize(&mut file_path, v).map_err(|_| {
		io::Error::new(
			io::ErrorKind::InvalidInput,
			format!("Failed to serialize data when writing to {}", path),
		)
	})?;
	Ok(())
}
<commit_msg>cleanup<commit_after>// Copyright 2018 The Grin Developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Common storage-related types
use memmap;

use std::cmp;
use std::fs::{self, File, OpenOptions};
use std::io::{self, BufRead, BufReader, BufWriter, ErrorKind, Read, Write};
use std::path::Path;

use core::core::hash::Hash;
use core::ser::{self, FixedLength};

/// A no-op function for doing nothing with some pruned data.
pub fn prune_noop(_pruned_data: &[u8]) {}

/// Hash file (MMR) wrapper around an append only file.
pub struct HashFile {
	file: AppendOnlyFile,
}

impl HashFile {
	/// Open (or create) a hash file at the provided path on disk.
	pub fn open(path: &str) -> io::Result<HashFile> {
		let file = AppendOnlyFile::open(path)?;
		Ok(HashFile { file })
	}

	/// Append a hash to this hash file.
	/// Will not be written to disk until flush() is subsequently called.
	/// Alternatively discard() may be called to discard any pending changes.
	pub fn append(&mut self, hash: &Hash) -> io::Result<()> {
		let mut bytes = ser::ser_vec(hash).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
		self.file.append(&mut bytes);
		Ok(())
	}

	/// Read a hash from the hash file by position.
	pub fn read(&self, position: u64) -> Option<Hash> {
		// The MMR starts at 1, our binary backend starts at 0.
		let pos = position - 1;

		// Must be on disk, doing a read at the correct position
		let file_offset = (pos as usize) * Hash::LEN;
		let data = self.file.read(file_offset, Hash::LEN);
		match ser::deserialize(&mut &data[..]) {
			Ok(h) => Some(h),
			Err(e) => {
				error!(
					"Corrupted storage, could not read an entry from hash file: {:?}",
					e
				);
				None
			}
		}
	}

	/// Rewind the backend file to the specified position.
	pub fn rewind(&mut self, position: u64) -> io::Result<()> {
		self.file.rewind(position * Hash::LEN as u64);
		Ok(())
	}

	/// Flush unsynced changes to the hash file to disk.
	pub fn flush(&mut self) -> io::Result<()> {
		self.file.flush()
	}

	/// Discard any unsynced changes to the hash file.
	pub fn discard(&mut self) {
		self.file.discard()
	}

	/// Size of the hash file in number of hashes (not bytes).
	pub fn size(&self) -> u64 {
		self.file.size() / Hash::LEN as u64
	}

	/// Size of the unsync'd hash file, in hashes (not bytes).
	pub fn size_unsync(&self) -> u64 {
		self.file.size_unsync() / Hash::LEN as u64
	}

	/// Rewrite the hash file out to disk, pruning removed hashes.
	pub fn save_prune<T>(&self, target: String, prune_offs: &[u64], prune_cb: T) -> io::Result<()>
	where
		T: Fn(&[u8]),
	{
		let prune_offs = prune_offs
			.iter()
			.map(|x| x * Hash::LEN as u64)
			.collect::<Vec<_>>();
		self.file
			.save_prune(target, prune_offs.as_slice(), Hash::LEN as u64, prune_cb)
	}
}

/// Wrapper for a file that can be read at any position (random read) but for
/// which writes are append only. Reads are backed by a memory map (mmap(2)),
/// relying on the operating system for fast access and caching. The memory
/// map is reallocated to expand it when new writes are flushed.
///
/// Despite being append-only, the file can still be pruned and truncated. The
/// former simply happens by rewriting it, ignoring some of the data. The
/// latter by truncating the underlying file and re-creating the mmap.
pub struct AppendOnlyFile {
	path: String,
	file: File,
	mmap: Option<memmap::Mmap>,
	buffer_start: usize,
	buffer: Vec<u8>,
	buffer_start_bak: usize,
}

impl AppendOnlyFile {
	/// Open a file (existing or not) as append-only, backed by a mmap.
	pub fn open(path: &str) -> io::Result<AppendOnlyFile> {
		let file = OpenOptions::new()
			.read(true)
			.append(true)
			.create(true)
			.open(&path)?;
		let mut aof = AppendOnlyFile {
			file,
			path: path.to_string(),
			mmap: None,
			buffer_start: 0,
			buffer: vec![],
			buffer_start_bak: 0,
		};
		// If we have a non-empty file then mmap it.
		let sz = aof.size();
		if sz > 0 {
			aof.buffer_start = sz as usize;
			aof.mmap = Some(unsafe { memmap::Mmap::map(&aof.file)? });
		}
		Ok(aof)
	}

	/// Append data to the file. Until the append-only file is synced, data is
	/// only written to memory.
	pub fn append(&mut self, buf: &mut Vec<u8>) {
		self.buffer.append(buf);
	}

	/// Rewinds the data file back to a lower position. The new position needs
	/// to be the one of the first byte the next time data is appended.
	/// Supports two scenarios currently -
	///   * rewind from a clean state (rewinding to handle a forked block)
	///   * rewind within the buffer itself (raw_tx fails to validate)
	/// Note: we do not currently support a rewind() that
	/// crosses the buffer boundary.
	pub fn rewind(&mut self, file_pos: u64) {
		if self.buffer.is_empty() {
			// rewinding from clean state, no buffer, not already rewound anything
			if self.buffer_start_bak == 0 {
				self.buffer_start_bak = self.buffer_start;
			}
			self.buffer_start = file_pos as usize;
		} else {
			// rewinding (within) the buffer
			if self.buffer_start as u64 > file_pos {
				panic!("cannot rewind buffer beyond buffer_start");
			} else {
				let buffer_len = file_pos - self.buffer_start as u64;
				self.buffer.truncate(buffer_len as usize);
			}
		}
	}

	/// Syncs all writes (fsync), reallocating the memory map to make the newly
	/// written data accessible.
	pub fn flush(&mut self) -> io::Result<()> {
		if self.buffer_start_bak > 0 {
			// Flushing a rewound state, we need to truncate via set_len() before applying.
			self.file.set_len(self.buffer_start as u64)?;
			self.buffer_start_bak = 0;
		}

		self.buffer_start += self.buffer.len();
		self.file.write_all(&self.buffer[..])?;
		self.file.sync_all()?;

		self.buffer = vec![];

		// Note: file must be non-empty to memory map it
		if self.file.metadata()?.len() == 0 {
			self.mmap = None;
		} else {
			self.mmap = Some(unsafe { memmap::Mmap::map(&self.file)? });
		}

		Ok(())
	}

	/// Returns the last position (in bytes), taking into account whether data
	/// has been rewound
	pub fn last_buffer_pos(&self) -> usize {
		self.buffer_start
	}

	/// Discard the current non-flushed data.
	pub fn discard(&mut self) {
		if self.buffer_start_bak > 0 {
			// discarding a rewound state, restore the buffer start
			self.buffer_start = self.buffer_start_bak;
			self.buffer_start_bak = 0;
		}
		self.buffer = vec![];
	}

	/// Read length bytes of data at offset from the file.
	/// Leverages the memory map.
	pub fn read(&self, offset: usize, length: usize) -> Vec<u8> {
		if offset >= self.buffer_start {
			let buffer_offset = offset - self.buffer_start;
			return self.read_from_buffer(buffer_offset, length);
		}
		if self.mmap.is_none() {
			return vec![];
		}
		let mmap = self.mmap.as_ref().unwrap();

		if mmap.len() < (offset + length) {
			return vec![];
		}

		(&mmap[offset..(offset + length)]).to_vec()
	}

	// Read length bytes from the buffer, from offset.
	// Return empty vec if we do not have enough bytes in the buffer to read a full
	// vec.
	fn read_from_buffer(&self, offset: usize, length: usize) -> Vec<u8> {
		if self.buffer.len() < (offset + length) {
			vec![]
		} else {
			self.buffer[offset..(offset + length)].to_vec()
		}
	}

	/// Saves a copy of the current file content, skipping data at the provided
	/// prune indices. The prune Vec must be ordered.
	pub fn save_prune<T>(
		&self,
		target: String,
		prune_offs: &[u64],
		prune_len: u64,
		prune_cb: T,
	) -> io::Result<()>
	where
		T: Fn(&[u8]),
	{
		if prune_offs.is_empty() {
			fs::copy(&self.path, &target)?;
			Ok(())
		} else {
			let mut reader = File::open(&self.path)?;
			let mut writer = BufWriter::new(File::create(&target)?);

			// align the buffer on prune_len to avoid misalignments
			let mut buf = vec![0; (prune_len * 256) as usize];
			let mut read = 0;
			let mut prune_pos = 0;
			loop {
				// fill our buffer
				let len = match reader.read(&mut buf) {
					Ok(0) => return Ok(()),
					Ok(len) => len,
					Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
					Err(e) => return Err(e),
				} as u64;

				// write the buffer, except if we prune offsets in the current span,
				// in which case we skip
				let mut buf_start = 0;
				while prune_offs[prune_pos] >= read && prune_offs[prune_pos] < read + len {
					let prune_at = (prune_offs[prune_pos] - read) as usize;
					if prune_at != buf_start {
						writer.write_all(&buf[buf_start..prune_at])?;
					} else {
						prune_cb(&buf[buf_start..prune_at]);
					}
					buf_start = prune_at + (prune_len as usize);
					if prune_offs.len() > prune_pos + 1 {
						prune_pos += 1;
					} else {
						break;
					}
				}
				writer.write_all(&buf[buf_start..(len as usize)])?;
				read += len;
			}
		}
	}

	/// Current size of the file in bytes.
	pub fn size(&self) -> u64 {
		fs::metadata(&self.path).map(|md| md.len()).unwrap_or(0)
	}

	/// Current size of the (unsynced) file in bytes.
	pub fn size_unsync(&self) -> u64 {
		(self.buffer_start + self.buffer.len()) as u64
	}

	/// Path of the underlying file
	pub fn path(&self) -> String {
		self.path.clone()
	}
}

/// Read an ordered vector of scalars from a file.
pub fn read_ordered_vec<T>(path: &str, elmt_len: usize) -> io::Result<Vec<T>>
where
	T: ser::Readable + cmp::Ord,
{
	let file_path = Path::new(&path);
	let mut ovec = Vec::with_capacity(1000);
	if file_path.exists() {
		let mut file = BufReader::with_capacity(elmt_len * 1000, File::open(&path)?);
		loop {
			// need a block to end mutable borrow before consume
			let buf_len = {
				let buf = file.fill_buf()?;
				if buf.len() == 0 {
					break;
				}
				let elmts_res: Result<Vec<T>, ser::Error> = ser::deserialize(&mut &buf[..]);
				match elmts_res {
					Ok(elmts) => for elmt in elmts {
						if let Err(idx) = ovec.binary_search(&elmt) {
							ovec.insert(idx, elmt);
						}
					},
					Err(_) => {
						return Err(io::Error::new(
							io::ErrorKind::InvalidData,
							format!("Corrupted storage, could not read file at {}", path),
						));
					}
				}
				buf.len()
			};
			file.consume(buf_len);
		}
	}
	Ok(ovec)
}

/// Writes an ordered vector to a file
pub fn write_vec<T>(path: &str, v: &Vec<T>) -> io::Result<()>
where
	T: ser::Writeable,
{
	let mut file_path = File::create(&path)?;
	ser::serialize(&mut file_path, v).map_err(|_| {
		io::Error::new(
			io::ErrorKind::InvalidInput,
			format!("Failed to serialize data when writing to {}", path),
		)
	})?;
	Ok(())
}
<|endoftext|>


<commit_before>use bot::BotEnv;
use filters::Filter;

use lalafell::commands::prelude::*;
use lalafell::error::*;

use serenity::prelude::Mentionable;
use serenity::model::guild::Role;
use serenity::builder::CreateEmbed;

const USAGE: &'static str = "!search <filters>";

pub struct SearchCommand;

impl SearchCommand {
  pub fn new(_: Arc<BotEnv>) -> Self {
    SearchCommand
  }
}

#[derive(Debug, Deserialize)]
pub struct Params {
  filter_strings: Vec<String>
}

impl HasParams for SearchCommand {
  type Params = Params;
}

impl<'a> PublicChannelCommand<'a> for SearchCommand {
  fn run(&self, _: &Context, message: &Message, guild: GuildId, _: Arc<RwLock<GuildChannel>>, params: &[&str]) -> CommandResult<'a> {
    let params = self.params(USAGE, params)?;

    let member = guild.member(&message.author).chain_err(|| "could not get member")?;
    if !member.permissions().chain_err(|| "could not get permissions")?.manage_roles() {
      return Err(ExternalCommandFailure::default()
        .message(|e: CreateEmbed| e
          .title("Not enough permissions.")
          .description("You don't have enough permissions to use this command."))
        .wrap());
    }

    let filters: Vec<Filter> = match params.filter_strings.iter().map(|x| Filter::parse(x)).collect::<Option<_>>() {
      Some(f) => f,
      None => return Err("Invalid filter.".into())
    };
    let guild = some_or!(guild.find(), bail!("could not find guild"));
    let roles: Vec<Role> = guild.read().roles.values().cloned().collect();
    let matches: Vec<String> = guild.read().members.values()
      .filter(|m| filters.iter().all(|f| f.matches(m, &roles)))
      .map(|m| format!("{} - {}",
        m.mention(),
        m.joined_at
          .map(|d| d.format("%B %e, %Y %H:%M").to_string())
          .unwrap_or_else(|| String::from("unknown"))))
      .collect();
    Ok(matches.join("\n").into())
  }
}
<commit_msg>feat: show time since<commit_after>use bot::BotEnv;
use filters::Filter;

use lalafell::commands::prelude::*;
use lalafell::error::*;

use serenity::prelude::Mentionable;
use serenity::model::guild::Role;
use serenity::builder::CreateEmbed;

use chrono::Utc;

const USAGE: &'static str = "!search <filters>";

pub struct SearchCommand;

impl SearchCommand {
  pub fn new(_: Arc<BotEnv>) -> Self {
    SearchCommand
  }
}

#[derive(Debug, Deserialize)]
pub struct Params {
  filter_strings: Vec<String>
}

impl HasParams for SearchCommand {
  type Params = Params;
}

impl<'a> PublicChannelCommand<'a> for SearchCommand {
  fn run(&self, _: &Context, message: &Message, guild: GuildId, _: Arc<RwLock<GuildChannel>>, params: &[&str]) -> CommandResult<'a> {
    let params = self.params(USAGE, params)?;

    let member = guild.member(&message.author).chain_err(|| "could not get member")?;
    if !member.permissions().chain_err(|| "could not get permissions")?.manage_roles() {
      return Err(ExternalCommandFailure::default()
        .message(|e: CreateEmbed| e
          .title("Not enough permissions.")
          .description("You don't have enough permissions to use this command."))
        .wrap());
    }

    let filters: Vec<Filter> = match params.filter_strings.iter().map(|x| Filter::parse(x)).collect::<Option<_>>() {
      Some(f) => f,
      None => return Err("Invalid filter.".into())
    };
    let guild = some_or!(guild.find(), bail!("could not find guild"));
    let roles: Vec<Role> = guild.read().roles.values().cloned().collect();
    let now = Utc::now();
    let matches: Vec<String> = guild.read().members.values()
      .filter(|m| filters.iter().all(|f| f.matches(m, &roles)))
      .map(|m| format!("{} - {}",
        m.mention(),
        m.joined_at
          .map(|d| now.clone().signed_duration_since(d))
          .map(|d| {
            let mut res = String::new();
            let seconds = d.num_seconds() % 60;
            let minutes = d.num_minutes() % 60;
            let hours = d.num_hours() % 24;
            let days = d.num_days();
            if days > 0 {
              res.push_str(&format!("{} day{}, ", days, if days == 1 { "" } else { "s" }));
            }
            if hours > 0 {
              res.push_str(&format!("{} hour{}, ", hours, if hours == 1 { "" } else { "s" }));
            }
            if minutes > 0 {
              res.push_str(&format!("{} minute{}, ", minutes, if minutes == 1 { "" } else { "s" }));
            }
            if seconds > 0 {
              res.push_str(&format!("{} second{}", seconds, if seconds == 1 { "" } else { "s" }));
            }
            res
          })
          .unwrap_or_else(|| String::from("unknown"))))
      .collect();
    Ok(matches.join("\n").into())
  }
}
<|endoftext|>


<commit_before>use {Field, Matrix2d, Rectangle};
use {Transform2d};
use {Borrowed, Value};
use vecmath::{relative_rectangle, margin_rectangle,
translate, multiply, rotate_radians, scale, shear, identity};
use {AddColor};
use {EllipseColorContext};
use {RelativeRectangle, View};

/// An ellipse context.
pub struct EllipseContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle enclosing the ellipse.
    pub rect: Field<'a, Rectangle>,
}

impl<'a> Transform2d<'a> for EllipseContext<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(&trans, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn trans_local(&'a self, x: f64, y: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(self.transform.get(), &trans))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(&rot, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn rot_rad_local(&'a self, angle: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(self.transform.get(), &rot))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(&scale, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn scale_local(&'a self, sx: f64, sy: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(self.transform.get(), &scale))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(&shear, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn shear_local(&'a self, sx: f64, sy: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(self.transform.get(), &shear))
            },
            rect: Borrowed(self.rect.get()),
        }
    }
}

impl<'a> AddColor<'a, EllipseColorContext<'a>> for EllipseContext<'a> {
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> EllipseColorContext<'a> {
        EllipseColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            color: Value([r, g, b, a]),
        }
    }
}

impl<'a> RelativeRectangle<'a> for EllipseContext<'a> {
    #[inline(always)]
    fn margin(&'a self, m: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(margin_rectangle(self.rect.get(), m)),
        }
    }

    #[inline(always)]
    fn rel(&'a self, x: f64, y: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(relative_rectangle(self.rect.get(), x, y)),
        }
    }
}

impl<'a> View<'a> for EllipseContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
        }
    }
}

<commit_msg>Sorted use alphabetically<commit_after>use {
    AddColor,
    Borrowed,
    EllipseColorContext,
    Field,
    Matrix2d,
    Rectangle,
    RelativeRectangle,
    Value,
    View,
    Transform2d,
};
use vecmath::{
    identity,
    margin_rectangle,
    multiply,
    relative_rectangle,
    rotate_radians,
    scale,
    shear,
    translate,
};

/// An ellipse context.
pub struct EllipseContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle enclosing the ellipse.
    pub rect: Field<'a, Rectangle>,
}

impl<'a> Transform2d<'a> for EllipseContext<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(&trans, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn trans_local(&'a self, x: f64, y: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(self.transform.get(), &trans))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(&rot, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn rot_rad_local(&'a self, angle: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(self.transform.get(), &rot))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(&scale, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn scale_local(&'a self, sx: f64, sy: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(self.transform.get(), &scale))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(&shear, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn shear_local(&'a self, sx: f64, sy: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(self.transform.get(), &shear))
            },
            rect: Borrowed(self.rect.get()),
        }
    }
}

impl<'a> AddColor<'a, EllipseColorContext<'a>> for EllipseContext<'a> {
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> EllipseColorContext<'a> {
        EllipseColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            color: Value([r, g, b, a]),
        }
    }
}

impl<'a> RelativeRectangle<'a> for EllipseContext<'a> {
    #[inline(always)]
    fn margin(&'a self, m: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(margin_rectangle(self.rect.get(), m)),
        }
    }

    #[inline(always)]
    fn rel(&'a self, x: f64, y: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(relative_rectangle(self.rect.get(), x, y)),
        }
    }
}

impl<'a> View<'a> for EllipseContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
        }
    }
}

<|endoftext|>


<commit_before>//! Game loop.

// External crates.
use std::mem::replace;
use sync::{Mutex, Arc};

// Local crate.
use GameWindow;
use RenderWindow;

use GameIteratorSettings;
use GameIterator;
use KeyPress;
use KeyPressArgs;
use KeyRelease;
use KeyReleaseArgs;
use MouseMove;
use MouseMoveArgs;
use MouseRelativeMove;
use MouseRelativeMoveArgs;
use MousePress;
use MousePressArgs;
use MouseRelease;
use MouseReleaseArgs;
use MouseScroll;
use MouseScrollArgs;
use Render;
use RenderArgs;
use Update;
use UpdateArgs;

/// Implemented by game applications.
pub trait ConcurrentGame<R>: Copy + Send {
    /// Render graphics.
    fn render(&self, _resources: &mut R, _args: &RenderArgs) {}

    /// Update the physical state of the game.
    fn update(&mut self, _args: &UpdateArgs) {}

    /// Perform tasks for loading before showing anything.
    fn load(&mut self) {}

    /// User pressed a key.
    ///
    /// This can be overridden to handle key pressed events.
    fn key_press(&mut self, _args: &KeyPressArgs) {}

    /// User released a key.
    ///
    /// This can be overridden to handle key released events.
    fn key_release(&mut self, _args: &KeyReleaseArgs) {}

    /// Pressed a mouse button.
    fn mouse_press(&mut self, _args: &MousePressArgs) {}

    /// Released a mouse button.
    fn mouse_release(&mut self, _args: &MouseReleaseArgs) {}

    /// Moved mouse cursor.
    fn mouse_move(&mut self, _args: &MouseMoveArgs) {}

    /// Moved mouse relative, not bounded by cursor.
    fn mouse_relative_move(&mut self, _args: &MouseRelativeMoveArgs) {}

    /// Scrolled mouse.
    fn mouse_scroll(&mut self, _args: &MouseScrollArgs) {}

    /// Executes a game loop.
    fn run<W: GameWindow + Send, RW: RenderWindow> (
        mut self,
        windows: (W, RW),
        game_iter_settings: GameIteratorSettings,
        mut render_resources: R
    ) {
        let (game_window, render_window) = windows;

        // Setup.

        self.load();
        let mutex_self1 = Arc::new( Mutex::new( self ) );
        let mutex_self2 = mutex_self1.clone();
        let (tx, rx) = channel();

        // Game_loop thread.

        spawn(proc() {
            let mut buf2 = self;
            let mut game_window = game_window;

            let mut game_iter = GameIterator::new(
                &mut game_window,
                &game_iter_settings
             );

            loop {
                match game_iter.next() {
                    None => break,
                    Some(e) => match e {
                        Render(args) => {
                            let mut mutex_guard = mutex_self2.lock();
                            {
                                let render_buf = mutex_guard.deref_mut();
                                replace( render_buf, buf2 );
                            }
                            mutex_guard.cond.signal();
                            tx.send(Some(args));
                        },
                        Update(ref args) => buf2.update(args),
                        KeyPress(ref args) => buf2.key_press(args),
                        KeyRelease(ref args) => buf2.key_release(args),
                        MousePress(ref args) => buf2.mouse_press(args),
                        MouseRelease(ref args) => buf2.mouse_release(args),
                        MouseMove(ref args) => buf2.mouse_move(args),
                        MouseRelativeMove(ref args) => buf2.mouse_relative_move(args),
                        MouseScroll(ref args) => buf2.mouse_scroll(args),
                    }
                }
            }
            tx.send(None);
        });

        // Rendering thread.

        loop {
            let mut args: RenderArgs = match rx.recv() {
                Some( args ) => args,
                None => break,
            };

            let mut mutex_guard = mutex_self1.lock();
            {
                let render_buf = mutex_guard.deref_mut();
                render_buf.render( &mut render_resources, &mut args);
                render_window.swap_buffers();
            }
            mutex_guard.cond.signal();
        }
    }
}
<commit_msg>Add render_resources to load method<commit_after>//! Game loop.

// External crates.
use std::mem::replace;
use sync::{Mutex, Arc};

// Local crate.
use GameWindow;
use RenderWindow;

use GameIteratorSettings;
use GameIterator;
use KeyPress;
use KeyPressArgs;
use KeyRelease;
use KeyReleaseArgs;
use MouseMove;
use MouseMoveArgs;
use MouseRelativeMove;
use MouseRelativeMoveArgs;
use MousePress;
use MousePressArgs;
use MouseRelease;
use MouseReleaseArgs;
use MouseScroll;
use MouseScrollArgs;
use Render;
use RenderArgs;
use Update;
use UpdateArgs;

/// Implemented by game applications.
pub trait ConcurrentGame<R>: Copy + Send {
    /// Render graphics.
    fn render(&self, _resources: &mut R, _args: &RenderArgs) {}

    /// Update the physical state of the game.
    fn update(&mut self, _args: &UpdateArgs) {}

    /// Perform tasks for loading before showing anything.
    fn load(&mut self, _resources: &mut R) {}

    /// User pressed a key.
    ///
    /// This can be overridden to handle key pressed events.
    fn key_press(&mut self, _args: &KeyPressArgs) {}

    /// User released a key.
    ///
    /// This can be overridden to handle key released events.
    fn key_release(&mut self, _args: &KeyReleaseArgs) {}

    /// Pressed a mouse button.
    fn mouse_press(&mut self, _args: &MousePressArgs) {}

    /// Released a mouse button.
    fn mouse_release(&mut self, _args: &MouseReleaseArgs) {}

    /// Moved mouse cursor.
    fn mouse_move(&mut self, _args: &MouseMoveArgs) {}

    /// Moved mouse relative, not bounded by cursor.
    fn mouse_relative_move(&mut self, _args: &MouseRelativeMoveArgs) {}

    /// Scrolled mouse.
    fn mouse_scroll(&mut self, _args: &MouseScrollArgs) {}

    /// Executes a game loop.
    fn run<W: GameWindow + Send, RW: RenderWindow> (
        mut self,
        windows: (W, RW),
        game_iter_settings: GameIteratorSettings,
        mut render_resources: R
    ) {
        let (game_window, render_window) = windows;

        // Setup.

        self.load(&mut render_resources);
        let mutex_self1 = Arc::new( Mutex::new( self ) );
        let mutex_self2 = mutex_self1.clone();
        let (tx, rx) = channel();

        // Game_loop thread.

        spawn(proc() {
            let mut buf2 = self;
            let mut game_window = game_window;

            let mut game_iter = GameIterator::new(
                &mut game_window,
                &game_iter_settings
             );

            loop {
                match game_iter.next() {
                    None => break,
                    Some(e) => match e {
                        Render(args) => {
                            let mut mutex_guard = mutex_self2.lock();
                            {
                                let render_buf = mutex_guard.deref_mut();
                                replace( render_buf, buf2 );
                            }
                            mutex_guard.cond.signal();
                            tx.send(Some(args));
                        },
                        Update(ref args) => buf2.update(args),
                        KeyPress(ref args) => buf2.key_press(args),
                        KeyRelease(ref args) => buf2.key_release(args),
                        MousePress(ref args) => buf2.mouse_press(args),
                        MouseRelease(ref args) => buf2.mouse_release(args),
                        MouseMove(ref args) => buf2.mouse_move(args),
                        MouseRelativeMove(ref args) => buf2.mouse_relative_move(args),
                        MouseScroll(ref args) => buf2.mouse_scroll(args),
                    }
                }
            }
            tx.send(None);
        });

        // Rendering thread.

        loop {
            let mut args: RenderArgs = match rx.recv() {
                Some( args ) => args,
                None => break,
            };

            let mut mutex_guard = mutex_self1.lock();
            {
                let render_buf = mutex_guard.deref_mut();
                render_buf.render( &mut render_resources, &mut args);
                render_window.swap_buffers();
            }
            mutex_guard.cond.signal();
        }
    }
}
<|endoftext|>


<commit_before>use packet::InnerStmt;
use std::borrow::Borrow;
use std::collections::{HashMap, VecDeque};
use std::collections::hash_map::IntoIter;
use std::hash::{BuildHasherDefault, Hash};
use twox_hash::XxHash;

#[derive(Debug)]
pub struct StmtCache {
    cap: usize,
    map: HashMap<String, InnerStmt, BuildHasherDefault<XxHash>>,
    order: VecDeque<String>,
}

impl StmtCache {
    pub fn new(cap: usize) -> StmtCache {
        StmtCache {
            cap,
            map: Default::default(),
            order: VecDeque::with_capacity(cap),
        }
    }

    pub fn contains<T>(&self, key: &T) -> bool
        where String: Borrow<T>,
              T: Hash + Eq,
              T: ?Sized
    {
        self.map.contains_key(key)
    }

    pub fn get<T>(&mut self, key: &T) -> Option<&InnerStmt>
        where String: Borrow<T>,
              String: PartialEq<T>,
              T: Hash + Eq,
              T: ?Sized
    {
        if self.map.contains_key(key) {
            if let Some(mut pos) = self.order.iter().position(|x| x == key) {
                while pos < self.order.len() - 1 {
                    self.order.swap(pos, pos + 1);
                    pos += 1;
                }
            }
            self.map.get(key)
        } else {
            None
        }
    }

    pub fn put(&mut self, key: String, value: InnerStmt) -> Option<InnerStmt> {
        self.map.insert(key.clone(), value);
        self.order.push_front(key);
        if self.order.len() > self.cap {
            self.order.pop_back().and_then(|stmt| self.map.remove(&stmt))
        } else {
            None
        }
    }

    pub fn clear(&mut self) {
        self.map.clear();
        self.order.clear();
    }

    pub fn into_iter(self) -> IntoIter<String, InnerStmt> {
        self.map.into_iter()
    }

    pub fn get_cap(&self) -> usize {
        self.cap
    }
}<commit_msg>Fix StmtCache order<commit_after>use packet::InnerStmt;
use std::borrow::Borrow;
use std::collections::{HashMap, VecDeque};
use std::collections::hash_map::IntoIter;
use std::hash::{BuildHasherDefault, Hash};
use twox_hash::XxHash;

#[derive(Debug)]
pub struct StmtCache {
    cap: usize,
    map: HashMap<String, InnerStmt, BuildHasherDefault<XxHash>>,
    order: VecDeque<String>,
}

impl StmtCache {
    pub fn new(cap: usize) -> StmtCache {
        StmtCache {
            cap,
            map: Default::default(),
            order: VecDeque::with_capacity(cap),
        }
    }

    pub fn contains<T>(&self, key: &T) -> bool
        where String: Borrow<T>,
              T: Hash + Eq,
              T: ?Sized
    {
        self.map.contains_key(key)
    }

    pub fn get<T>(&mut self, key: &T) -> Option<&InnerStmt>
        where String: Borrow<T>,
              String: PartialEq<T>,
              T: Hash + Eq,
              T: ?Sized
    {
        if self.map.contains_key(key) {
            if let Some(mut pos) = self.order.iter().position(|x| x == key) {
                while pos < self.order.len() - 1 {
                    self.order.swap(pos, pos + 1);
                    pos += 1;
                }
            }
            self.map.get(key)
        } else {
            None
        }
    }

    pub fn put(&mut self, key: String, value: InnerStmt) -> Option<InnerStmt> {
        self.map.insert(key.clone(), value);
        self.order.push_back(key);
        if self.order.len() > self.cap {
            self.order.pop_front().and_then(|stmt| self.map.remove(&stmt))
        } else {
            None
        }
    }

    pub fn clear(&mut self) {
        self.map.clear();
        self.order.clear();
    }

    pub fn into_iter(self) -> IntoIter<String, InnerStmt> {
        self.map.into_iter()
    }

    pub fn get_cap(&self) -> usize {
        self.cap
    }
}<|endoftext|>


<commit_before>use std::os;

use cargo::core::MultiShell;
use cargo::ops::CompileOptions;
use cargo::ops;
use cargo::util::important_paths::{find_root_manifest_for_cwd};
use cargo::util::{CliResult, CliError};
use docopt;

docopt!(Options, "
Compile a local package and all of its dependencies

Usage:
    cargo build [options]

Options:
    -h, --help               Print this message
    -p SPEC, --package SPEC  Package to run benchmarks for
    -j N, --jobs N           The number of jobs to run in parallel
    --release                Build artifacts in release mode, with optimizations
    --features FEATURES      Space-separated list of features to also build
    --no-default-features    Do not build the `default` feature
    --target TRIPLE          Build for the target triple
    --manifest-path PATH     Path to the manifest to compile
    -v, --verbose            Use verbose output

If the --package argument is given, then SPEC is a package id specification
which indicates which package should be built. If it is not given, then the
current package built tested. For more information on SPEC and its format, see the
`cargo help pkgid` command.
",  flag_jobs: Option<uint>, flag_target: Option<String>,
    flag_manifest_path: Option<String>, flag_features: Vec<String>,
    flag_package: Option<String>)

pub fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
    debug!("executing; cmd=cargo-build; args={}", os::args());
    shell.set_verbose(options.flag_verbose);

    let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));

    let env = if options.flag_release {
        "release"
    } else {
        "compile"
    };

    let mut opts = CompileOptions {
        env: env,
        shell: shell,
        jobs: options.flag_jobs,
        target: options.flag_target.as_ref().map(|t| t.as_slice()),
        dev_deps: false,
        features: options.flag_features.as_slice(),
        no_default_features: options.flag_no_default_features,
        spec: options.flag_package.as_ref().map(|s| s.as_slice()),
    };

    ops::compile(&root, &mut opts).map(|_| None).map_err(|err| {
        CliError::from_boxed(err, 101)
    })
}
<commit_msg>auto merge of #654 : ebfe/cargo/cargo-build-help, r=alexcrichton<commit_after>use std::os;

use cargo::core::MultiShell;
use cargo::ops::CompileOptions;
use cargo::ops;
use cargo::util::important_paths::{find_root_manifest_for_cwd};
use cargo::util::{CliResult, CliError};
use docopt;

docopt!(Options, "
Compile a local package and all of its dependencies

Usage:
    cargo build [options]

Options:
    -h, --help               Print this message
    -p SPEC, --package SPEC  Package to build
    -j N, --jobs N           The number of jobs to run in parallel
    --release                Build artifacts in release mode, with optimizations
    --features FEATURES      Space-separated list of features to also build
    --no-default-features    Do not build the `default` feature
    --target TRIPLE          Build for the target triple
    --manifest-path PATH     Path to the manifest to compile
    -v, --verbose            Use verbose output

If the --package argument is given, then SPEC is a package id specification
which indicates which package should be built. If it is not given, then the
current package is built. For more information on SPEC and its format, see the
`cargo help pkgid` command.
",  flag_jobs: Option<uint>, flag_target: Option<String>,
    flag_manifest_path: Option<String>, flag_features: Vec<String>,
    flag_package: Option<String>)

pub fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
    debug!("executing; cmd=cargo-build; args={}", os::args());
    shell.set_verbose(options.flag_verbose);

    let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));

    let env = if options.flag_release {
        "release"
    } else {
        "compile"
    };

    let mut opts = CompileOptions {
        env: env,
        shell: shell,
        jobs: options.flag_jobs,
        target: options.flag_target.as_ref().map(|t| t.as_slice()),
        dev_deps: false,
        features: options.flag_features.as_slice(),
        no_default_features: options.flag_no_default_features,
        spec: options.flag_package.as_ref().map(|s| s.as_slice()),
    };

    ops::compile(&root, &mut opts).map(|_| None).map_err(|err| {
        CliError::from_boxed(err, 101)
    })
}
<|endoftext|>


<commit_before>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#![feature(if_let, macro_rules, slicing_syntax)]

extern crate glob;
extern crate serialize;
extern crate term;
extern crate common;

use std::{io, os, str};
use std::io::{Command, MemReader};
use std::io::process::ExitStatus;
use std::str::{MaybeOwned, SendStr};
use glob::Paths;
use serialize::{json, Decodable};
use term::color::Color;
use common::SolverResult;

const PROBLEM_EXE_PAT: &'static str = "p[0-9][0-9][0-9]";

macro_rules! try2(
    ($e:expr) => (try!($e.map_err(|e| e.to_program_error())))
)

type ProgramResult<T> = Result<T, ProgramError>;
type OutputPair<'a> = (Option<Color>, MaybeOwned<'a>);

#[deriving(Show)]
enum ProgramErrorKind {
    IoError(io::IoError),
    JsonSyntaxError(json::ErrorCode, uint, uint),
    JsonDecoderError(json::DecoderError),
    Unknown
}

#[deriving(Show)]
struct ProgramError {
    kind: ProgramErrorKind,
    message: SendStr
}

impl ProgramError {
    pub fn new<T: IntoMaybeOwned<'static>>(msg: T, kind: ProgramErrorKind) -> ProgramError {
        ProgramError {
            kind: kind,
            message: msg.into_maybe_owned()
        }
    }
}

trait ToProgramError {
    fn to_program_error(self) -> ProgramError;
}

impl ToProgramError for io::IoError {
    fn to_program_error(self) -> ProgramError {
        ProgramError::new(self.desc.into_maybe_owned(), ProgramErrorKind::IoError(self))
    }
}

impl ToProgramError for json::ParserError {
    fn to_program_error(self) -> ProgramError {
        match self {
            json::SyntaxError(code, line, col) => {
                ProgramError::new(format!("{}:{}:{}", line, col, json::error_str(code)),
                                  ProgramErrorKind::JsonSyntaxError(code, line, col))
            },
            json::IoError(kind, desc) => {
                (io::IoError {kind: kind, desc: desc, detail: None })
                    .to_program_error()
            }
        }
    }
}

impl ToProgramError for json::DecoderError {
    fn to_program_error(self: json::DecoderError) -> ProgramError {
        ProgramError::new(format!("{}", self), ProgramErrorKind::JsonDecoderError(self))
    }
}

fn exe_path() -> ProgramResult<Path> {
    match os::self_exe_name() {
        Some(x) => Ok(x),
        None    => Err(ProgramError::new("cannot get self exe name", ProgramErrorKind::Unknown))
    }
}

fn problem_paths(dir_path: Path) -> ProgramResult<Paths> {
    let pat = dir_path.join(PROBLEM_EXE_PAT);
    match pat.as_str() {
        Some(x) => Ok(glob::glob(x)),
        None    => Err(ProgramError::new("path contains non-utf8 character", ProgramErrorKind::Unknown))
    }
}

fn run_problem(path: &Path) -> ProgramResult<SolverResult<String>> {
    let proc_out = try2!(Command::new(path).arg("--json").output());

    if !proc_out.error.is_empty() {
        let _ = match str::from_utf8(proc_out.error[]) {
            Some(s) => writeln!(&mut io::stderr(), "{}", s.trim()),
            None    => writeln!(&mut io::stderr(), "{}", proc_out.error)
        };
    }

    match proc_out.status {
        ExitStatus(0) | ExitStatus(1) => { } // expected
        st => {
            return Err(ProgramError::new(format!("child process exit with {}", st), ProgramErrorKind::Unknown))
        }
    }

    let json = try2!(json::from_reader(&mut MemReader::new(proc_out.output)));
    Ok(try2!(Decodable::decode(&mut json::Decoder::new(json))))
}

fn run() -> ProgramResult<()> {
    let dir_path = try!(exe_path()).dir_path();
    let mut out = io::stdout();

    let mut is_ok = true;
    let mut num_prob = 0;
    let mut total_time = 0;
    for path in try!(problem_paths(dir_path)) {
        let program = format!("{}", path.filename_display());

        match run_problem(&path) {
            Ok(ref r) => {
                num_prob   += 1;
                total_time += r.time;
                is_ok &= r.is_ok;
                let _ = r.print_pretty(program[], true);
            }
            Err(e) => {
                is_ok = false;
                let _ = writeln!(out, "{}: {}", program, e);
            }
        }
    }

    if num_prob > 0 {
        let r = SolverResult {
            time: total_time / num_prob,
            answer: "".to_string(),
            is_ok: is_ok
        };
        let _ = r.print_pretty(" AVG", true);

        let r = SolverResult {
            time: total_time,
            answer: "".to_string(),
            is_ok: is_ok
        };
        let _ = r.print_pretty(" SUM", false);
    }

    if !is_ok {
        os::set_exit_status(1);
    }

    Ok(())
}

fn main() {
    match run() {
        Ok(()) => {}
        Err(e) => {
            let _ = writeln!(&mut io::stderr(), "{}", e);
            os::set_exit_status(255);
        }
    }
}
<commit_msg>update to latest rustc<commit_after>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#![feature(if_let, macro_rules, slicing_syntax)]

extern crate glob;
extern crate serialize;
extern crate term;
extern crate common;

use std::{io, os, str};
use std::io::{Command, MemReader};
use std::io::process::ExitStatus;
use std::str::{MaybeOwned, SendStr};
use glob::Paths;
use serialize::{json, Decodable};
use term::color::Color;
use common::SolverResult;

const PROBLEM_EXE_PAT: &'static str = "p[0-9][0-9][0-9]";

macro_rules! try2(
    ($e:expr) => (try!($e.map_err(|e| e.to_program_error())))
)

type ProgramResult<T> = Result<T, ProgramError>;
type OutputPair<'a> = (Option<Color>, MaybeOwned<'a>);

#[deriving(Show)]
enum ProgramErrorKind {
    IoError(io::IoError),
    JsonSyntaxError(json::ErrorCode, uint, uint),
    JsonDecoderError(json::DecoderError),
    Unknown
}

#[deriving(Show)]
struct ProgramError {
    kind: ProgramErrorKind,
    message: SendStr
}

impl ProgramError {
    pub fn new<T: IntoMaybeOwned<'static>>(msg: T, kind: ProgramErrorKind) -> ProgramError {
        ProgramError {
            kind: kind,
            message: msg.into_maybe_owned()
        }
    }
}

trait ToProgramError {
    fn to_program_error(self) -> ProgramError;
}

impl ToProgramError for io::IoError {
    fn to_program_error(self) -> ProgramError {
        ProgramError::new(self.desc.into_maybe_owned(), ProgramErrorKind::IoError(self))
    }
}

impl ToProgramError for json::ParserError {
    fn to_program_error(self) -> ProgramError {
        match self {
            json::SyntaxError(code, line, col) => {
                ProgramError::new(format!("{}:{}:{}", line, col, json::error_str(code)),
                                  ProgramErrorKind::JsonSyntaxError(code, line, col))
            },
            json::IoError(kind, desc) => {
                (io::IoError {kind: kind, desc: desc, detail: None })
                    .to_program_error()
            }
        }
    }
}

impl ToProgramError for json::DecoderError {
    fn to_program_error(self: json::DecoderError) -> ProgramError {
        ProgramError::new(format!("{}", self), ProgramErrorKind::JsonDecoderError(self))
    }
}

fn exe_path() -> ProgramResult<Path> {
    match os::self_exe_name() {
        Some(x) => Ok(x),
        None    => Err(ProgramError::new("cannot get self exe name", ProgramErrorKind::Unknown))
    }
}

fn problem_paths(dir_path: Path) -> ProgramResult<Paths> {
    let pat = dir_path.join(PROBLEM_EXE_PAT);
    match pat.as_str() {
        Some(x) => Ok(glob::glob(x)),
        None    => Err(ProgramError::new("path contains non-utf8 character", ProgramErrorKind::Unknown))
    }
}

fn run_problem(path: &Path) -> ProgramResult<SolverResult<String>> {
    let proc_out = try2!(Command::new(path).arg("--json").output());

    if !proc_out.error.is_empty() {
        let _ = match str::from_utf8(proc_out.error[]) {
            Some(s) => writeln!(&mut io::stderr(), "{}", s.trim()),
            None    => writeln!(&mut io::stderr(), "{}", proc_out.error)
        };
    }

    match proc_out.status {
        ExitStatus(0) | ExitStatus(1) => { } // expected
        st => {
            return Err(ProgramError::new(format!("child process exit with {}", st), ProgramErrorKind::Unknown))
        }
    }

    let json = try2!(json::from_reader(&mut MemReader::new(proc_out.output)));
    Ok(try2!(Decodable::decode(&mut json::Decoder::new(json))))
}

fn run() -> ProgramResult<()> {
    let dir_path = try!(exe_path()).dir_path();
    let mut out = io::stdout();

    let mut is_ok = true;
    let mut num_prob = 0;
    let mut total_time = 0;
    for path in try!(problem_paths(dir_path)) {
        let program = format!("{}", path.filename_display());

        match run_problem(&path) {
            Ok(ref r) => {
                num_prob   += 1;
                total_time += r.time;
                is_ok &= r.is_ok;
                let _ = r.print_pretty(program[], true);
            }
            Err(e) => {
                is_ok = false;
                let _ = writeln!(&mut out, "{}: {}", program, e);
            }
        }
    }

    if num_prob > 0 {
        let r = SolverResult {
            time: total_time / num_prob,
            answer: "".to_string(),
            is_ok: is_ok
        };
        let _ = r.print_pretty(" AVG", true);

        let r = SolverResult {
            time: total_time,
            answer: "".to_string(),
            is_ok: is_ok
        };
        let _ = r.print_pretty(" SUM", false);
    }

    if !is_ok {
        os::set_exit_status(1);
    }

    Ok(())
}

fn main() {
    match run() {
        Ok(()) => {}
        Err(e) => {
            let _ = writeln!(&mut io::stderr(), "{}", e);
            os::set_exit_status(255);
        }
    }
}
<|endoftext|>


<commit_before>use gl;
use std::os::raw::c_void;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

pub use glfw::{self, Action, Context, CursorMode, Key, MouseButton, Window};

#[derive(Clone, Copy, Debug)]
pub enum LuminanceBackend {
  GL33
}

#[derive(Clone, Copy, Debug)]
pub enum WindowDim {
  Windowed(u32, u32),
  FullScreen,
  FullScreenRestricted(u32, u32)
}

pub type Keyboard = mpsc::Receiver<(Key, Action)>;
pub type Mouse = mpsc::Receiver<(MouseButton, Action)>;
pub type MouseMove = mpsc::Receiver<[f64; 2]>;
pub type Scroll = mpsc::Receiver<[f64; 2]>;

pub fn bootstrap<App: FnMut(u32, u32, Keyboard, Mouse, MouseMove, Scroll, Window)>(dim: WindowDim, title: &'static str, backend: LuminanceBackend, mut app: App) {
  let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

  match backend {
    LuminanceBackend::GL33 => {
      // OpenGL hints; implements luminance-gl’s core contexts creation
      glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
      glfw.window_hint(glfw::WindowHint::ContextVersionMajor(3));
      glfw.window_hint(glfw::WindowHint::ContextVersionMinor(3));
    }
  }

  // open a window in windowed or fullscreen mode
  let (mut window, events, w, h) = match dim {
    WindowDim::Windowed(w, h) => {
      let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::Windowed).expect("Failed to create GLFW window.");
      (window, events, w, h)
    },
    WindowDim::FullScreen => {
      glfw.with_primary_monitor(|glfw, monitor| {
        let monitor = monitor.unwrap();
        let vmode = monitor.get_video_mode().expect("primary monitor’s video mode");
        let (w, h) = (vmode.width, vmode.height);

        let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
        (window, events, w, h)
      })
    },
    WindowDim::FullScreenRestricted(w, h) => {
      glfw.with_primary_monitor(|glfw, monitor| {
        let monitor = monitor.unwrap();

        let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
        (window, events, w, h)
      })
    }
  };

  window.make_current();

  if cfg!(feature = "release") {
    window.set_cursor_mode(CursorMode::Disabled);
  }

  window.set_key_polling(true);
  window.set_cursor_pos_polling(true);
  window.set_mouse_button_polling(true);
  window.set_scroll_polling(true);

  // init OpenGL
  gl::load_with(|s| window.get_proc_address(s) as *const c_void);

  info!("using resolution {}x{}", w, h);

  // create channels to stream keyboard and mouse events
  let (kbd_snd, kbd_rcv) = mpsc::channel();
  let (mouse_snd, mouse_rcv) = mpsc::channel();
  let (mouse_move_snd, mouse_move_rcv) = mpsc::channel();
  let (scroll_snd, scroll_rcv) = mpsc::channel();

  // start the event threads
  let _ = thread::spawn(move || {
    for (_, event) in glfw::flush_messages(&events) {
      glfw.poll_events();

      match event {
          glfw::WindowEvent::Key(key, _, action, _) => {
            let _ = kbd_snd.send((key, action));
          },
          glfw::WindowEvent::MouseButton(button, action, _) => {
            let _ = mouse_snd.send((button, action));
          },
          glfw::WindowEvent::CursorPos(x, y) => {
            let _ = mouse_move_snd.send([x, y]);
          },
          glfw::WindowEvent::Scroll(x, y) => {
            let _ = scroll_snd.send([x, y]);
          },
          _ => {},
      }

      thread::sleep(Duration::from_millis(100));
    }
  });

  app(w, h, kbd_rcv, mouse_rcv, mouse_move_rcv, scroll_rcv, window);
}
<commit_msg>FnMut -> FnOnce.<commit_after>use gl;
use std::os::raw::c_void;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

pub use glfw::{self, Action, Context, CursorMode, Key, MouseButton, Window};

#[derive(Clone, Copy, Debug)]
pub enum LuminanceBackend {
  GL33
}

#[derive(Clone, Copy, Debug)]
pub enum WindowDim {
  Windowed(u32, u32),
  FullScreen,
  FullScreenRestricted(u32, u32)
}

pub type Keyboard = mpsc::Receiver<(Key, Action)>;
pub type Mouse = mpsc::Receiver<(MouseButton, Action)>;
pub type MouseMove = mpsc::Receiver<[f64; 2]>;
pub type Scroll = mpsc::Receiver<[f64; 2]>;

pub fn bootstrap<App: FnOnce(u32, u32, Keyboard, Mouse, MouseMove, Scroll, Window)>(dim: WindowDim, title: &'static str, backend: LuminanceBackend, app: App) {
  let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

  match backend {
    LuminanceBackend::GL33 => {
      // OpenGL hints; implements luminance-gl’s core contexts creation
      glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
      glfw.window_hint(glfw::WindowHint::ContextVersionMajor(3));
      glfw.window_hint(glfw::WindowHint::ContextVersionMinor(3));
    }
  }

  // open a window in windowed or fullscreen mode
  let (mut window, events, w, h) = match dim {
    WindowDim::Windowed(w, h) => {
      let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::Windowed).expect("Failed to create GLFW window.");
      (window, events, w, h)
    },
    WindowDim::FullScreen => {
      glfw.with_primary_monitor(|glfw, monitor| {
        let monitor = monitor.unwrap();
        let vmode = monitor.get_video_mode().expect("primary monitor’s video mode");
        let (w, h) = (vmode.width, vmode.height);

        let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
        (window, events, w, h)
      })
    },
    WindowDim::FullScreenRestricted(w, h) => {
      glfw.with_primary_monitor(|glfw, monitor| {
        let monitor = monitor.unwrap();

        let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
        (window, events, w, h)
      })
    }
  };

  window.make_current();

  if cfg!(feature = "release") {
    window.set_cursor_mode(CursorMode::Disabled);
  }

  window.set_key_polling(true);
  window.set_cursor_pos_polling(true);
  window.set_mouse_button_polling(true);
  window.set_scroll_polling(true);

  // init OpenGL
  gl::load_with(|s| window.get_proc_address(s) as *const c_void);

  info!("using resolution {}x{}", w, h);

  // create channels to stream keyboard and mouse events
  let (kbd_snd, kbd_rcv) = mpsc::channel();
  let (mouse_snd, mouse_rcv) = mpsc::channel();
  let (mouse_move_snd, mouse_move_rcv) = mpsc::channel();
  let (scroll_snd, scroll_rcv) = mpsc::channel();

  // start the event threads
  let _ = thread::spawn(move || {
    for (_, event) in glfw::flush_messages(&events) {
      glfw.poll_events();

      match event {
          glfw::WindowEvent::Key(key, _, action, _) => {
            let _ = kbd_snd.send((key, action));
          },
          glfw::WindowEvent::MouseButton(button, action, _) => {
            let _ = mouse_snd.send((button, action));
          },
          glfw::WindowEvent::CursorPos(x, y) => {
            let _ = mouse_move_snd.send([x, y]);
          },
          glfw::WindowEvent::Scroll(x, y) => {
            let _ = scroll_snd.send([x, y]);
          },
          _ => {},
      }

      thread::sleep(Duration::from_millis(100));
    }
  });

  app(w, h, kbd_rcv, mouse_rcv, mouse_move_rcv, scroll_rcv, window);
}
<|endoftext|>