<commit_before>extern crate rand;
extern crate regex;

use std::collections::HashSet;
use once_cell::sync::Lazy;

use self::regex::Regex;

const COLORS: Lazy<HashSet<&'static str>> = sync_lazy! {
    let mut set = HashSet::new();
    set.insert("black");
    set.insert("red");
    set.insert("green");
    set.insert("yellow");
    set.insert("blue");
    set.insert("magenta");
    set.insert("cyan");
    set.insert("white");
    set.insert("default");
    set
};

pub fn replace_all(input: String, from: &str, to: &str) -> String {
    input.replace(from, to)
}

pub fn consolidate_whitespace( input: String ) -> String {
    let found = input.find( |c: char| !c.is_whitespace() );
    let mut result = String::new();

    if let Some(found) = found {
        let (leading,rest) = input.split_at(found);
        let lastchar = input.chars().rev().next().unwrap();

        result.push_str(leading);

        let iter = rest.split_whitespace();
        for elem in iter {
            result.push_str(elem);
            result.push(' ');
        }
        result.pop();
        if lastchar.is_whitespace() {
            result.push(' ');
        }
    }

    result
}

pub fn to_u(rs_str: String, default_value: u32) -> u32 {
    let mut result = rs_str.parse::<u32>();

    if result.is_err() {
        result = Ok(default_value);
    }

    result.unwrap()
}

pub fn is_special_url(url: &str) -> bool {
    is_query_url(url) || is_filter_url(url) || is_exec_url(url)
}

pub fn is_http_url(url: &str) -> bool {
    url.starts_with("https://") || url.starts_with("http://")
}

pub fn is_query_url(url: &str) -> bool {
   url.starts_with("query:")
}

pub fn is_filter_url(url: &str) -> bool {
    url.starts_with("filter:")
}

pub fn is_exec_url(url: &str) -> bool {
    url.starts_with("exec:")
}

pub fn get_default_browser() -> String {
    use std::env;
    match env::var("BROWSER") {
        Ok(val) => return val,
        Err(_) => return String::from("lynx"),
    }
}

pub fn trim(rs_str: String) -> String {
    rs_str.trim().to_string()
}

pub fn trim_end(rs_str: String) -> String {
    let x: &[_] = &['\n','\r'];
    rs_str.trim_right_matches(x).to_string()
}

pub fn get_random_value(max: u32) -> u32 {
   rand::random::<u32>() % max
}

pub fn is_valid_color(color: &str) -> bool {
    if COLORS.contains(color) {
        return true;
    }
    if color.starts_with("color0") {
        return color == "color0";
    }
    if color.starts_with("color") {
        let num_part = &color[5..];
        match num_part.parse::<u8>() {
            Ok(_) => return true,
            _ => return false,
        }
    }
    false
}

pub fn is_valid_podcast_type(mimetype: &str) -> bool {
    let re = Regex::new(r"(audio|video)/.*").unwrap();
    let matches = re.is_match(mimetype);

    let acceptable = ["application/ogg"];
    let found = acceptable.contains(&mimetype);

    matches || found
}

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

    #[test]
    fn t_replace_all() {
	assert_eq!(
            replace_all(String::from("aaa"), "a", "b"),
            String::from("bbb"));
	assert_eq!(
            replace_all(String::from("aaa"), "aa", "ba"),
            String::from("baa"));
	assert_eq!(
            replace_all(String::from("aaaaaa"), "aa", "ba"),
            String::from("bababa"));
	assert_eq!(
            replace_all(String::new(), "a", "b"),
            String::new());

        let input = String::from("aaaa");
	assert_eq!(replace_all(input.clone(), "b", "c"), input);

	assert_eq!(
            replace_all(String::from("this is a normal test text"), " t", " T"),
            String::from("this is a normal Test Text"));

	assert_eq!(
            replace_all(String::from("o o o"), "o", "<o>"),
            String::from("<o> <o> <o>"));
    }

    #[test]
    fn t_consolidate_whitespace() {
        assert_eq!(
            consolidate_whitespace(String::from("LoremIpsum")),
            String::from("LoremIpsum"));
        assert_eq!(
            consolidate_whitespace(String::from("Lorem Ipsum")),
            String::from("Lorem Ipsum"));
        assert_eq!(
            consolidate_whitespace(String::from(" Lorem \t\tIpsum \t ")),
            String::from(" Lorem Ipsum "));
        assert_eq!(consolidate_whitespace(String::from(" Lorem \r\n\r\n\tIpsum")),
            String::from(" Lorem Ipsum"));
        assert_eq!(consolidate_whitespace(String::new()), String::new());
        assert_eq!(consolidate_whitespace(String::from("    Lorem \t\tIpsum \t ")),
            String::from("    Lorem Ipsum "));
        assert_eq!(consolidate_whitespace(String::from("   Lorem \r\n\r\n\tIpsum")),
            String::from("   Lorem Ipsum"));
    }

    #[test]
    fn t_to_u() {
        assert_eq!(to_u(String::from("0"), 10), 0);
        assert_eq!(to_u(String::from("23"), 1), 23);
        assert_eq!(to_u(String::from(""), 0), 0);
        assert_eq!(to_u(String::from("zero"), 1), 1);
    }

    #[test]
    fn t_is_special_url() {
	assert!(is_special_url("query:"));
	assert!(is_special_url("query: example"));
	assert!(!is_special_url("query"));
	assert!(!is_special_url("   query:"));

	assert!(is_special_url("filter:"));
	assert!(is_special_url("filter: example"));
	assert!(!is_special_url("filter"));
	assert!(!is_special_url("   filter:"));

	assert!(is_special_url("exec:"));
	assert!(is_special_url("exec: example"));
	assert!(!is_special_url("exec"));
	assert!(!is_special_url("   exec:"));
    }

    #[test]
    fn t_is_http_url() {
	assert!(is_http_url("https://foo.bar"));
	assert!(is_http_url("http://"));
	assert!(is_http_url("https://"));

	assert!(!is_http_url("htt://foo.bar"));
	assert!(!is_http_url("http:/"));
	assert!(!is_http_url("foo://bar"));
    }

    #[test]
    fn t_is_query_url() {
	assert!(is_query_url("query:"));
	assert!(is_query_url("query: example"));

	assert!(!is_query_url("query"));
	assert!(!is_query_url("   query:"));
    }

    #[test]
    fn t_is_filter_url() {
	assert!(is_filter_url("filter:"));
	assert!(is_filter_url("filter: example"));

	assert!(!is_filter_url("filter"));
	assert!(!is_filter_url("   filter:"));
    }

    #[test]
    fn t_is_exec_url() {
	assert!(is_exec_url("exec:"));
	assert!(is_exec_url("exec: example"));

	assert!(!is_exec_url("exec"));
	assert!(!is_exec_url("   exec:"));
    }

    #[test]
    fn t_trim() {
        assert_eq!(trim(String::from("  xxx\r\n")), "xxx");
        assert_eq!(trim(String::from("\n\n abc  foobar\n")), "abc  foobar");
        assert_eq!(trim(String::from("")), "");
        assert_eq!(trim(String::from("     \n")), "");
    }

    #[test]
    fn t_trim_end() {
        assert_eq!(trim_end(String::from("quux\n")), "quux");
    }

    #[test]
    fn t_is_valid_color() {
        let invalid = [
            "awesome",
            "list",
            "of",
            "things",
            "that",
            "aren't",
            "colors",
            "color0123",
            "color1024",
        ];
        for color in &invalid {
            assert!(!is_valid_color(color));
        }

        let valid = [
            "black",
            "red",
            "green",
            "yellow",
            "blue",
            "magenta",
            "cyan",
            "white",
            "default",
            "color0",
            "color163",
        ];

        for color in &valid {
            assert!(is_valid_color(color));
        }
    }

    #[test]
    fn t_is_valid_podcast_type() {
	assert!(is_valid_podcast_type("audio/mpeg"));
	assert!(is_valid_podcast_type("audio/mp3"));
	assert!(is_valid_podcast_type("audio/x-mp3"));
	assert!(is_valid_podcast_type("audio/ogg"));
	assert!(is_valid_podcast_type("application/ogg"));

	assert!(!is_valid_podcast_type("image/jpeg"));
	assert!(!is_valid_podcast_type("image/png"));
	assert!(!is_valid_podcast_type("text/plain"));
	assert!(!is_valid_podcast_type("application/zip"));
    }
}

<commit_msg>Document utils::is_http_url<commit_after>extern crate rand;
extern crate regex;

use std::collections::HashSet;
use once_cell::sync::Lazy;

use self::regex::Regex;

const COLORS: Lazy<HashSet<&'static str>> = sync_lazy! {
    let mut set = HashSet::new();
    set.insert("black");
    set.insert("red");
    set.insert("green");
    set.insert("yellow");
    set.insert("blue");
    set.insert("magenta");
    set.insert("cyan");
    set.insert("white");
    set.insert("default");
    set
};

pub fn replace_all(input: String, from: &str, to: &str) -> String {
    input.replace(from, to)
}

pub fn consolidate_whitespace( input: String ) -> String {
    let found = input.find( |c: char| !c.is_whitespace() );
    let mut result = String::new();

    if let Some(found) = found {
        let (leading,rest) = input.split_at(found);
        let lastchar = input.chars().rev().next().unwrap();

        result.push_str(leading);

        let iter = rest.split_whitespace();
        for elem in iter {
            result.push_str(elem);
            result.push(' ');
        }
        result.pop();
        if lastchar.is_whitespace() {
            result.push(' ');
        }
    }

    result
}

pub fn to_u(rs_str: String, default_value: u32) -> u32 {
    let mut result = rs_str.parse::<u32>();

    if result.is_err() {
        result = Ok(default_value);
    }

    result.unwrap()
}

pub fn is_special_url(url: &str) -> bool {
    is_query_url(url) || is_filter_url(url) || is_exec_url(url)
}

/// Check if the given URL is a http(s) URL
/// # Example
/// ```
/// use libnewsboat::utils::is_http_url;
/// assert!(is_http_url("http://example.com"));
/// ```
pub fn is_http_url(url: &str) -> bool {
    url.starts_with("https://") || url.starts_with("http://")
}

pub fn is_query_url(url: &str) -> bool {
   url.starts_with("query:")
}

pub fn is_filter_url(url: &str) -> bool {
    url.starts_with("filter:")
}

pub fn is_exec_url(url: &str) -> bool {
    url.starts_with("exec:")
}

pub fn get_default_browser() -> String {
    use std::env;
    match env::var("BROWSER") {
        Ok(val) => return val,
        Err(_) => return String::from("lynx"),
    }
}

pub fn trim(rs_str: String) -> String {
    rs_str.trim().to_string()
}

pub fn trim_end(rs_str: String) -> String {
    let x: &[_] = &['\n','\r'];
    rs_str.trim_right_matches(x).to_string()
}

pub fn get_random_value(max: u32) -> u32 {
   rand::random::<u32>() % max
}

pub fn is_valid_color(color: &str) -> bool {
    if COLORS.contains(color) {
        return true;
    }
    if color.starts_with("color0") {
        return color == "color0";
    }
    if color.starts_with("color") {
        let num_part = &color[5..];
        match num_part.parse::<u8>() {
            Ok(_) => return true,
            _ => return false,
        }
    }
    false
}

pub fn is_valid_podcast_type(mimetype: &str) -> bool {
    let re = Regex::new(r"(audio|video)/.*").unwrap();
    let matches = re.is_match(mimetype);

    let acceptable = ["application/ogg"];
    let found = acceptable.contains(&mimetype);

    matches || found
}

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

    #[test]
    fn t_replace_all() {
	assert_eq!(
            replace_all(String::from("aaa"), "a", "b"),
            String::from("bbb"));
	assert_eq!(
            replace_all(String::from("aaa"), "aa", "ba"),
            String::from("baa"));
	assert_eq!(
            replace_all(String::from("aaaaaa"), "aa", "ba"),
            String::from("bababa"));
	assert_eq!(
            replace_all(String::new(), "a", "b"),
            String::new());

        let input = String::from("aaaa");
	assert_eq!(replace_all(input.clone(), "b", "c"), input);

	assert_eq!(
            replace_all(String::from("this is a normal test text"), " t", " T"),
            String::from("this is a normal Test Text"));

	assert_eq!(
            replace_all(String::from("o o o"), "o", "<o>"),
            String::from("<o> <o> <o>"));
    }

    #[test]
    fn t_consolidate_whitespace() {
        assert_eq!(
            consolidate_whitespace(String::from("LoremIpsum")),
            String::from("LoremIpsum"));
        assert_eq!(
            consolidate_whitespace(String::from("Lorem Ipsum")),
            String::from("Lorem Ipsum"));
        assert_eq!(
            consolidate_whitespace(String::from(" Lorem \t\tIpsum \t ")),
            String::from(" Lorem Ipsum "));
        assert_eq!(consolidate_whitespace(String::from(" Lorem \r\n\r\n\tIpsum")),
            String::from(" Lorem Ipsum"));
        assert_eq!(consolidate_whitespace(String::new()), String::new());
        assert_eq!(consolidate_whitespace(String::from("    Lorem \t\tIpsum \t ")),
            String::from("    Lorem Ipsum "));
        assert_eq!(consolidate_whitespace(String::from("   Lorem \r\n\r\n\tIpsum")),
            String::from("   Lorem Ipsum"));
    }

    #[test]
    fn t_to_u() {
        assert_eq!(to_u(String::from("0"), 10), 0);
        assert_eq!(to_u(String::from("23"), 1), 23);
        assert_eq!(to_u(String::from(""), 0), 0);
        assert_eq!(to_u(String::from("zero"), 1), 1);
    }

    #[test]
    fn t_is_special_url() {
	assert!(is_special_url("query:"));
	assert!(is_special_url("query: example"));
	assert!(!is_special_url("query"));
	assert!(!is_special_url("   query:"));

	assert!(is_special_url("filter:"));
	assert!(is_special_url("filter: example"));
	assert!(!is_special_url("filter"));
	assert!(!is_special_url("   filter:"));

	assert!(is_special_url("exec:"));
	assert!(is_special_url("exec: example"));
	assert!(!is_special_url("exec"));
	assert!(!is_special_url("   exec:"));
    }

    #[test]
    fn t_is_http_url() {
	assert!(is_http_url("https://foo.bar"));
	assert!(is_http_url("http://"));
	assert!(is_http_url("https://"));

	assert!(!is_http_url("htt://foo.bar"));
	assert!(!is_http_url("http:/"));
	assert!(!is_http_url("foo://bar"));
    }

    #[test]
    fn t_is_query_url() {
	assert!(is_query_url("query:"));
	assert!(is_query_url("query: example"));

	assert!(!is_query_url("query"));
	assert!(!is_query_url("   query:"));
    }

    #[test]
    fn t_is_filter_url() {
	assert!(is_filter_url("filter:"));
	assert!(is_filter_url("filter: example"));

	assert!(!is_filter_url("filter"));
	assert!(!is_filter_url("   filter:"));
    }

    #[test]
    fn t_is_exec_url() {
	assert!(is_exec_url("exec:"));
	assert!(is_exec_url("exec: example"));

	assert!(!is_exec_url("exec"));
	assert!(!is_exec_url("   exec:"));
    }

    #[test]
    fn t_trim() {
        assert_eq!(trim(String::from("  xxx\r\n")), "xxx");
        assert_eq!(trim(String::from("\n\n abc  foobar\n")), "abc  foobar");
        assert_eq!(trim(String::from("")), "");
        assert_eq!(trim(String::from("     \n")), "");
    }

    #[test]
    fn t_trim_end() {
        assert_eq!(trim_end(String::from("quux\n")), "quux");
    }

    #[test]
    fn t_is_valid_color() {
        let invalid = [
            "awesome",
            "list",
            "of",
            "things",
            "that",
            "aren't",
            "colors",
            "color0123",
            "color1024",
        ];
        for color in &invalid {
            assert!(!is_valid_color(color));
        }

        let valid = [
            "black",
            "red",
            "green",
            "yellow",
            "blue",
            "magenta",
            "cyan",
            "white",
            "default",
            "color0",
            "color163",
        ];

        for color in &valid {
            assert!(is_valid_color(color));
        }
    }

    #[test]
    fn t_is_valid_podcast_type() {
	assert!(is_valid_podcast_type("audio/mpeg"));
	assert!(is_valid_podcast_type("audio/mp3"));
	assert!(is_valid_podcast_type("audio/x-mp3"));
	assert!(is_valid_podcast_type("audio/ogg"));
	assert!(is_valid_podcast_type("application/ogg"));

	assert!(!is_valid_podcast_type("image/jpeg"));
	assert!(!is_valid_podcast_type("image/png"));
	assert!(!is_valid_podcast_type("text/plain"));
	assert!(!is_valid_podcast_type("application/zip"));
    }
}

<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use hir::def_id::CrateNum;
use std::fmt::Debug;
use std::sync::Arc;

macro_rules! try_opt {
    ($e:expr) => (
        match $e {
            Some(r) => r,
            None => return None,
        }
    )
}

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub enum DepNode<D: Clone + Debug> {
    // The `D` type is "how definitions are identified".
    // During compilation, it is always `DefId`, but when serializing
    // it is mapped to `DefPath`.

    // Represents the `Krate` as a whole (the `hir::Krate` value) (as
    // distinct from the krate module). This is basically a hash of
    // the entire krate, so if you read from `Krate` (e.g., by calling
    // `tcx.hir.krate()`), we will have to assume that any change
    // means that you need to be recompiled. This is because the
    // `Krate` value gives you access to all other items. To avoid
    // this fate, do not call `tcx.hir.krate()`; instead, prefer
    // wrappers like `tcx.visit_all_items_in_krate()`.  If there is no
    // suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
    // access to the krate, but you must remember to add suitable
    // edges yourself for the individual items that you read.
    Krate,

    // Represents the HIR node with the given node-id
    Hir(D),

    // Represents the body of a function or method. The def-id is that of the
    // function/method.
    HirBody(D),

    // Represents the metadata for a given HIR node, typically found
    // in an extern crate.
    MetaData(D),

    // Represents some artifact that we save to disk. Note that these
    // do not have a def-id as part of their identifier.
    WorkProduct(Arc<WorkProductId>),

    // Represents different phases in the compiler.
    RegionResolveCrate,
    Coherence,
    Resolve,
    CoherenceCheckTrait(D),
    CoherenceCheckImpl(D),
    CoherenceOverlapCheck(D),
    CoherenceOverlapCheckSpecial(D),
    Variance,
    PrivacyAccessLevels(CrateNum),

    // Represents the MIR for a fn; also used as the task node for
    // things read/modify that MIR.
    MirKrate,
    Mir(D),
    MirShim(Vec<D>),

    BorrowCheckKrate,
    BorrowCheck(D),
    RvalueCheck(D),
    Reachability,
    LateLintCheck,
    TransCrateItem(D),
    TransInlinedItem(D),
    TransWriteMetadata,

    // Nodes representing bits of computed IR in the tcx. Each shared
    // table in the tcx (or elsewhere) maps to one of these
    // nodes. Often we map multiple tables to the same node if there
    // is no point in distinguishing them (e.g., both the type and
    // predicates for an item wind up in `ItemSignature`).
    AssociatedItems(D),
    ItemSignature(D),
    IsForeignItem(D),
    TypeParamPredicates((D, D)),
    SizedConstraint(D),
    DtorckConstraint(D),
    AdtDestructor(D),
    AssociatedItemDefIds(D),
    InherentImpls(D),
    TypeckBodiesKrate,
    TypeckTables(D),
    UsedTraitImports(D),
    ConstEval(D),
    SymbolName(D),

    // The set of impls for a given trait. Ultimately, it would be
    // nice to get more fine-grained here (e.g., to include a
    // simplified type), but we can't do that until we restructure the
    // HIR to distinguish the *header* of an impl from its body.  This
    // is because changes to the header may change the self-type of
    // the impl and hence would require us to be more conservative
    // than changes in the impl body.
    TraitImpls(D),

    // Nodes representing caches. To properly handle a true cache, we
    // don't use a DepTrackingMap, but rather we push a task node.
    // Otherwise the write into the map would be incorrectly
    // attributed to the first task that happened to fill the cache,
    // which would yield an overly conservative dep-graph.
    TraitItems(D),
    ReprHints(D),

    // Trait selection cache is a little funny. Given a trait
    // reference like `Foo: SomeTrait<Bar>`, there could be
    // arbitrarily many def-ids to map on in there (e.g., `Foo`,
    // `SomeTrait`, `Bar`). We could have a vector of them, but it
    // requires heap-allocation, and trait sel in general can be a
    // surprisingly hot path. So instead we pick two def-ids: the
    // trait def-id, and the first def-id in the input types. If there
    // is no def-id in the input types, then we use the trait def-id
    // again. So for example:
    //
    // - `i32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
    // - `u32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
    // - `Clone: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
    // - `Vec<i32>: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }`
    // - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }`
    // - `Foo: Trait<Bar>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
    // - `Foo: Trait<i32>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
    // - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
    // - `i32: Trait<Foo>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
    //
    // You can see that we map many trait refs to the same
    // trait-select node.  This is not a problem, it just means
    // imprecision in our dep-graph tracking.  The important thing is
    // that for any given trait-ref, we always map to the **same**
    // trait-select node.
    TraitSelect { trait_def_id: D, input_def_id: D },

    // For proj. cache, we just keep a list of all def-ids, since it is
    // not a hotspot.
    ProjectionCache { def_ids: Vec<D> },

    // Depnodes for MetaData
    DescribeDef(D),
    DefSpan(D),
}

impl<D: Clone + Debug> DepNode<D> {
    /// Used in testing
    pub fn from_label_string(label: &str, data: D) -> Result<DepNode<D>, ()> {
        macro_rules! check {
            ($($name:ident,)*) => {
                match label {
                    $(stringify!($name) => Ok(DepNode::$name(data)),)*
                    _ => Err(())
                }
            }
        }

        if label == "Krate" {
            // special case
            return Ok(DepNode::Krate);
        }

        check! {
            BorrowCheck,
            Hir,
            HirBody,
            TransCrateItem,
            AssociatedItems,
            ItemSignature,
            IsForeignItem,
            AssociatedItemDefIds,
            InherentImpls,
            TypeckTables,
            UsedTraitImports,
            TraitImpls,
            ReprHints,
        }
    }

    pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
        where OP: FnMut(&D) -> Option<E>, E: Clone + Debug
    {
        use self::DepNode::*;

        match *self {
            Krate => Some(Krate),
            BorrowCheckKrate => Some(BorrowCheckKrate),
            MirKrate => Some(MirKrate),
            TypeckBodiesKrate => Some(TypeckBodiesKrate),
            RegionResolveCrate => Some(RegionResolveCrate),
            Coherence => Some(Coherence),
            Resolve => Some(Resolve),
            Variance => Some(Variance),
            PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)),
            Reachability => Some(Reachability),
            LateLintCheck => Some(LateLintCheck),
            TransWriteMetadata => Some(TransWriteMetadata),

            // work product names do not need to be mapped, because
            // they are always absolute.
            WorkProduct(ref id) => Some(WorkProduct(id.clone())),

            Hir(ref d) => op(d).map(Hir),
            HirBody(ref d) => op(d).map(HirBody),
            MetaData(ref d) => op(d).map(MetaData),
            CoherenceCheckTrait(ref d) => op(d).map(CoherenceCheckTrait),
            CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
            CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
            CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
            Mir(ref d) => op(d).map(Mir),
            MirShim(ref def_ids) => {
                let def_ids: Option<Vec<E>> = def_ids.iter().map(op).collect();
                def_ids.map(MirShim)
            }
            BorrowCheck(ref d) => op(d).map(BorrowCheck),
            RvalueCheck(ref d) => op(d).map(RvalueCheck),
            TransCrateItem(ref d) => op(d).map(TransCrateItem),
            TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
            AssociatedItems(ref d) => op(d).map(AssociatedItems),
            ItemSignature(ref d) => op(d).map(ItemSignature),
            IsForeignItem(ref d) => op(d).map(IsForeignItem),
            TypeParamPredicates((ref item, ref param)) => {
                Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
            }
            SizedConstraint(ref d) => op(d).map(SizedConstraint),
            DtorckConstraint(ref d) => op(d).map(DtorckConstraint),
            AdtDestructor(ref d) => op(d).map(AdtDestructor),
            AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
            InherentImpls(ref d) => op(d).map(InherentImpls),
            TypeckTables(ref d) => op(d).map(TypeckTables),
            UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
            ConstEval(ref d) => op(d).map(ConstEval),
            SymbolName(ref d) => op(d).map(SymbolName),
            TraitImpls(ref d) => op(d).map(TraitImpls),
            TraitItems(ref d) => op(d).map(TraitItems),
            ReprHints(ref d) => op(d).map(ReprHints),
            TraitSelect { ref trait_def_id, ref input_def_id } => {
                op(trait_def_id).and_then(|trait_def_id| {
                    op(input_def_id).and_then(|input_def_id| {
                        Some(TraitSelect { trait_def_id: trait_def_id,
                                           input_def_id: input_def_id })
                    })
                })
            }
            ProjectionCache { ref def_ids } => {
                let def_ids: Option<Vec<E>> = def_ids.iter().map(op).collect();
                def_ids.map(|d| ProjectionCache { def_ids: d })
            }
            DescribeDef(ref d) => op(d).map(MetaData),
            DefSpan(ref d) => op(d).map(MetaData),
        }
    }
}

/// A "work product" corresponds to a `.o` (or other) file that we
/// save in between runs. These ids do not have a DefId but rather
/// some independent path or string that persists between runs without
/// the need to be mapped or unmapped. (This ensures we can serialize
/// them even in the absence of a tcx.)
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub struct WorkProductId(pub String);
<commit_msg>chaned dep nodes impl<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use hir::def_id::CrateNum;
use std::fmt::Debug;
use std::sync::Arc;

macro_rules! try_opt {
    ($e:expr) => (
        match $e {
            Some(r) => r,
            None => return None,
        }
    )
}

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub enum DepNode<D: Clone + Debug> {
    // The `D` type is "how definitions are identified".
    // During compilation, it is always `DefId`, but when serializing
    // it is mapped to `DefPath`.

    // Represents the `Krate` as a whole (the `hir::Krate` value) (as
    // distinct from the krate module). This is basically a hash of
    // the entire krate, so if you read from `Krate` (e.g., by calling
    // `tcx.hir.krate()`), we will have to assume that any change
    // means that you need to be recompiled. This is because the
    // `Krate` value gives you access to all other items. To avoid
    // this fate, do not call `tcx.hir.krate()`; instead, prefer
    // wrappers like `tcx.visit_all_items_in_krate()`.  If there is no
    // suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
    // access to the krate, but you must remember to add suitable
    // edges yourself for the individual items that you read.
    Krate,

    // Represents the HIR node with the given node-id
    Hir(D),

    // Represents the body of a function or method. The def-id is that of the
    // function/method.
    HirBody(D),

    // Represents the metadata for a given HIR node, typically found
    // in an extern crate.
    MetaData(D),

    // Represents some artifact that we save to disk. Note that these
    // do not have a def-id as part of their identifier.
    WorkProduct(Arc<WorkProductId>),

    // Represents different phases in the compiler.
    RegionResolveCrate,
    Coherence,
    Resolve,
    CoherenceCheckTrait(D),
    CoherenceCheckImpl(D),
    CoherenceOverlapCheck(D),
    CoherenceOverlapCheckSpecial(D),
    Variance,
    PrivacyAccessLevels(CrateNum),

    // Represents the MIR for a fn; also used as the task node for
    // things read/modify that MIR.
    MirKrate,
    Mir(D),
    MirShim(Vec<D>),

    BorrowCheckKrate,
    BorrowCheck(D),
    RvalueCheck(D),
    Reachability,
    LateLintCheck,
    TransCrateItem(D),
    TransInlinedItem(D),
    TransWriteMetadata,

    // Nodes representing bits of computed IR in the tcx. Each shared
    // table in the tcx (or elsewhere) maps to one of these
    // nodes. Often we map multiple tables to the same node if there
    // is no point in distinguishing them (e.g., both the type and
    // predicates for an item wind up in `ItemSignature`).
    AssociatedItems(D),
    ItemSignature(D),
    IsForeignItem(D),
    TypeParamPredicates((D, D)),
    SizedConstraint(D),
    DtorckConstraint(D),
    AdtDestructor(D),
    AssociatedItemDefIds(D),
    InherentImpls(D),
    TypeckBodiesKrate,
    TypeckTables(D),
    UsedTraitImports(D),
    ConstEval(D),
    SymbolName(D),

    // The set of impls for a given trait. Ultimately, it would be
    // nice to get more fine-grained here (e.g., to include a
    // simplified type), but we can't do that until we restructure the
    // HIR to distinguish the *header* of an impl from its body.  This
    // is because changes to the header may change the self-type of
    // the impl and hence would require us to be more conservative
    // than changes in the impl body.
    TraitImpls(D),

    // Nodes representing caches. To properly handle a true cache, we
    // don't use a DepTrackingMap, but rather we push a task node.
    // Otherwise the write into the map would be incorrectly
    // attributed to the first task that happened to fill the cache,
    // which would yield an overly conservative dep-graph.
    TraitItems(D),
    ReprHints(D),

    // Trait selection cache is a little funny. Given a trait
    // reference like `Foo: SomeTrait<Bar>`, there could be
    // arbitrarily many def-ids to map on in there (e.g., `Foo`,
    // `SomeTrait`, `Bar`). We could have a vector of them, but it
    // requires heap-allocation, and trait sel in general can be a
    // surprisingly hot path. So instead we pick two def-ids: the
    // trait def-id, and the first def-id in the input types. If there
    // is no def-id in the input types, then we use the trait def-id
    // again. So for example:
    //
    // - `i32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
    // - `u32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
    // - `Clone: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
    // - `Vec<i32>: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }`
    // - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }`
    // - `Foo: Trait<Bar>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
    // - `Foo: Trait<i32>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
    // - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
    // - `i32: Trait<Foo>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
    //
    // You can see that we map many trait refs to the same
    // trait-select node.  This is not a problem, it just means
    // imprecision in our dep-graph tracking.  The important thing is
    // that for any given trait-ref, we always map to the **same**
    // trait-select node.
    TraitSelect { trait_def_id: D, input_def_id: D },

    // For proj. cache, we just keep a list of all def-ids, since it is
    // not a hotspot.
    ProjectionCache { def_ids: Vec<D> },

    // Depnodes for MetaData
    DescribeDef(D),
    DefSpan(D),
}

impl<D: Clone + Debug> DepNode<D> {
    /// Used in testing
    pub fn from_label_string(label: &str, data: D) -> Result<DepNode<D>, ()> {
        macro_rules! check {
            ($($name:ident,)*) => {
                match label {
                    $(stringify!($name) => Ok(DepNode::$name(data)),)*
                    _ => Err(())
                }
            }
        }

        if label == "Krate" {
            // special case
            return Ok(DepNode::Krate);
        }

        check! {
            BorrowCheck,
            Hir,
            HirBody,
            TransCrateItem,
            AssociatedItems,
            ItemSignature,
            IsForeignItem,
            AssociatedItemDefIds,
            InherentImpls,
            TypeckTables,
            UsedTraitImports,
            TraitImpls,
            ReprHints,
        }
    }

    pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
        where OP: FnMut(&D) -> Option<E>, E: Clone + Debug
    {
        use self::DepNode::*;

        match *self {
            Krate => Some(Krate),
            BorrowCheckKrate => Some(BorrowCheckKrate),
            MirKrate => Some(MirKrate),
            TypeckBodiesKrate => Some(TypeckBodiesKrate),
            RegionResolveCrate => Some(RegionResolveCrate),
            Coherence => Some(Coherence),
            Resolve => Some(Resolve),
            Variance => Some(Variance),
            PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)),
            Reachability => Some(Reachability),
            LateLintCheck => Some(LateLintCheck),
            TransWriteMetadata => Some(TransWriteMetadata),

            // work product names do not need to be mapped, because
            // they are always absolute.
            WorkProduct(ref id) => Some(WorkProduct(id.clone())),

            Hir(ref d) => op(d).map(Hir),
            HirBody(ref d) => op(d).map(HirBody),
            MetaData(ref d) => op(d).map(MetaData),
            CoherenceCheckTrait(ref d) => op(d).map(CoherenceCheckTrait),
            CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
            CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
            CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
            Mir(ref d) => op(d).map(Mir),
            MirShim(ref def_ids) => {
                let def_ids: Option<Vec<E>> = def_ids.iter().map(op).collect();
                def_ids.map(MirShim)
            }
            BorrowCheck(ref d) => op(d).map(BorrowCheck),
            RvalueCheck(ref d) => op(d).map(RvalueCheck),
            TransCrateItem(ref d) => op(d).map(TransCrateItem),
            TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
            AssociatedItems(ref d) => op(d).map(AssociatedItems),
            ItemSignature(ref d) => op(d).map(ItemSignature),
            IsForeignItem(ref d) => op(d).map(IsForeignItem),
            TypeParamPredicates((ref item, ref param)) => {
                Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
            }
            SizedConstraint(ref d) => op(d).map(SizedConstraint),
            DtorckConstraint(ref d) => op(d).map(DtorckConstraint),
            AdtDestructor(ref d) => op(d).map(AdtDestructor),
            AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
            InherentImpls(ref d) => op(d).map(InherentImpls),
            TypeckTables(ref d) => op(d).map(TypeckTables),
            UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
            ConstEval(ref d) => op(d).map(ConstEval),
            SymbolName(ref d) => op(d).map(SymbolName),
            TraitImpls(ref d) => op(d).map(TraitImpls),
            TraitItems(ref d) => op(d).map(TraitItems),
            ReprHints(ref d) => op(d).map(ReprHints),
            TraitSelect { ref trait_def_id, ref input_def_id } => {
                op(trait_def_id).and_then(|trait_def_id| {
                    op(input_def_id).and_then(|input_def_id| {
                        Some(TraitSelect { trait_def_id: trait_def_id,
                                           input_def_id: input_def_id })
                    })
                })
            }
            ProjectionCache { ref def_ids } => {
                let def_ids: Option<Vec<E>> = def_ids.iter().map(op).collect();
                def_ids.map(|d| ProjectionCache { def_ids: d })
            }
            DescribeDef(ref d) => op(d).map(DescribeDef),
            DefSpan(ref d) => op(d).map(DefSpan),
        }
    }
}

/// A "work product" corresponds to a `.o` (or other) file that we
/// save in between runs. These ids do not have a DefId but rather
/// some independent path or string that persists between runs without
/// the need to be mapped or unmapped. (This ensures we can serialize
/// them even in the absence of a tcx.)
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub struct WorkProductId(pub String);
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::io;
use std::io::BufRead;

fn main() {
    let mut counts: BTreeMap<String, isize> = BTreeMap::new();
    let stdin = io::stdin();
    for line_result in stdin.lock().lines() {
        if let Ok(line) = line_result {
            let lowercase_line = line.to_lowercase();
            let words = lowercase_line.split(|c: char| {
                 !(c.is_alphabetic() || c == '\'')
             });
             for word in words {
                 if word.len() > 0 {
                     *counts.entry(word.to_string()).or_insert(0) += 1;
                 }
             }
        } else {
            panic!("Error parsing stdin");
        }
    }
    for (key, value) in counts.iter() {
        println!("{} {}", key, value);
    }
}
<commit_msg>Use match instead of if let<commit_after>use std::collections::BTreeMap;
use std::io;
use std::io::BufRead;

fn main() {
    let mut counts: BTreeMap<String, isize> = BTreeMap::new();
    let stdin = io::stdin();
    for line_result in stdin.lock().lines() {
        match line_result {
            Ok(line) => {
                let lowercase_line = line.to_lowercase();
                let words = lowercase_line.split(|c: char| {
                     !(c.is_alphabetic() || c == '\'')
                 }).filter(|s| !s.is_empty());
                 for word in words {
                    *(counts.entry(word.to_string()).or_insert(0)) += 1;
                 }
            },
            Err(e) => {
                panic!("Error parsing stdin: {:?}", e);
            }
        }
    }
    for (key, value) in counts.iter() {
        println!("{} {}", key, value);
    }
}
<|endoftext|>


<commit_before>/// The validator service. Connects to a beacon node and signs blocks when required.
use crate::attester_service::{AttestationGrpcClient, AttesterService};
use crate::block_producer_service::{BeaconBlockGrpcClient, BlockProducerService};
use crate::config::Config as ValidatorConfig;
use crate::duties::UpdateOutcome;
use crate::duties::{DutiesManager, EpochDutiesMap};
use crate::error as error_chain;
use crate::error::ErrorKind;
use attester::test_utils::EpochMap;
use attester::{test_utils::LocalSigner as AttesterLocalSigner, Attester};
use block_proposer::{test_utils::LocalSigner as BlockProposerLocalSigner, BlockProducer};
use bls::Keypair;
use grpcio::{ChannelBuilder, EnvBuilder};
use protos::services::Empty;
use protos::services_grpc::{
    AttestationServiceClient, BeaconBlockServiceClient, BeaconNodeServiceClient,
    ValidatorServiceClient,
};
use slog::{debug, error, info, warn};
use slot_clock::{SlotClock, SystemTimeSlotClock};
use std::sync::Arc;
use std::sync::RwLock;
use std::time::{Duration, Instant, SystemTime};
use tokio::prelude::*;
use tokio::runtime::Builder;
use tokio::timer::Interval;
use tokio_timer::clock::Clock;
use types::{Epoch, Fork, Slot};

//TODO: This service should be simplified in the future. Can be made more steamlined.

/// The validator service. This is the main thread that executes and maintains validator
/// duties.
pub struct Service {
    /// The node we currently connected to.
    connected_node_version: String,
    /// The chain id we are processing on.
    chain_id: u16,
    /// The fork state we processing on.
    fork: Fork,
    /// The slot clock for this service.
    slot_clock: SystemTimeSlotClock,
    /// The current slot we are processing.
    current_slot: Slot,
    /// Duration until the next slot. This is used for initializing the tokio timer interval.
    duration_to_next_slot: Duration,
    /// The number of slots per epoch to allow for converting slots to epochs.
    slots_per_epoch: u64,
    // GRPC Clients
    /// The beacon block GRPC client.
    beacon_block_client: Arc<BeaconBlockServiceClient>,
    /// The validator GRPC client.
    validator_client: Arc<ValidatorServiceClient>,
    /// The attester GRPC client.
    attester_client: Arc<AttestationServiceClient>,
    /// The validator client logger.
    log: slog::Logger,
}

impl Service {
    ///  Initial connection to the beacon node to determine its properties.
    ///
    ///  This tries to connect to a beacon node. Once connected, it initialised the gRPC clients
    ///  and returns an instance of the service.
    fn initialize_service(
        config: &ValidatorConfig,
        log: slog::Logger,
    ) -> error_chain::Result<Self> {
        // initialise the beacon node client to check for a connection

        let env = Arc::new(EnvBuilder::new().build());
        // Beacon node gRPC beacon node endpoints.
        let beacon_node_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(BeaconNodeServiceClient::new(ch))
        };

        // retrieve node information
        let node_info = loop {
            match beacon_node_client.info(&Empty::new()) {
                Err(e) => {
                    warn!(log, "Could not connect to node. Error: {}", e);
                    info!(log, "Retrying in 5 seconds...");
                    std::thread::sleep(Duration::from_secs(5));
                    continue;
                }
                Ok(info) => {
                    if SystemTime::now()
                        .duration_since(SystemTime::UNIX_EPOCH)
                        .unwrap()
                        .as_secs()
                        < info.genesis_time
                    {
                        warn!(
                            log,
                            "Beacon Node's genesis time is in the future. No work to do.\n Exiting"
                        );
                        return Err("Genesis time in the future".into());
                    }
                    break info;
                }
            };
        };

        // build requisite objects to form Self
        let genesis_time = node_info.get_genesis_time();

        info!(log,"Beacon node connected"; "Node Version" => node_info.version.clone(), "Chain ID" => node_info.chain_id, "Genesis time" => genesis_time);

        let proto_fork = node_info.get_fork();
        let mut previous_version: [u8; 4] = [0; 4];
        let mut current_version: [u8; 4] = [0; 4];
        previous_version.copy_from_slice(&proto_fork.get_previous_version()[..4]);
        current_version.copy_from_slice(&proto_fork.get_current_version()[..4]);
        let fork = Fork {
            previous_version,
            current_version,
            epoch: Epoch::from(proto_fork.get_epoch()),
        };

        // initialize the RPC clients

        // Beacon node gRPC beacon block endpoints.
        let beacon_block_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(BeaconBlockServiceClient::new(ch))
        };

        // Beacon node gRPC validator endpoints.
        let validator_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(ValidatorServiceClient::new(ch))
        };

        //Beacon node gRPC attester endpoints.
        let attester_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(AttestationServiceClient::new(ch))
        };

        // build the validator slot clock
        let slot_clock = SystemTimeSlotClock::new(genesis_time, config.spec.seconds_per_slot)
            .expect("Unable to instantiate SystemTimeSlotClock.");

        let current_slot = slot_clock
            .present_slot()
            .map_err(|e| ErrorKind::SlotClockError(e))?
            .expect("Genesis must be in the future");

        // calculate the duration to the next slot
        let duration_to_next_slot = {
            let seconds_per_slot = config.spec.seconds_per_slot;
            let syslot_time = SystemTime::now();
            let duration_since_epoch = syslot_time
                .duration_since(SystemTime::UNIX_EPOCH)
                .map_err(|e| ErrorKind::SystemTimeError(e.to_string()))?;
            let duration_since_genesis = duration_since_epoch
                .checked_sub(Duration::from_secs(genesis_time))
                .expect("Genesis must be in the future. Checked on connection");
            let elapsed_slots = duration_since_epoch
                .as_secs()
                .checked_div(seconds_per_slot as u64)
                .expect("Seconds per slot should not be 0");

            // the duration to the next slot
            Duration::from_secs(
                (elapsed_slots + 1)
                    .checked_mul(seconds_per_slot)
                    .expect("Next slot time should not overflow u64"),
            )
            .checked_sub(duration_since_genesis)
            .expect("This should never saturate")
        };

        Ok(Self {
            connected_node_version: node_info.version,
            chain_id: node_info.chain_id as u16,
            fork,
            slot_clock,
            current_slot,
            duration_to_next_slot,
            slots_per_epoch: config.spec.slots_per_epoch,
            beacon_block_client,
            validator_client,
            attester_client,
            log,
        })
    }

    /// Initialise the service then run the core thread.
    pub fn start(config: ValidatorConfig, log: slog::Logger) -> error_chain::Result<()> {
        // connect to the node and retrieve its properties and initialize the gRPC clients
        let service = Service::initialize_service(&config, log)?;

        // we have connected to a node and established its parameters. Spin up the core service

        // set up the validator service runtime
        let mut runtime = Builder::new()
            .clock(Clock::system())
            .name_prefix("validator-client-")
            .build()
            .map_err(|e| format!("Tokio runtime failed: {}", e))?;

        // set up the validator work interval - start at next slot and proceed every slot
        let interval = {
            // Set the interval to start at the next slot, and every slot after
            let slot_duration = Duration::from_secs(config.spec.seconds_per_slot);
            //TODO: Handle checked add correctly
            Interval::new(
                Instant::now() + service.duration_to_next_slot,
                slot_duration,
            )
        };

        /* kick off core service */

        // generate keypairs

        // TODO: keypairs are randomly generated; they should be loaded from a file or generated.
        // https://github.com/sigp/lighthouse/issues/160
        let keypairs = Arc::new(vec![Keypair::random()]);

        /* build requisite objects to pass to core thread */

        // Builds a mapping of Epoch -> Map(PublicKey, EpochDuty)
        // where EpochDuty contains slot numbers and attestation data that each validator needs to
        // produce work on.
        let duties_map = RwLock::new(EpochDutiesMap::new(config.spec.slots_per_epoch));

        // builds a manager which maintains the list of current duties for all known validators
        // and can check when a validator needs to perform a task.
        let manager = Arc::new(DutiesManager {
            duties_map,
            pubkeys: keypairs.iter().map(|keypair| keypair.pk.clone()).collect(),
            beacon_node: service.validator_client.clone(),
        });

        // run the core thread
        runtime
            .block_on(interval.for_each(move |_| {
                let log = service.log.clone();

                /* get the current slot and epoch */
                let current_slot = match service.slot_clock.present_slot() {
                    Err(e) => {
                        error!(log, "SystemTimeError {:?}", e);
                        return Ok(());
                    }
                    Ok(slot) => slot.expect("Genesis is in the future"),
                };

                let current_epoch = current_slot.epoch(service.slots_per_epoch);

                debug_assert!(
                    current_slot > service.current_slot,
                    "The Timer should poll a new slot"
                );

                info!(log, "Processing slot: {}", current_slot.as_u64());

                /* check for new duties */

                let cloned_manager = manager.clone();
                tokio::spawn(futures::future::poll_fn(move || {
                    cloned_manager.run_update(current_epoch.clone(), log.clone())
                }));

                /* execute any specified duties */

                if let Some(work) = manager.get_current_work(current_slot) {
                    for (_public_key, work_type) in work {
                        if work_type.produce_block {
                            // TODO: Produce a beacon block in a new thread
                        }
                        if work_type.attestation_duty.is_some() {
                            // available AttestationDuty info
                            let attestation_duty =
                                work_type.attestation_duty.expect("Cannot be None");
                            //TODO: Produce an attestation in a new thread
                        }
                    }
                }

                Ok(())
            }))
            .map_err(|e| format!("Service thread failed: {:?}", e))?;

        // completed a slot process
        Ok(())
    }

    /*

    for keypair in keypairs {
        info!(self.log, "Starting validator services"; "validator" => keypair.pk.concatenated_hex_id());

        // Spawn a new thread to maintain the validator's `EpochDuties`.
        let duties_manager_thread = {
            let spec = spec.clone();
            let duties_map = duties_map.clone();
            let slot_clock = self.slot_clock.clone();
            let log = self.log.clone();
            let beacon_node = self.validator_client.clone();
            let pubkey = keypair.pk.clone();
            thread::spawn(move || {
                let manager = DutiesManager {
                    duties_map,
                    pubkey,
                    spec,
                    slot_clock,
                    beacon_node,
                };
                let mut duties_manager_service = DutiesManagerService {
                    manager,
                    poll_interval_millis,
                    log,
                };

                duties_manager_service.run();
            })
        };

        // Spawn a new thread to perform block production for the validator.
        let producer_thread = {
            let spec = spec.clone();
            let signer = Arc::new(BlockProposerLocalSigner::new(keypair.clone()));
            let duties_map = duties_map.clone();
            let slot_clock = slot_clock.clone();
            let log = log.clone();
            let client = Arc::new(BeaconBlockGrpcClient::new(beacon_block_grpc_client.clone()));
            thread::spawn(move || {
                let block_producer =
                    BlockProducer::new(spec, duties_map, slot_clock, client, signer);
                let mut block_producer_service = BlockProducerService {
                    block_producer,
                    poll_interval_millis,
                    log,
                };

                block_producer_service.run();
            })
        };

        // Spawn a new thread for attestation for the validator.
        let attester_thread = {
            let signer = Arc::new(AttesterLocalSigner::new(keypair.clone()));
            let epoch_map = epoch_map_for_attester.clone();
            let slot_clock = slot_clock.clone();
            let log = log.clone();
            let client = Arc::new(AttestationGrpcClient::new(attester_grpc_client.clone()));
            thread::spawn(move || {
                let attester = Attester::new(epoch_map, slot_clock, client, signer);
                let mut attester_service = AttesterService {
                    attester,
                    poll_interval_millis,
                    log,
                };

                attester_service.run();
            })
        };

        threads.push((duties_manager_thread, producer_thread, attester_thread));
    }

    // Naively wait for all the threads to complete.
    for tuple in threads {
        let (manager, producer, attester) = tuple;
        let _ = producer.join();
        let _ = manager.join();
        let _ = attester.join();
    }
    */
}
<commit_msg>Added deterministic key generation for testing purposes.<commit_after>/// The validator service. Connects to a beacon node and signs blocks when required.
use crate::attester_service::{AttestationGrpcClient, AttesterService};
use crate::block_producer_service::{BeaconBlockGrpcClient, BlockProducerService};
use crate::config::Config as ValidatorConfig;
use crate::duties::UpdateOutcome;
use crate::duties::{DutiesManager, EpochDutiesMap};
use crate::error as error_chain;
use crate::error::ErrorKind;
use attester::test_utils::EpochMap;
use attester::{test_utils::LocalSigner as AttesterLocalSigner, Attester};
use block_proposer::{test_utils::LocalSigner as BlockProposerLocalSigner, BlockProducer};
use bls::Keypair;
use grpcio::{ChannelBuilder, EnvBuilder};
use protos::services::Empty;
use protos::services_grpc::{
    AttestationServiceClient, BeaconBlockServiceClient, BeaconNodeServiceClient,
    ValidatorServiceClient,
};
use slog::{debug, error, info, warn};
use slot_clock::{SlotClock, SystemTimeSlotClock};
use std::sync::Arc;
use std::sync::RwLock;
use std::time::{Duration, Instant, SystemTime};
use tokio::prelude::*;
use tokio::runtime::Builder;
use tokio::timer::Interval;
use tokio_timer::clock::Clock;
use types::{Epoch, Fork, Slot};
use types::test_utils::generate_deterministic_keypairs;

//TODO: This service should be simplified in the future. Can be made more steamlined.

/// The validator service. This is the main thread that executes and maintains validator
/// duties.
pub struct Service {
    /// The node we currently connected to.
    connected_node_version: String,
    /// The chain id we are processing on.
    chain_id: u16,
    /// The fork state we processing on.
    fork: Fork,
    /// The slot clock for this service.
    slot_clock: SystemTimeSlotClock,
    /// The current slot we are processing.
    current_slot: Slot,
    /// Duration until the next slot. This is used for initializing the tokio timer interval.
    duration_to_next_slot: Duration,
    /// The number of slots per epoch to allow for converting slots to epochs.
    slots_per_epoch: u64,
    // GRPC Clients
    /// The beacon block GRPC client.
    beacon_block_client: Arc<BeaconBlockServiceClient>,
    /// The validator GRPC client.
    validator_client: Arc<ValidatorServiceClient>,
    /// The attester GRPC client.
    attester_client: Arc<AttestationServiceClient>,
    /// The validator client logger.
    log: slog::Logger,
}

impl Service {
    ///  Initial connection to the beacon node to determine its properties.
    ///
    ///  This tries to connect to a beacon node. Once connected, it initialised the gRPC clients
    ///  and returns an instance of the service.
    fn initialize_service(
        config: &ValidatorConfig,
        log: slog::Logger,
    ) -> error_chain::Result<Self> {
        // initialise the beacon node client to check for a connection

        let env = Arc::new(EnvBuilder::new().build());
        // Beacon node gRPC beacon node endpoints.
        let beacon_node_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(BeaconNodeServiceClient::new(ch))
        };

        // retrieve node information
        let node_info = loop {
            match beacon_node_client.info(&Empty::new()) {
                Err(e) => {
                    warn!(log, "Could not connect to node. Error: {}", e);
                    info!(log, "Retrying in 5 seconds...");
                    std::thread::sleep(Duration::from_secs(5));
                    continue;
                }
                Ok(info) => {
                    if SystemTime::now()
                        .duration_since(SystemTime::UNIX_EPOCH)
                        .unwrap()
                        .as_secs()
                        < info.genesis_time
                    {
                        warn!(
                            log,
                            "Beacon Node's genesis time is in the future. No work to do.\n Exiting"
                        );
                        return Err("Genesis time in the future".into());
                    }
                    break info;
                }
            };
        };

        // build requisite objects to form Self
        let genesis_time = node_info.get_genesis_time();

        info!(log,"Beacon node connected"; "Node Version" => node_info.version.clone(), "Chain ID" => node_info.chain_id, "Genesis time" => genesis_time);

        let proto_fork = node_info.get_fork();
        let mut previous_version: [u8; 4] = [0; 4];
        let mut current_version: [u8; 4] = [0; 4];
        previous_version.copy_from_slice(&proto_fork.get_previous_version()[..4]);
        current_version.copy_from_slice(&proto_fork.get_current_version()[..4]);
        let fork = Fork {
            previous_version,
            current_version,
            epoch: Epoch::from(proto_fork.get_epoch()),
        };

        // initialize the RPC clients

        // Beacon node gRPC beacon block endpoints.
        let beacon_block_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(BeaconBlockServiceClient::new(ch))
        };

        // Beacon node gRPC validator endpoints.
        let validator_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(ValidatorServiceClient::new(ch))
        };

        //Beacon node gRPC attester endpoints.
        let attester_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(AttestationServiceClient::new(ch))
        };

        // build the validator slot clock
        let slot_clock = SystemTimeSlotClock::new(genesis_time, config.spec.seconds_per_slot)
            .expect("Unable to instantiate SystemTimeSlotClock.");

        let current_slot = slot_clock
            .present_slot()
            .map_err(|e| ErrorKind::SlotClockError(e))?
            .expect("Genesis must be in the future");

        // calculate the duration to the next slot
        let duration_to_next_slot = {
            let seconds_per_slot = config.spec.seconds_per_slot;
            let syslot_time = SystemTime::now();
            let duration_since_epoch = syslot_time
                .duration_since(SystemTime::UNIX_EPOCH)
                .map_err(|e| ErrorKind::SystemTimeError(e.to_string()))?;
            let duration_since_genesis = duration_since_epoch
                .checked_sub(Duration::from_secs(genesis_time))
                .expect("Genesis must be in the future. Checked on connection");
            let elapsed_slots = duration_since_epoch
                .as_secs()
                .checked_div(seconds_per_slot as u64)
                .expect("Seconds per slot should not be 0");

            // the duration to the next slot
            Duration::from_secs(
                (elapsed_slots + 1)
                    .checked_mul(seconds_per_slot)
                    .expect("Next slot time should not overflow u64"),
            )
            .checked_sub(duration_since_genesis)
            .expect("This should never saturate")
        };

        Ok(Self {
            connected_node_version: node_info.version,
            chain_id: node_info.chain_id as u16,
            fork,
            slot_clock,
            current_slot,
            duration_to_next_slot,
            slots_per_epoch: config.spec.slots_per_epoch,
            beacon_block_client,
            validator_client,
            attester_client,
            log,
        })
    }

    /// Initialise the service then run the core thread.
    pub fn start(config: ValidatorConfig, log: slog::Logger) -> error_chain::Result<()> {
        // connect to the node and retrieve its properties and initialize the gRPC clients
        let service = Service::initialize_service(&config, log)?;

        // we have connected to a node and established its parameters. Spin up the core service

        // set up the validator service runtime
        let mut runtime = Builder::new()
            .clock(Clock::system())
            .name_prefix("validator-client-")
            .build()
            .map_err(|e| format!("Tokio runtime failed: {}", e))?;

        // set up the validator work interval - start at next slot and proceed every slot
        let interval = {
            // Set the interval to start at the next slot, and every slot after
            let slot_duration = Duration::from_secs(config.spec.seconds_per_slot);
            //TODO: Handle checked add correctly
            Interval::new(
                Instant::now() + service.duration_to_next_slot,
                slot_duration,
            )
        };

        /* kick off core service */

        // generate keypairs

        // TODO: keypairs are randomly generated; they should be loaded from a file or generated.
        // https://github.com/sigp/lighthouse/issues/160
        let keypairs = generate_deterministic_keypairs(8);

        /* build requisite objects to pass to core thread */

        // Builds a mapping of Epoch -> Map(PublicKey, EpochDuty)
        // where EpochDuty contains slot numbers and attestation data that each validator needs to
        // produce work on.
        let duties_map = RwLock::new(EpochDutiesMap::new(config.spec.slots_per_epoch));

        // builds a manager which maintains the list of current duties for all known validators
        // and can check when a validator needs to perform a task.
        let manager = Arc::new(DutiesManager {
            duties_map,
            pubkeys: keypairs.iter().map(|keypair| keypair.pk.clone()).collect(),
            beacon_node: service.validator_client.clone(),
        });

        // run the core thread
        runtime
            .block_on(interval.for_each(move |_| {
                let log = service.log.clone();

                /* get the current slot and epoch */
                let current_slot = match service.slot_clock.present_slot() {
                    Err(e) => {
                        error!(log, "SystemTimeError {:?}", e);
                        return Ok(());
                    }
                    Ok(slot) => slot.expect("Genesis is in the future"),
                };

                let current_epoch = current_slot.epoch(service.slots_per_epoch);

                debug_assert!(
                    current_slot > service.current_slot,
                    "The Timer should poll a new slot"
                );

                info!(log, "Processing slot: {}", current_slot.as_u64());

                /* check for new duties */

                let cloned_manager = manager.clone();
                tokio::spawn(futures::future::poll_fn(move || {
                    cloned_manager.run_update(current_epoch.clone(), log.clone())
                }));

                /* execute any specified duties */

                if let Some(work) = manager.get_current_work(current_slot) {
                    for (_public_key, work_type) in work {
                        if work_type.produce_block {
                            // TODO: Produce a beacon block in a new thread
                        }
                        if work_type.attestation_duty.is_some() {
                            // available AttestationDuty info
                            let attestation_duty =
                                work_type.attestation_duty.expect("Cannot be None");
                            //TODO: Produce an attestation in a new thread
                        }
                    }
                }

                Ok(())
            }))
            .map_err(|e| format!("Service thread failed: {:?}", e))?;

        // completed a slot process
        Ok(())
    }

    /*

    for keypair in keypairs {
        info!(self.log, "Starting validator services"; "validator" => keypair.pk.concatenated_hex_id());

        // Spawn a new thread to maintain the validator's `EpochDuties`.
        let duties_manager_thread = {
            let spec = spec.clone();
            let duties_map = duties_map.clone();
            let slot_clock = self.slot_clock.clone();
            let log = self.log.clone();
            let beacon_node = self.validator_client.clone();
            let pubkey = keypair.pk.clone();
            thread::spawn(move || {
                let manager = DutiesManager {
                    duties_map,
                    pubkey,
                    spec,
                    slot_clock,
                    beacon_node,
                };
                let mut duties_manager_service = DutiesManagerService {
                    manager,
                    poll_interval_millis,
                    log,
                };

                duties_manager_service.run();
            })
        };

        // Spawn a new thread to perform block production for the validator.
        let producer_thread = {
            let spec = spec.clone();
            let signer = Arc::new(BlockProposerLocalSigner::new(keypair.clone()));
            let duties_map = duties_map.clone();
            let slot_clock = slot_clock.clone();
            let log = log.clone();
            let client = Arc::new(BeaconBlockGrpcClient::new(beacon_block_grpc_client.clone()));
            thread::spawn(move || {
                let block_producer =
                    BlockProducer::new(spec, duties_map, slot_clock, client, signer);
                let mut block_producer_service = BlockProducerService {
                    block_producer,
                    poll_interval_millis,
                    log,
                };

                block_producer_service.run();
            })
        };

        // Spawn a new thread for attestation for the validator.
        let attester_thread = {
            let signer = Arc::new(AttesterLocalSigner::new(keypair.clone()));
            let epoch_map = epoch_map_for_attester.clone();
            let slot_clock = slot_clock.clone();
            let log = log.clone();
            let client = Arc::new(AttestationGrpcClient::new(attester_grpc_client.clone()));
            thread::spawn(move || {
                let attester = Attester::new(epoch_map, slot_clock, client, signer);
                let mut attester_service = AttesterService {
                    attester,
                    poll_interval_millis,
                    log,
                };

                attester_service.run();
            })
        };

        threads.push((duties_manager_thread, producer_thread, attester_thread));
    }

    // Naively wait for all the threads to complete.
    for tuple in threads {
        let (manager, producer, attester) = tuple;
        let _ = producer.join();
        let _ = manager.join();
        let _ = attester.join();
    }
    */
}
<|endoftext|>


<commit_before>//! A simple example which prints out information about available Metal devices

extern crate mtl;

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
fn main() {
    println!("Metal is not supported on this platform");
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
fn main() {
    let devices = mtl::Device::enumerate_all_system_devices();

    let num_devices_message = format!("Number of system devices: {}", devices.len());
    let separator = std::iter::repeat('=').take(num_devices_message.len())
                                          .collect::<String>();

    println!("{}", num_devices_message);
    println!("{}", separator);
    println!("");

    for (index, device) in devices.into_iter().enumerate() {
        println!("Device {} info:", index);
        let device = match device {
            Ok(device) => device,
            Err(e) => {
                use std::error::Error;
                println!("{}", e.description());
                break;
            }
        };

        println!("Name:\t\t\t\t\t\t{}", device.name());
        println!("Supports 24 bit stencil and 8 bit depth:\t{}",
                 device.is_depth24_stencil8_pixel_format_supported());
        {
            let max_tpg = device.max_threads_per_group();
            println!("Maximum threads per group:\t\t\t({}, {}, {})",
                     max_tpg.width,
                     max_tpg.height,
                     max_tpg.depth);
        }
        println!("Is low power:\t\t\t\t\t{}", device.is_low_power());
        println!("Is headless:\t\t\t\t\t{}", device.is_headless());
        println!("");
    }
}
<commit_msg>rustfmt<commit_after>//! A simple example which prints out information about available Metal devices

extern crate mtl;

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
fn main() {
    println!("Metal is not supported on this platform");
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
fn main() {
    let devices = mtl::Device::enumerate_all_system_devices();

    let num_devices_message = format!("Number of system devices: {}", devices.len());
    let separator = std::iter::repeat('=')
                        .take(num_devices_message.len())
                        .collect::<String>();

    println!("{}", num_devices_message);
    println!("{}", separator);
    println!("");

    for (index, device) in devices.into_iter().enumerate() {
        println!("Device {} info:", index);
        let device = match device {
            Ok(device) => device,
            Err(e) => {
                use std::error::Error;
                println!("{}", e.description());
                break;
            }
        };

        println!("Name:\t\t\t\t\t\t{}", device.name());
        println!("Supports 24 bit stencil and 8 bit depth:\t{}",
                 device.is_depth24_stencil8_pixel_format_supported());
        {
            let max_tpg = device.max_threads_per_group();
            println!("Maximum threads per group:\t\t\t({}, {}, {})",
                     max_tpg.width,
                     max_tpg.height,
                     max_tpg.depth);
        }
        println!("Is low power:\t\t\t\t\t{}", device.is_low_power());
        println!("Is headless:\t\t\t\t\t{}", device.is_headless());
        println!("");
    }
}
<|endoftext|>


<commit_before>extern crate quickcheck;

use quickcheck::quickcheck;

fn reverse<T: Clone>(xs: &[T]) -> Vec<T> {
    let mut rev = vec!();
    for x in xs.iter() {
        rev.unshift(x.clone())
    }
    rev
}

fn main() {
    fn prop(xs: Vec<int>) -> bool {
        xs == reverse(reverse(xs.as_slice()).as_slice())
    }
    quickcheck(prop);
}
<commit_msg>Better name for the property<commit_after>extern crate quickcheck;

use quickcheck::quickcheck;

fn reverse<T: Clone>(xs: &[T]) -> Vec<T> {
    let mut rev = vec!();
    for x in xs.iter() {
        rev.unshift(x.clone())
    }
    rev
}

fn main() {
    fn equality_after_applying_twice(xs: Vec<int>) -> bool {
        xs == reverse(reverse(xs.as_slice()).as_slice())
    }
    quickcheck(equality_after_applying_twice);
}
<|endoftext|>


<commit_before>use geohash::interval::*;
use geohash::*;
use std::str;

pub fn encode(lat:f64, lon:f64, precision:uint) -> ~str {
  let mut ilat = Interval{ lo:-MAX_LAT, hi:MAX_LAT };
  let mut ilon = Interval{ lo:-MAX_LON, hi:MAX_LON };

  let bit_count : uint    = 5 * precision;
  let mut bits: ~[bool]   = ~[];
  let mut result: ~[char] = ~[];

  for i in range(0, bit_count) {
    if i.is_even() {
      let is_higher = lon > ilon.median();
      bits.push(is_higher);
      ilon.contract(if is_higher {UpperHalf} else {LowerHalf});
    } else {
      let is_higher = lat > ilat.median();
      bits.push(is_higher);
      ilat.contract(if is_higher {UpperHalf} else {LowerHalf});
    }
  }

  for char_bits in bits.chunk_iter(5) {
    let result_char = base32::encode_vec(char_bits).unwrap();
    result.push(result_char);
  }

  str::from_chars(result)
}

#[test]
fn test_encode_good() {
  let lat = 57.649109959602356;
  let lon = 10.407439023256302;

  assert!( Geohash::encode(lat, lon, 2)  == ~"u4" );
  assert!( Geohash::encode(lat, lon, 4)  == ~"u4pr" );
  assert!( Geohash::encode(lat, lon, 6)  == ~"u4pruy" );
  assert!( Geohash::encode(lat, lon, 8)  == ~"u4pruydq" );
}<commit_msg>Fixes encoding by using >= instead of ><commit_after>use geohash::interval::*;
use geohash::*;
use std::str;

pub fn encode(lat:f64, lon:f64, precision:uint) -> ~str {
  let mut ilat = Interval{ lo:-MAX_LAT, hi:MAX_LAT };
  let mut ilon = Interval{ lo:-MAX_LON, hi:MAX_LON };

  let bit_count : uint    = 5 * precision;
  let mut bits: ~[bool]   = ~[];
  let mut result: ~[char] = ~[];

  for i in range(0, bit_count) {
    if i.is_even() {
      let is_higher = lon >= ilon.median();
      bits.push(is_higher);
      ilon.contract(if is_higher {UpperHalf} else {LowerHalf});
    } else {
      let is_higher = lat >= ilat.median();
      bits.push(is_higher);
      ilat.contract(if is_higher {UpperHalf} else {LowerHalf});
    }
  }

  for char_bits in bits.chunk_iter(5) {
    let result_char = base32::encode_vec(char_bits).unwrap();
    result.push(result_char);
  }

  str::from_chars(result)
}

#[test]
fn test_encode_good() {
  let lat = 57.649109959602356;
  let lon = 10.407439023256302;

  assert!( Geohash::encode(lat, lon, 2)  == ~"u4" );
  assert!( Geohash::encode(lat, lon, 4)  == ~"u4pr" );
  assert!( Geohash::encode(lat, lon, 6)  == ~"u4pruy" );
  assert!( Geohash::encode(lat, lon, 8)  == ~"u4pruydq" );
  assert!( Geohash::encode(lat, lon, 10) == ~"u4pruydqqv" );
  assert!( Geohash::encode(lat, lon, 11) == ~"u4pruydqqvj" );
}<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Image whose purpose is to be used as a framebuffer attachment.
//!
//! This module declares the `AttachmentImage` type. It is a safe wrapper around `UnsafeImage`
//! and implements all the relevant image traits.
//!
//! The image is always two-dimensional and has only one mipmap, but it can have any kind of
//! format. Trying to use a format that the backend doesn't support for rendering will result in
//! an error being returned when creating the image. Once you have an `AttachmentImage`, you are
//! guaranteed that you will be able to draw on it.
//!
//! The template parameter of `AttachmentImage` is a type that describes the format of the image.
//!
//! # Regular vs transient
//!
//! Calling `AttachmentImage::new` will create a regular image, while calling
//! `AttachmentImage::transient` will create a *transient* image.
//!
//! A transient image is a special kind of image whose content is undefined outside of render
//! passes. Once you finish drawing, you can't read from it anymore.
//!
//! This gives a hint to the Vulkan implementation that it is possible for the image's content to
//! live exclusively in some cache memory, and that no real memory has to be allocated for it.
//!
//! In other words, if you are going to read from the image after drawing to it, use a regular
//! image. If you don't need to read from it (for example if it's some kind of intermediary color,
//! or a depth buffer that is only used once) then use a transient image.
//!
use std::mem;
use std::iter::Empty;
use std::ops::Range;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::Weak;

use command_buffer::Submission;
use device::Device;
use format::ClearValue;
use format::FormatDesc;
use format::FormatTy;
use image::sys::Dimensions;
use image::sys::ImageCreationError;
use image::sys::Layout;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use image::sys::Usage;
use image::traits::AccessRange;
use image::traits::GpuAccessResult;
use image::traits::Image;
use image::traits::ImageClearValue;
use image::traits::ImageContent;
use image::traits::ImageView;
use image::traits::Transition;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::Sharing;

/// Image whose purpose is to be used as a framebuffer attachment.
#[derive(Debug)]
pub struct AttachmentImage<F, A = StdMemoryPool> where A: MemoryPool {
    // Inner implementation.
    image: UnsafeImage,

    // We maintain a view of the whole image since we will need it when rendering.
    view: UnsafeImageView,

    // Memory used to back the image.
    memory: A::Alloc,

    // Format.
    format: F,

    // Layout to use when the image is used as a framebuffer attachment.
    // Should be either "depth-stencil optimal" or "color optimal".
    attachment_layout: Layout,

    // Additional info behind a mutex.
    guarded: Mutex<Guarded>,
}

#[derive(Debug)]
struct Guarded {
    // If false, the image is still in the undefined layout.
    correct_layout: bool,

    // The latest submission that used the image. Used for synchronization purposes.
    latest_submission: Option<Weak<Submission>>,    // TODO: can use `Weak::new()` once it's stabilized
}

impl<F> AttachmentImage<F> {
    /// Creates a new image with the given dimensions and format.
    ///
    /// Returns an error if the dimensions are too large or if the backend doesn't support this
    /// format as a framebuffer attachment.
    pub fn new(device: &Arc<Device>, dimensions: [u32; 2], format: F)
               -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
        where F: FormatDesc
    {
        let usage = Usage {
            transfer_source: true,
            sampled: true,
            .. Usage::none()
        };

        AttachmentImage::new_impl(device, dimensions, format, usage)
    }

    /// Same as `new`, except that the image will be transient.
    ///
    /// A transient image is special because its content is undefined outside of a render pass.
    /// This means that the implementation has the possibility to not allocate any memory for it.
    pub fn transient(device: &Arc<Device>, dimensions: [u32; 2], format: F)
                     -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
        where F: FormatDesc
    {
        let usage = Usage {
            transient_attachment: true,
            .. Usage::none()
        };

        AttachmentImage::new_impl(device, dimensions, format, usage)
    }

    fn new_impl(device: &Arc<Device>, dimensions: [u32; 2], format: F, usage: Usage)
                -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
        where F: FormatDesc
    {
        let is_depth = match format.format().ty() {
            FormatTy::Depth => true,
            FormatTy::DepthStencil => true,
            FormatTy::Compressed => panic!(),
            _ => false
        };

        let usage = Usage {
            color_attachment: !is_depth,
            depth_stencil_attachment: is_depth,
            input_attachment: true,
            .. usage
        };

        let (image, mem_reqs) = unsafe {
            try!(UnsafeImage::new(device, &usage, format.format(),
                                  Dimensions::Dim2d { width: dimensions[0], height: dimensions[1] },
                                  1, 1, Sharing::Exclusive::<Empty<u32>>, false, false))
        };

        let mem_ty = {
            let device_local = device.physical_device().memory_types()
                                     .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
                                     .filter(|t| t.is_device_local());
            let any = device.physical_device().memory_types()
                            .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0);
            device_local.chain(any).next().unwrap()
        };

        let mem = try!(MemoryPool::alloc(&device.standard_pool(), mem_ty,
                                         mem_reqs.size, mem_reqs.alignment));
        debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
        unsafe { try!(image.bind_memory(mem.memory(), mem.offset())); }

        let view = unsafe {
            try!(UnsafeImageView::raw(&image, 0 .. 1, 0 .. 1))
        };

        Ok(Arc::new(AttachmentImage {
            image: image,
            view: view,
            memory: mem,
            format: format,
            attachment_layout: if is_depth { Layout::DepthStencilAttachmentOptimal }
                               else { Layout::ColorAttachmentOptimal },
            guarded: Mutex::new(Guarded {
                correct_layout: false,
                latest_submission: None,
            }),
        }))
    }
}

impl<F, A> AttachmentImage<F, A> where A: MemoryPool {
    /// Returns the dimensions of the image.
    #[inline]
    pub fn dimensions(&self) -> [u32; 2] {
        let dims = self.image.dimensions();
        [dims.width(), dims.height()]
    }
}

unsafe impl<F, A> Image for AttachmentImage<F, A> where F: 'static + Send + Sync, A: MemoryPool {
    #[inline]
    fn inner_image(&self) -> &UnsafeImage {
        &self.image
    }

    #[inline]
    fn blocks(&self, _: Range<u32>, _: Range<u32>) -> Vec<(u32, u32)> {
        vec![(0, 0)]
    }

    #[inline]
    fn block_mipmap_levels_range(&self, block: (u32, u32)) -> Range<u32> {
        0 .. 1
    }

    #[inline]
    fn block_array_layers_range(&self, block: (u32, u32)) -> Range<u32> {
        0 .. 1
    }

    #[inline]
    fn initial_layout(&self, _: (u32, u32), _: Layout) -> (Layout, bool, bool) {
        (self.attachment_layout, false, false)
    }

    #[inline]
    fn final_layout(&self, _: (u32, u32), _: Layout) -> (Layout, bool, bool) {
        (self.attachment_layout, false, false)
    }

    fn needs_fence(&self, access: &mut Iterator<Item = AccessRange>) -> Option<bool> {
        Some(false)
    }

    unsafe fn gpu_access(&self, _: &mut Iterator<Item = AccessRange>,
                         submission: &Arc<Submission>) -> GpuAccessResult
    {
        let mut guarded = self.guarded.lock().unwrap();

        let dependency = mem::replace(&mut guarded.latest_submission, Some(Arc::downgrade(submission)));
        let dependency = dependency.and_then(|d| d.upgrade());

        let transition = if !guarded.correct_layout {
            vec![Transition {
                block: (0, 0),
                from: Layout::Undefined,
                to: self.attachment_layout,
            }]
        } else {
            vec![]
        };

        guarded.correct_layout = true;

        GpuAccessResult {
            dependencies: if let Some(dependency) = dependency {
                vec![dependency]
            } else {
                vec![]
            },
            additional_wait_semaphore: None,
            additional_signal_semaphore: None,
            before_transitions: transition,
            after_transitions: vec![],
        }
    }
}

unsafe impl<F, A> ImageClearValue<F::ClearValue> for AttachmentImage<F, A>
    where F: FormatDesc + 'static + Send + Sync, A: MemoryPool
{
    #[inline]
    fn decode(&self, value: F::ClearValue) -> Option<ClearValue> {
        Some(self.format.decode_clear_value(value))
    }
}

unsafe impl<P, F, A> ImageContent<P> for AttachmentImage<F, A>
    where F: 'static + Send + Sync, A: MemoryPool
{
    #[inline]
    fn matches_format(&self) -> bool {
        true        // FIXME:
    }
}

unsafe impl<F, A> ImageView for AttachmentImage<F, A>
    where F: 'static + Send + Sync, A: MemoryPool
{
    #[inline]
    fn parent(&self) -> &Image {
        self
    }

    #[inline]
    fn parent_arc(me: &Arc<Self>) -> Arc<Image> where Self: Sized {
        me.clone() as Arc<_>
    }

    #[inline]
    fn blocks(&self) -> Vec<(u32, u32)> {
        vec![(0, 0)]
    }

    #[inline]
    fn inner_view(&self) -> &UnsafeImageView {
        &self.view
    }

    #[inline]
    fn descriptor_set_storage_image_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_sampled_image_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_input_attachment_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn identity_swizzle(&self) -> bool {
        true
    }
}

#[cfg(test)]
mod tests {
    use super::AttachmentImage;
    use format::Format;

    #[test]
    fn create_regular() {
        let (device, _) = gfx_dev_and_queue!();
        let _img = AttachmentImage::new(&device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
    }

    #[test]
    fn create_transient() {
        let (device, _) = gfx_dev_and_queue!();
        let _img = AttachmentImage::transient(&device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
    }
}
<commit_msg>Add transfer_dest for AttachmentImage<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Image whose purpose is to be used as a framebuffer attachment.
//!
//! This module declares the `AttachmentImage` type. It is a safe wrapper around `UnsafeImage`
//! and implements all the relevant image traits.
//!
//! The image is always two-dimensional and has only one mipmap, but it can have any kind of
//! format. Trying to use a format that the backend doesn't support for rendering will result in
//! an error being returned when creating the image. Once you have an `AttachmentImage`, you are
//! guaranteed that you will be able to draw on it.
//!
//! The template parameter of `AttachmentImage` is a type that describes the format of the image.
//!
//! # Regular vs transient
//!
//! Calling `AttachmentImage::new` will create a regular image, while calling
//! `AttachmentImage::transient` will create a *transient* image.
//!
//! A transient image is a special kind of image whose content is undefined outside of render
//! passes. Once you finish drawing, you can't read from it anymore.
//!
//! This gives a hint to the Vulkan implementation that it is possible for the image's content to
//! live exclusively in some cache memory, and that no real memory has to be allocated for it.
//!
//! In other words, if you are going to read from the image after drawing to it, use a regular
//! image. If you don't need to read from it (for example if it's some kind of intermediary color,
//! or a depth buffer that is only used once) then use a transient image.
//!
use std::mem;
use std::iter::Empty;
use std::ops::Range;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::Weak;

use command_buffer::Submission;
use device::Device;
use format::ClearValue;
use format::FormatDesc;
use format::FormatTy;
use image::sys::Dimensions;
use image::sys::ImageCreationError;
use image::sys::Layout;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use image::sys::Usage;
use image::traits::AccessRange;
use image::traits::GpuAccessResult;
use image::traits::Image;
use image::traits::ImageClearValue;
use image::traits::ImageContent;
use image::traits::ImageView;
use image::traits::Transition;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::Sharing;

/// Image whose purpose is to be used as a framebuffer attachment.
#[derive(Debug)]
pub struct AttachmentImage<F, A = StdMemoryPool> where A: MemoryPool {
    // Inner implementation.
    image: UnsafeImage,

    // We maintain a view of the whole image since we will need it when rendering.
    view: UnsafeImageView,

    // Memory used to back the image.
    memory: A::Alloc,

    // Format.
    format: F,

    // Layout to use when the image is used as a framebuffer attachment.
    // Should be either "depth-stencil optimal" or "color optimal".
    attachment_layout: Layout,

    // Additional info behind a mutex.
    guarded: Mutex<Guarded>,
}

#[derive(Debug)]
struct Guarded {
    // If false, the image is still in the undefined layout.
    correct_layout: bool,

    // The latest submission that used the image. Used for synchronization purposes.
    latest_submission: Option<Weak<Submission>>,    // TODO: can use `Weak::new()` once it's stabilized
}

impl<F> AttachmentImage<F> {
    /// Creates a new image with the given dimensions and format.
    ///
    /// Returns an error if the dimensions are too large or if the backend doesn't support this
    /// format as a framebuffer attachment.
    pub fn new(device: &Arc<Device>, dimensions: [u32; 2], format: F)
               -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
        where F: FormatDesc
    {
        let usage = Usage {
            transfer_source: true,
            transfer_dest: true,
            sampled: true,
            .. Usage::none()
        };

        AttachmentImage::new_impl(device, dimensions, format, usage)
    }

    /// Same as `new`, except that the image will be transient.
    ///
    /// A transient image is special because its content is undefined outside of a render pass.
    /// This means that the implementation has the possibility to not allocate any memory for it.
    pub fn transient(device: &Arc<Device>, dimensions: [u32; 2], format: F)
                     -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
        where F: FormatDesc
    {
        let usage = Usage {
            transient_attachment: true,
            .. Usage::none()
        };

        AttachmentImage::new_impl(device, dimensions, format, usage)
    }

    fn new_impl(device: &Arc<Device>, dimensions: [u32; 2], format: F, usage: Usage)
                -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
        where F: FormatDesc
    {
        let is_depth = match format.format().ty() {
            FormatTy::Depth => true,
            FormatTy::DepthStencil => true,
            FormatTy::Compressed => panic!(),
            _ => false
        };

        let usage = Usage {
            color_attachment: !is_depth,
            depth_stencil_attachment: is_depth,
            input_attachment: true,
            .. usage
        };

        let (image, mem_reqs) = unsafe {
            try!(UnsafeImage::new(device, &usage, format.format(),
                                  Dimensions::Dim2d { width: dimensions[0], height: dimensions[1] },
                                  1, 1, Sharing::Exclusive::<Empty<u32>>, false, false))
        };

        let mem_ty = {
            let device_local = device.physical_device().memory_types()
                                     .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
                                     .filter(|t| t.is_device_local());
            let any = device.physical_device().memory_types()
                            .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0);
            device_local.chain(any).next().unwrap()
        };

        let mem = try!(MemoryPool::alloc(&device.standard_pool(), mem_ty,
                                         mem_reqs.size, mem_reqs.alignment));
        debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
        unsafe { try!(image.bind_memory(mem.memory(), mem.offset())); }

        let view = unsafe {
            try!(UnsafeImageView::raw(&image, 0 .. 1, 0 .. 1))
        };

        Ok(Arc::new(AttachmentImage {
            image: image,
            view: view,
            memory: mem,
            format: format,
            attachment_layout: if is_depth { Layout::DepthStencilAttachmentOptimal }
                               else { Layout::ColorAttachmentOptimal },
            guarded: Mutex::new(Guarded {
                correct_layout: false,
                latest_submission: None,
            }),
        }))
    }
}

impl<F, A> AttachmentImage<F, A> where A: MemoryPool {
    /// Returns the dimensions of the image.
    #[inline]
    pub fn dimensions(&self) -> [u32; 2] {
        let dims = self.image.dimensions();
        [dims.width(), dims.height()]
    }
}

unsafe impl<F, A> Image for AttachmentImage<F, A> where F: 'static + Send + Sync, A: MemoryPool {
    #[inline]
    fn inner_image(&self) -> &UnsafeImage {
        &self.image
    }

    #[inline]
    fn blocks(&self, _: Range<u32>, _: Range<u32>) -> Vec<(u32, u32)> {
        vec![(0, 0)]
    }

    #[inline]
    fn block_mipmap_levels_range(&self, block: (u32, u32)) -> Range<u32> {
        0 .. 1
    }

    #[inline]
    fn block_array_layers_range(&self, block: (u32, u32)) -> Range<u32> {
        0 .. 1
    }

    #[inline]
    fn initial_layout(&self, _: (u32, u32), _: Layout) -> (Layout, bool, bool) {
        (self.attachment_layout, false, false)
    }

    #[inline]
    fn final_layout(&self, _: (u32, u32), _: Layout) -> (Layout, bool, bool) {
        (self.attachment_layout, false, false)
    }

    fn needs_fence(&self, access: &mut Iterator<Item = AccessRange>) -> Option<bool> {
        Some(false)
    }

    unsafe fn gpu_access(&self, _: &mut Iterator<Item = AccessRange>,
                         submission: &Arc<Submission>) -> GpuAccessResult
    {
        let mut guarded = self.guarded.lock().unwrap();

        let dependency = mem::replace(&mut guarded.latest_submission, Some(Arc::downgrade(submission)));
        let dependency = dependency.and_then(|d| d.upgrade());

        let transition = if !guarded.correct_layout {
            vec![Transition {
                block: (0, 0),
                from: Layout::Undefined,
                to: self.attachment_layout,
            }]
        } else {
            vec![]
        };

        guarded.correct_layout = true;

        GpuAccessResult {
            dependencies: if let Some(dependency) = dependency {
                vec![dependency]
            } else {
                vec![]
            },
            additional_wait_semaphore: None,
            additional_signal_semaphore: None,
            before_transitions: transition,
            after_transitions: vec![],
        }
    }
}

unsafe impl<F, A> ImageClearValue<F::ClearValue> for AttachmentImage<F, A>
    where F: FormatDesc + 'static + Send + Sync, A: MemoryPool
{
    #[inline]
    fn decode(&self, value: F::ClearValue) -> Option<ClearValue> {
        Some(self.format.decode_clear_value(value))
    }
}

unsafe impl<P, F, A> ImageContent<P> for AttachmentImage<F, A>
    where F: 'static + Send + Sync, A: MemoryPool
{
    #[inline]
    fn matches_format(&self) -> bool {
        true        // FIXME:
    }
}

unsafe impl<F, A> ImageView for AttachmentImage<F, A>
    where F: 'static + Send + Sync, A: MemoryPool
{
    #[inline]
    fn parent(&self) -> &Image {
        self
    }

    #[inline]
    fn parent_arc(me: &Arc<Self>) -> Arc<Image> where Self: Sized {
        me.clone() as Arc<_>
    }

    #[inline]
    fn blocks(&self) -> Vec<(u32, u32)> {
        vec![(0, 0)]
    }

    #[inline]
    fn inner_view(&self) -> &UnsafeImageView {
        &self.view
    }

    #[inline]
    fn descriptor_set_storage_image_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_sampled_image_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_input_attachment_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn identity_swizzle(&self) -> bool {
        true
    }
}

#[cfg(test)]
mod tests {
    use super::AttachmentImage;
    use format::Format;

    #[test]
    fn create_regular() {
        let (device, _) = gfx_dev_and_queue!();
        let _img = AttachmentImage::new(&device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
    }

    #[test]
    fn create_transient() {
        let (device, _) = gfx_dev_and_queue!();
        let _img = AttachmentImage::transient(&device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
    }
}
<|endoftext|>