<commit_before>// Copyright 2012-2013 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 std::io;
use syntax::ast;
use syntax::print::pp;
use syntax::print::pprust;
use syntax::parse::token;

pub fn each_binding(l: @ast::Local, f: @fn(&ast::Path, ast::NodeId)) {
    use syntax::oldvisit;

    let vt = oldvisit::mk_simple_visitor(
        @oldvisit::SimpleVisitor {
            visit_pat: |pat| {
                match pat.node {
                    ast::pat_ident(_, ref path, _) => {
                        f(path, pat.id);
                    }
                    _ => {}
                }
            },
            .. *oldvisit::default_simple_visitor()
        }
    );
    (vt.visit_pat)(l.pat, ((), vt));
}

/// A utility function that hands off a pretty printer to a callback.
pub fn with_pp(intr: @token::ident_interner,
               cb: &fn(@pprust::ps, @io::Writer)) -> ~str {
    do io::with_str_writer |writer| {
        let pp = pprust::rust_printer(writer, intr);

        cb(pp, writer);
        pp::eof(pp.s);
    }
}
<commit_msg>Ported rusti::utils from oldvisit to <V:Visitor> trait API.<commit_after>// Copyright 2012-2013 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 std::io;
use syntax::ast;
use syntax::print::pp;
use syntax::print::pprust;
use syntax::parse::token;
use syntax::visit;

struct EachBindingVisitor {
    f: @fn(&ast::Path, ast::NodeId)
}

impl visit::Visitor<()> for EachBindingVisitor {
    fn visit_pat(&mut self, pat:@ast::pat, _:()) {
                match pat.node {
                    ast::pat_ident(_, ref path, _) => {
                        (self.f)(path, pat.id);
                    }
                    _ => {}
                }

                visit::walk_pat(self, pat, ());
    }
}

pub fn each_binding(l: @ast::Local, f: @fn(&ast::Path, ast::NodeId)) {
    use syntax::visit::Visitor;

    let mut vt = EachBindingVisitor{ f: f };

    vt.visit_pat(l.pat, ());
}

/// A utility function that hands off a pretty printer to a callback.
pub fn with_pp(intr: @token::ident_interner,
               cb: &fn(@pprust::ps, @io::Writer)) -> ~str {
    do io::with_str_writer |writer| {
        let pp = pprust::rust_printer(writer, intr);

        cb(pp, writer);
        pp::eof(pp.s);
    }
}
<|endoftext|>


<commit_before>use xpath_reader::{FromXml, FromXmlError, XpathReader};
use xpath_reader::reader::{FromXmlContained, FromXmlElement};

use entities::{Mbid, Resource};
use entities::date::PartialDate;

/// A label entity in the MusicBrainz database.
/// There is quite some controversy in the music industry what a 'label'
/// constitutes.
///
/// For a complete disambiguation see the `LabelType` enum. The labels in
/// MusicBrainz are mostly
/// imprints.
pub struct Label {
    /// MBID of the entity in the MusicBrainz database.
    pub mbid: Mbid,

    /// The official name of the label.
    pub name: String,

    /// Version of the `name` converted to latin characters for sorting.
    pub sort_name: String,

    /// If there are multiple labels with the same name in the database, a
    /// short disambiguation
    /// comment is provided which allows to differentiate the entities.
    pub disambiguation: Option<String>,

    /// Variants of the name mainly used as search help.
    /// These can be variants, spellings of names, missing titles and common
    /// misspellings.
    pub aliases: Vec<String>,

    /// LC code of the label, as issued by the IFPI.
    pub label_code: Option<String>,

    /// Describes the main activity of the label.
    pub label_type: LabelType,

    /// ISO 3166 country of origin for the label.
    pub country: Option<String>,

    /// Identifying number of the label as assigned by the CISAC database.
    pub ipi_code: Option<String>,

    /// ISNI code of the label.
    pub isni_code: Option<String>,

    /// The date when this label was founded.
    /// (Consult the MusicBrainz manual for disclaimers about the significance
    /// of these
    /// informations.)
    pub begin_date: Option<PartialDate>,

    /// The date when this label ceased to exist or its last release ever was
    /// released.
    pub end_date: Option<PartialDate>,
}

impl Resource for Label {
    fn get_name() -> &'static str
    {
        "Label"
    }

    fn get_url(mbid: &Mbid) -> String
    {
        format!("https://musicbrainz.org/ws/2/label/{}?inc=aliases", mbid)
    }

    fn base_url() -> &'static str
    {
        "https://musicbrainz.org/ws/2/label/"
    }
}

impl FromXmlContained for Label {}
impl FromXml for Label {
    fn from_xml<'d, R>(reader: &'d R) -> Result<Label, FromXmlError>
    where
        R: XpathReader<'d>,
    {
        Ok(Label {
            mbid: reader.read(".//mb:label/@id")?,
            name: reader.read(".//mb:label/mb:name/text()")?,
            sort_name: reader.read(".//mb:label/mb:sort-name/text()")?,
            disambiguation: reader.read_option(".//mb:label/mb:disambiguation/text()")?,
            aliases: reader.read_vec(".//mb:label/mb:alias-list/mb:alias/text()")?,
            label_code: reader.read_option(".//mb:label/mb:label-code/text()")?,
            label_type: reader.read(".//mb:label/@type")?,
            country: reader.read_option(".//mb:label/mb:country/text()")?,
            ipi_code: None, // TODO
            isni_code: None, // TODO
            begin_date: reader.read_option(".//mb:label/mb:life-span/mb:begin/text()")?,
            end_date: reader.read_option(".//mb:label/mb:life-span/mb:end/text()")?,
        })
    }
}

enum_mb_xml! {
    pub enum LabelType {
        /// The main `LabelType` in the MusicBrainz database.
        /// That is a brand (and trademark) associated with the marketing of a
        /// release.
        var Imprint = "Imprint",

        /// Production company producing entirely new releases.
        var ProductionOriginal = "Original Production",
        /// Known bootleg production companies, not sanctioned by the rights owners
        /// of the released
        /// work.
        var ProductionBootleg = "Bootleg Production",
        /// Companies specialized in catalog reissues.
        var ProductionReissue = "Reissue Production",

        /// Companies mainly distributing other labels production, often in a
        /// specfic region of the
        /// world.
        var Distribution = "Distribution",
        /// Holdings, conglomerates or other financial entities that don't mainly
        /// produce records but
        /// manage a large set of recording labels owned by them.
        var Holding = "Holding",
        /// An organization which collects royalties on behalf of the artists.
        var RightsSociety = "RightsSociety",
    }
}

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

    #[test]
    fn label_read_xml1()
    {
        let mbid = Mbid::from_str("c029628b-6633-439e-bcee-ed02e8a338f7").unwrap();
        let label: Label = ::util::test_utils::fetch_entity(&mbid).unwrap();

        assert_eq!(label.mbid, mbid);
        assert_eq!(label.name, "EMI".to_string());
        assert_eq!(label.sort_name, "EMI".to_string());
        assert_eq!(
            label.disambiguation,
            Some("EMI Records, since 1972".to_string())
        );
        assert_eq!(
            label.aliases,
            vec![
                "EMI".to_string(),
                "EMI Records (UK)".to_string(),
                "EMI Records Ltd".to_string(),
                "EMI UK".to_string(),
            ]
        );
        assert_eq!(label.label_code, Some("542".to_string()));
        assert_eq!(label.label_type, LabelType::ProductionOriginal);
        assert_eq!(label.country, Some("GB".to_string()));
        assert_eq!(label.ipi_code, None);
        assert_eq!(label.isni_code, None);
        assert_eq!(
            label.begin_date,
            Some(PartialDate::from_str("1972").unwrap())
        );
        assert_eq!(label.end_date, None);
    }

    #[test]
    fn read_aliases()
    {
        let mbid = Mbid::from_str("168f48c8-057e-4974-9600-aa9956d21e1a").unwrap();
        let label: Label = ::util::test_utils::fetch_entity(&mbid).unwrap();

        let mut expected = vec![
            "Avex Trax Japan".to_string(),
            "エイベックス・トラックス".to_string(),
        ];
        expected.sort();
        let mut actual = label.aliases.clone();
        actual.sort();

        assert_eq!(actual, expected);
    }
}
<commit_msg>Label types are optional<commit_after>use xpath_reader::{FromXml, FromXmlError, XpathReader};
use xpath_reader::reader::{FromXmlContained, FromXmlElement};

use entities::{Mbid, Resource};
use entities::date::PartialDate;

/// A label entity in the MusicBrainz database.
/// There is quite some controversy in the music industry what a 'label'
/// constitutes.
///
/// For a complete disambiguation see the `LabelType` enum. The labels in
/// MusicBrainz are mostly
/// imprints.
pub struct Label {
    /// MBID of the entity in the MusicBrainz database.
    pub mbid: Mbid,

    /// The official name of the label.
    pub name: String,

    /// Version of the `name` converted to latin characters for sorting.
    pub sort_name: String,

    /// If there are multiple labels with the same name in the database, a
    /// short disambiguation
    /// comment is provided which allows to differentiate the entities.
    pub disambiguation: Option<String>,

    /// Variants of the name mainly used as search help.
    /// These can be variants, spellings of names, missing titles and common
    /// misspellings.
    pub aliases: Vec<String>,

    /// LC code of the label, as issued by the IFPI.
    pub label_code: Option<String>,

    /// Describes the main activity of the label.
    pub label_type: Option<LabelType>,

    /// ISO 3166 country of origin for the label.
    pub country: Option<String>,

    /// Identifying number of the label as assigned by the CISAC database.
    pub ipi_code: Option<String>,

    /// ISNI code of the label.
    pub isni_code: Option<String>,

    /// The date when this label was founded.
    /// (Consult the MusicBrainz manual for disclaimers about the significance
    /// of these
    /// informations.)
    pub begin_date: Option<PartialDate>,

    /// The date when this label ceased to exist or its last release ever was
    /// released.
    pub end_date: Option<PartialDate>,
}

impl Resource for Label {
    fn get_name() -> &'static str
    {
        "Label"
    }

    fn get_url(mbid: &Mbid) -> String
    {
        format!("https://musicbrainz.org/ws/2/label/{}?inc=aliases", mbid)
    }

    fn base_url() -> &'static str
    {
        "https://musicbrainz.org/ws/2/label/"
    }
}

impl FromXmlContained for Label {}
impl FromXml for Label {
    fn from_xml<'d, R>(reader: &'d R) -> Result<Label, FromXmlError>
    where
        R: XpathReader<'d>,
    {
        Ok(Label {
            mbid: reader.read(".//mb:label/@id")?,
            name: reader.read(".//mb:label/mb:name/text()")?,
            sort_name: reader.read(".//mb:label/mb:sort-name/text()")?,
            disambiguation: reader.read_option(".//mb:label/mb:disambiguation/text()")?,
            aliases: reader.read_vec(".//mb:label/mb:alias-list/mb:alias/text()")?,
            label_code: reader.read_option(".//mb:label/mb:label-code/text()")?,
            label_type: reader.read_option(".//mb:label/@type")?,
            country: reader.read_option(".//mb:label/mb:country/text()")?,
            ipi_code: None, // TODO
            isni_code: None, // TODO
            begin_date: reader.read_option(".//mb:label/mb:life-span/mb:begin/text()")?,
            end_date: reader.read_option(".//mb:label/mb:life-span/mb:end/text()")?,
        })
    }
}

enum_mb_xml! {
    pub enum LabelType {
        /// The main `LabelType` in the MusicBrainz database.
        /// That is a brand (and trademark) associated with the marketing of a
        /// release.
        var Imprint = "Imprint",

        var Production = "Production",
        var Publisher = "Publisher",

        /// Production company producing entirely new releases.
        var ProductionOriginal = "Original Production",
        /// Known bootleg production companies, not sanctioned by the rights owners
        /// of the released
        /// work.
        var ProductionBootleg = "Bootleg Production",
        /// Companies specialized in catalog reissues.
        var ProductionReissue = "Reissue Production",

        /// Companies mainly distributing other labels production, often in a
        /// specfic region of the
        /// world.
        var Distribution = "Distribution",
        /// Holdings, conglomerates or other financial entities that don't mainly
        /// produce records but
        /// manage a large set of recording labels owned by them.
        var Holding = "Holding",
        /// An organization which collects royalties on behalf of the artists.
        var RightsSociety = "RightsSociety",
    }
}

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

    #[test]
    fn label_read_xml1()
    {
        let mbid = Mbid::from_str("c029628b-6633-439e-bcee-ed02e8a338f7").unwrap();
        let label: Label = ::util::test_utils::fetch_entity(&mbid).unwrap();

        assert_eq!(label.mbid, mbid);
        assert_eq!(label.name, "EMI".to_string());
        assert_eq!(label.sort_name, "EMI".to_string());
        assert_eq!(
            label.disambiguation,
            Some("EMI Records, since 1972".to_string())
        );
        assert_eq!(
            label.aliases,
            vec![
                "EMI".to_string(),
                "EMI Records (UK)".to_string(),
                "EMI Records Ltd".to_string(),
                "EMI UK".to_string(),
            ]
        );
        assert_eq!(label.label_code, Some("542".to_string()));
        assert_eq!(label.label_type, Some(LabelType::ProductionOriginal));
        assert_eq!(label.country, Some("GB".to_string()));
        assert_eq!(label.ipi_code, None);
        assert_eq!(label.isni_code, None);
        assert_eq!(
            label.begin_date,
            Some(PartialDate::from_str("1972").unwrap())
        );
        assert_eq!(label.end_date, None);
    }

    #[test]
    fn read_aliases()
    {
        let mbid = Mbid::from_str("168f48c8-057e-4974-9600-aa9956d21e1a").unwrap();
        let label: Label = ::util::test_utils::fetch_entity(&mbid).unwrap();

        let mut expected = vec![
            "Avex Trax Japan".to_string(),
            "エイベックス・トラックス".to_string(),
        ];
        expected.sort();
        let mut actual = label.aliases.clone();
        actual.sort();

        assert_eq!(actual, expected);
    }
}
<|endoftext|>


<commit_before>use std::io;
pub mod log_events;
use self::log_events::*;

pub fn parse_line(line: Result<String, io::Error>) -> Result<LogEvent, &'static str> {
    match line {
        Err(_) => return Err("Failed to read line."),
        Ok(ref line) if line.contains("->") => {
            match Request::new_from_log_line(line) {
                Ok(request) => Ok(LogEvent::Request(request)),
                Err(err) => Err(err),
            }
        }
        Ok(ref line) if line.contains("<-") => {
            match Response::new_from_log_line(line) {
                Ok(response) => Ok(LogEvent::Response(response)),
                Err(err) => Err(err),
            }
        }
        Ok(_) => Err("Line is neither a Request nor a Response"),
    }
}

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

    #[test]
    fn test_parse_line_request() {
        let line = "08/Apr/2016:09:58:47 +0200 [02] -> GET /content/some/other.html HTTP/1.1"
            .to_string();

        let event = match parse_line(Ok(line)).unwrap() {
            LogEvent::Request(request) => request,
            LogEvent::Response(_) => unreachable!(),
        };

        assert_eq!(event.id, 2);
    }

    #[test]
    fn test_parse_line_response() {
        let line = "08/Apr/2016:09:58:48 +0200 [05] <- 200 text/html 10ms".to_string();

        let event = match parse_line(Ok(line)).unwrap() {
            LogEvent::Request(_) => unreachable!(),
            LogEvent::Response(response) => response,
        };

        assert_eq!(event.id, 5);
    }

    #[test]
    fn test_parse_line_unrecognized() {
        let line = "08/Apr/2016:09:58:48 +0200 [05] XY 200 text/html 10ms".to_string();

        let event = parse_line(Ok(line));

        assert_eq!(event, Err("Line is neither a Request nor a Response"));
    }

    #[test]
    fn test_parse_line_with_response_arrow_in_url() {
        let line = "08/Apr/2016:09:58:47 +0200 [02] -> GET /content/<-.html HTTP/1.1".to_string();

        let _ = match parse_line(Ok(line)).unwrap() {
            LogEvent::Request(request) => request,
            LogEvent::Response(_) => unreachable!(),
        };
    }
}
<commit_msg>Avoid unneeded result match<commit_after>use std::io;
pub mod log_events;
use self::log_events::*;

pub fn parse_line(line: Result<String, io::Error>) -> Result<LogEvent, &'static str> {
    match line {
        Err(_) => return Err("Failed to read line."),
        Ok(ref line) if line.contains("->") => {
            Ok(LogEvent::Request(Request::new_from_log_line(line)?))
        }
        Ok(ref line) if line.contains("<-") => {
            Ok(LogEvent::Response(Response::new_from_log_line(line)?))
        }
        Ok(_) => Err("Line is neither a Request nor a Response"),
    }
}

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

    #[test]
    fn test_parse_line_request() {
        let line = "08/Apr/2016:09:58:47 +0200 [02] -> GET /content/some/other.html HTTP/1.1"
            .to_string();

        let event = match parse_line(Ok(line)).unwrap() {
            LogEvent::Request(request) => request,
            LogEvent::Response(_) => unreachable!(),
        };

        assert_eq!(event.id, 2);
    }

    #[test]
    fn test_parse_line_response() {
        let line = "08/Apr/2016:09:58:48 +0200 [05] <- 200 text/html 10ms".to_string();

        let event = match parse_line(Ok(line)).unwrap() {
            LogEvent::Request(_) => unreachable!(),
            LogEvent::Response(response) => response,
        };

        assert_eq!(event.id, 5);
    }

    #[test]
    fn test_parse_line_unrecognized() {
        let line = "08/Apr/2016:09:58:48 +0200 [05] XY 200 text/html 10ms".to_string();

        let event = parse_line(Ok(line));

        assert_eq!(event, Err("Line is neither a Request nor a Response"));
    }

    #[test]
    fn test_parse_line_with_response_arrow_in_url() {
        let line = "08/Apr/2016:09:58:47 +0200 [02] -> GET /content/<-.html HTTP/1.1".to_string();

        let _ = match parse_line(Ok(line)).unwrap() {
            LogEvent::Request(request) => request,
            LogEvent::Response(_) => unreachable!(),
        };
    }
}
<|endoftext|>


<commit_before>pub extern crate syslog;
extern crate ansi_term;

use self::syslog::Facility;
pub use self::syslog::Severity;
use self::ansi_term::Colour::{Red, Yellow, White, Green, Cyan, Blue};

#[derive(Debug, PartialEq, Clone)]
pub enum LogDest {
    StdOut,
    Syslog,
}

#[derive(Debug, Clone)]
pub struct Logger {
    dest: LogDest
}

impl Logger {
    pub fn new(dest: LogDest) -> Logger {
        Logger { dest: dest }
    }

    pub fn log(&self, severity: Severity, msg: &str) -> () {
        match self.dest {
            LogDest::StdOut => {
                match severity {
                    Severity::LOG_EMERG => {
                        println!("<0> {}", Cyan.paint(msg));
                    }
                    Severity::LOG_ALERT => {
                        println!("<1> {}", Red.paint(msg));
                    }
                    Severity::LOG_CRIT => {
                        println!("<2> {}", Red.paint(msg));
                    }
                    Severity::LOG_ERR => {
                        println!("<3> {}", Red.paint(msg));
                    }
                    Severity::LOG_WARNING => {
                        println!("<4> {}", Yellow.paint(msg));
                    }
                    Severity::LOG_NOTICE => {
                        println!("<5> {}", Blue.paint(msg));
                    }
                    Severity::LOG_INFO => {
                        println!("<6> {}", White.paint(msg));
                    }
                    Severity::LOG_DEBUG => {
                        println!("<7> {}", Green.paint(msg));
                    }
                }
            }
            LogDest::Syslog => {
                match syslog::unix(Facility::LOG_DAEMON) {
                    Err(e) => println!("[!] impossible to connect to syslog: {:?}", e),
                    Ok(writer) => {
                        let r = writer.send(severity, msg);
                        if r.is_err() {
                            println!("[!] error sending the log {}", r.err().expect("got error"));
                        }
                    }
                }
            }
        }
    }
}<commit_msg>logger test<commit_after>pub extern crate syslog;

pub use self::syslog::Severity;

#[cfg(not(test))]
use self::prod_calls::{stdout_log, syslog_log};
#[cfg(test)]
use self::test_calls::{stdout_log, syslog_log};

#[derive(Debug, PartialEq, Clone)]
pub enum LogDest {
    StdOut,
    Syslog,
}

#[derive(Debug, Clone)]
pub struct Logger {
    dest: LogDest
}

impl Logger {
    pub fn new(dest: LogDest) -> Logger {
        Logger { dest: dest }
    }

    pub fn log(&self, severity: Severity, msg: &str) -> () {
        match self.dest {
            LogDest::StdOut => {
                stdout_log(severity, msg);
            }
            LogDest::Syslog => {
                syslog_log(severity, msg);
            }
        }
    }
}

#[allow(dead_code)]
mod prod_calls {
    extern crate ansi_term;

    use self::ansi_term::Colour::{Red, Yellow, White, Green, Cyan, Blue};
    use super::Severity;
    use super::syslog::{unix, Facility};

    pub fn stdout_log(severity: Severity, msg: &str) -> () {
        match severity {
            Severity::LOG_EMERG => {
                println!("<0> {}", Cyan.paint(msg));
            }
            Severity::LOG_ALERT => {
                println!("<1> {}", Red.paint(msg));
            }
            Severity::LOG_CRIT => {
                println!("<2> {}", Red.paint(msg));
            }
            Severity::LOG_ERR => {
                println!("<3> {}", Red.paint(msg));
            }
            Severity::LOG_WARNING => {
                println!("<4> {}", Yellow.paint(msg));
            }
            Severity::LOG_NOTICE => {
                println!("<5> {}", Blue.paint(msg));
            }
            Severity::LOG_INFO => {
                println!("<6> {}", White.paint(msg));
            }
            Severity::LOG_DEBUG => {
                println!("<7> {}", Green.paint(msg));
            }
        }
    }

    pub fn syslog_log(severity: Severity, msg: &str) -> () {
        match unix(Facility::LOG_DAEMON) {
            Err(e) => println!("[!] impossible to connect to syslog: {:?}", e),
            Ok(writer) => {
                let r = writer.send(severity, msg);
                if r.is_err() {
                    println!("[!] error sending the log {}", r.err().expect("got error"));
                }
            }
        }
    }
}

#[allow(dead_code)]
mod test_calls {
    use super::Severity;
    use std::mem;

    pub static mut FUNC_USED: u8 = 0;
    pub static mut SEVERITY_TRANSMUTED: u8 = 255;

    pub fn stdout_log(severity: Severity, msg: &str) -> () {
        unsafe {
            let ordinal: u8 = mem::transmute(severity);
            FUNC_USED = 1;
            SEVERITY_TRANSMUTED = ordinal;
            println!("stdout_log({}, {})", ordinal, msg);
        }
    }

    pub fn syslog_log(severity: Severity, msg: &str) -> () {
        unsafe {
            let ordinal: u8 = mem::transmute(severity);
            FUNC_USED = 2;
            SEVERITY_TRANSMUTED = ordinal;
            println!("syslog_log({}, {})", ordinal, msg);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{Logger, LogDest};
    use super::{Severity};

    #[test]
    fn test_stdout_match() {
        let l = Logger::new(LogDest::StdOut);
        l.log(Severity::LOG_EMERG, "foo");
        unsafe {
            assert_eq! (1, super::test_calls::FUNC_USED);
            assert_eq! (0, super::test_calls::SEVERITY_TRANSMUTED);
        }
    }

    #[test]
    fn test_syslog_match() {
        let l = Logger::new(LogDest::Syslog);
        l.log(Severity::LOG_ALERT, "foo");
        unsafe {
            assert_eq! (2, super::test_calls::FUNC_USED);
            assert_eq! (1, super::test_calls::SEVERITY_TRANSMUTED);
        }
    }
}<|endoftext|>


<commit_before>extern crate structopt;
#[macro_use]
extern crate structopt_derive;

use structopt::StructOpt;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::Read;

type Node = usize;

fn parse(input: &str) -> HashMap<Node, Vec<Node>> {
    input
        .lines()
        .map(|line| {
            let mut split = line.split("<->");
            match (split.next(), split.next()) {
                (Some(node), Some(neighbors)) => (
                    node.trim()
                        .parse()
                        .expect(&format!("Could not parse {} as node", node)),
                    neighbors
                        .split(',')
                        .map(|neighbor| {
                            neighbor.trim().parse().expect(&format!(
                                "Could not parse {} as node",
                                neighbor
                            ))
                        })
                        .collect(),
                ),
                _ => panic!(format!("Could not parse line {}", line)),
            }
        })
        .collect()
}

fn node_group(
    start: Node,
    nodemap: &HashMap<Node, Vec<Node>>,
) -> HashSet<Node> {
    let mut reachable = HashSet::<Node>::new();
    let mut outer_edge = HashSet::<Node>::new();
    outer_edge.insert(start);
    while !outer_edge.is_empty() {
        let mut new_edge = HashSet::new();
        for item in outer_edge.drain() {
            if !reachable.contains(&item) {
                reachable.insert(item);
                new_edge.extend(nodemap[&item].iter());
            }
        }
        outer_edge = new_edge;
    }
    reachable
}

fn part1(nodemap: &HashMap<Node, Vec<Node>>) -> usize {
    node_group(0, nodemap).len()
}

fn part2(nodemap: &HashMap<Node, Vec<Node>>) -> usize {
    let mut visited = HashSet::<Node>::new();
    let mut groups: Vec<HashSet<Node>> = Vec::new();
    for start in nodemap.keys().cloned() {
        if visited.contains(&start) {
            continue;
        }
        let group = node_group(start, nodemap);
        for node in &group {
            visited.insert(node.clone());
        }
        groups.push(group);
    }
    groups.len()
}

fn main() {
    let opt = Opt::from_args();
    let mut contents = String::new();
    if opt.input == "-" {
        std::io::stdin()
            .read_to_string(&mut contents)
            .expect("could not read stdin");
    } else {
        let mut file = File::open(&opt.input)
            .expect(&format!("file {} not found", opt.input));
        file.read_to_string(&mut contents)
            .expect(&format!("could not read file {}", opt.input));
    }
    let nodemap = parse(&contents);
    println!("Part 1: {}", part1(&nodemap));
    println!("Part 2: {}", part2(&nodemap));
}

#[derive(StructOpt, Debug)]
#[structopt(name = "day12", about = "Advent of code 2017 day 12")]
struct Opt {
    #[structopt(help = "Input file")] input: String,
}

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

    static TEST_INPUT: &str = "0 <-> 2\n\
                               1 <-> 1\n\
                               2 <-> 0, 3, 4\n\
                               3 <-> 2, 4\n\
                               4 <-> 2, 3, 6\n\
                               5 <-> 6\n\
                               6 <-> 4, 5\n";

    #[test]
    fn part1_test() {
        let nodemap = parse(TEST_INPUT);
        assert_eq!(part1(&nodemap), 6);
    }

    #[test]
    fn part2_test() {
        let nodemap = parse(TEST_INPUT);
        assert_eq!(part2(&nodemap), 2);
    }
}
<commit_msg>2017 day 12: Make paths more technically correct<commit_after>extern crate structopt;
#[macro_use]
extern crate structopt_derive;

use structopt::StructOpt;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

type Node = usize;

fn parse(input: &str) -> HashMap<Node, Vec<Node>> {
    input
        .lines()
        .map(|line| {
            let mut split = line.split("<->");
            match (split.next(), split.next()) {
                (Some(node), Some(neighbors)) => (
                    node.trim()
                        .parse()
                        .expect(&format!("Could not parse {} as node", node)),
                    neighbors
                        .split(',')
                        .map(|neighbor| {
                            neighbor.trim().parse().expect(&format!(
                                "Could not parse {} as node",
                                neighbor
                            ))
                        })
                        .collect(),
                ),
                _ => panic!(format!("Could not parse line {}", line)),
            }
        })
        .collect()
}

fn node_group(
    start: Node,
    nodemap: &HashMap<Node, Vec<Node>>,
) -> HashSet<Node> {
    let mut reachable = HashSet::<Node>::new();
    let mut outer_edge = HashSet::<Node>::new();
    outer_edge.insert(start);
    while !outer_edge.is_empty() {
        let mut new_edge = HashSet::new();
        for item in outer_edge.drain() {
            if !reachable.contains(&item) {
                reachable.insert(item);
                new_edge.extend(nodemap[&item].iter());
            }
        }
        outer_edge = new_edge;
    }
    reachable
}

fn part1(nodemap: &HashMap<Node, Vec<Node>>) -> usize {
    node_group(0, nodemap).len()
}

fn part2(nodemap: &HashMap<Node, Vec<Node>>) -> usize {
    let mut visited = HashSet::<Node>::new();
    let mut groups: Vec<HashSet<Node>> = Vec::new();
    for start in nodemap.keys().cloned() {
        if visited.contains(&start) {
            continue;
        }
        let group = node_group(start, nodemap);
        for node in &group {
            visited.insert(node.clone());
        }
        groups.push(group);
    }
    groups.len()
}

fn main() {
    let opt = Opt::from_args();
    let mut contents = String::new();
    if opt.input.to_str() == Some("-") {
        std::io::stdin()
            .read_to_string(&mut contents)
            .expect("could not read stdin");
    } else {
        let mut file = File::open(&opt.input)
            .expect(&format!("file {} not found", opt.input.display()));
        file.read_to_string(&mut contents)
            .expect(&format!("could not read file {}", opt.input.display()));
    }
    let nodemap = parse(&contents);
    println!("Part 1: {}", part1(&nodemap));
    println!("Part 2: {}", part2(&nodemap));
}

#[derive(StructOpt, Debug)]
#[structopt(name = "day12", about = "Advent of code 2017 day 12")]
struct Opt {
    #[structopt(help = "Input file", parse(from_os_str))] input: PathBuf,
}

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

    static TEST_INPUT: &str = "0 <-> 2\n\
                               1 <-> 1\n\
                               2 <-> 0, 3, 4\n\
                               3 <-> 2, 4\n\
                               4 <-> 2, 3, 6\n\
                               5 <-> 6\n\
                               6 <-> 4, 5\n";

    #[test]
    fn part1_test() {
        let nodemap = parse(TEST_INPUT);
        assert_eq!(part1(&nodemap), 6);
    }

    #[test]
    fn part2_test() {
        let nodemap = parse(TEST_INPUT);
        assert_eq!(part2(&nodemap), 2);
    }
}
<|endoftext|>


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

//! Constructs display lists from boxes.

use layout::box::Box;
use layout::context::LayoutContext;
use std::cast::transmute;
use script::dom::node::AbstractNode;

use gfx;
use style;

/// Display list data is usually an AbstractNode with view () to indicate
/// that nodes in this view shoud not really be touched. The idea is to
/// store the nodes in the display list and have layout transmute them.
pub trait ExtraDisplayListData {
    fn new(box: &@Box) -> Self;
}

pub type Nothing = ();

impl ExtraDisplayListData for AbstractNode<()> {
    fn new(box: &@Box) -> AbstractNode<()> {
        unsafe {
            transmute(box.node)
        }
    }
}

impl ExtraDisplayListData for Nothing {
    fn new(_: &@Box) -> Nothing {
        ()
    }
}

impl ExtraDisplayListData for @Box {
    fn new(box: &@Box) -> @Box {
        *box
    }
}

/// A builder object that manages display list builder should mainly hold information about the
/// initial request and desired result--for example, whether the `DisplayList` is to be used for
/// painting or hit testing. This can affect which boxes are created.
///
/// Right now, the builder isn't used for much, but it establishes the pattern we'll need once we
/// support display-list-based hit testing and so forth.
pub struct DisplayListBuilder<'self> {
    ctx:  &'self LayoutContext,
}

//
// Miscellaneous useful routines
//

/// Allows a CSS color to be converted into a graphics color.
pub trait ToGfxColor {
    /// Converts a CSS color to a graphics color.
    fn to_gfx_color(&self) -> gfx::color::Color;
}

impl ToGfxColor for style::computed_values::RGBA {
    fn to_gfx_color(&self) -> gfx::color::Color {
        gfx::color::rgba(self.red, self.green, self.blue, self.alpha)
    }
}

<commit_msg>layout: Remove the ability to put boxes in display list items.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Constructs display lists from boxes.

use layout::box::Box;
use layout::context::LayoutContext;
use std::cast::transmute;
use script::dom::node::AbstractNode;

use gfx;
use style;

/// Display list data is usually an AbstractNode with view () to indicate
/// that nodes in this view shoud not really be touched. The idea is to
/// store the nodes in the display list and have layout transmute them.
pub trait ExtraDisplayListData {
    fn new(box: &@Box) -> Self;
}

pub type Nothing = ();

impl ExtraDisplayListData for AbstractNode<()> {
    fn new(box: &@Box) -> AbstractNode<()> {
        unsafe {
            transmute(box.node)
        }
    }
}

impl ExtraDisplayListData for Nothing {
    fn new(_: &@Box) -> Nothing {
        ()
    }
}

/// A builder object that manages display list builder should mainly hold information about the
/// initial request and desired result--for example, whether the `DisplayList` is to be used for
/// painting or hit testing. This can affect which boxes are created.
///
/// Right now, the builder isn't used for much, but it establishes the pattern we'll need once we
/// support display-list-based hit testing and so forth.
pub struct DisplayListBuilder<'self> {
    ctx:  &'self LayoutContext,
}

//
// Miscellaneous useful routines
//

/// Allows a CSS color to be converted into a graphics color.
pub trait ToGfxColor {
    /// Converts a CSS color to a graphics color.
    fn to_gfx_color(&self) -> gfx::color::Color;
}

impl ToGfxColor for style::computed_values::RGBA {
    fn to_gfx_color(&self) -> gfx::color::Color {
        gfx::color::rgba(self.red, self.green, self.blue, self.alpha)
    }
}

<|endoftext|>


<commit_before>use std::str::Chars;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum TokenType {
	Ampersand,
	Bang,
	Caret,
	ForwardSlash,
	Identifier { str: String },
	LeftAngleBracketX2,
	LeftParen,
	Minus,
	NewLine,
	Number { str: String },
	Percent,
	Pipe,
	Plus,
	RightAngleBracketX2,
	RightParen,
	Star,
	StarX2,
}

pub struct Token {
	pub token_type: TokenType,
	pub line: u32,
	pub column: u32,
	pub length: u32
}

pub struct Scanner<'a> {
	chars: Chars<'a>,
	next_char: Option<char>,
	line: u32,
	column: u32,
}

impl<'a> Iterator for Scanner<'a> {
	type Item = Token;

	fn next(&mut self) -> Option<Token> {
		self.next()
	}
}

impl<'a> Scanner<'a> {
	pub fn new(input: &'a str) -> Scanner<'a> {
		let mut chars = input.chars();
		Scanner {
			next_char: chars.next(),
			chars: chars,
			line: 1,
			column: 1,
		}
	}

	fn get_char(&mut self) -> Option<char> {
		let next = self.next_char;
		self.next_char = self.chars.next();
		self.column += 1;
		next
	}

	fn peek_char(&self) -> Option<char> {
		self.next_char
	}

	fn skip_char(&mut self) {
		self.next_char = self.chars.next();
		self.column += 1;
	}

	fn expect_char(&mut self, expected: char) -> Option<char> {
		match self.peek_char() {
			Some(c) => {
				if c == expected {
					Some(c)
				} else {
					println!("Expected '{}' but found '{}' instead (line {}, column {})",
						expected, c, self.line, self.column);
					None
				}
			},
			None => {
				println!("Expected '{}' but found end-of-input instead (line {}, column {})",
					expected, self.line, self.column);
				None
			},
		}
	}

	fn new_token(&self, token_type: TokenType, length: u32) -> Option<Token> {
		let t = Token {
			token_type: token_type,
			line: self.line,
			column: self.column - length,
			length: length
		};

		trace!("{:?} @{}:{}, len {}",
			t.token_type, t.line, t.column, t.length);

		Some(t)
	}

	fn next(&mut self) -> Option<Token> {
		let mut c;

		// find the next non-whitespace character
		loop {
			c = unwrap!(self.peek_char(), {
				return None;
			});

			// keep new lines, even though they are "whitespace"
			if c == '\n' || !c.is_whitespace() {
				break;
			}

			self.skip_char();
		}

		match c {
			'(' => self.scan_left_paren(),
			')' => self.scan_right_paren(),
			'+' => self.scan_plus(),
			'-' => self.scan_minus(),
			'*' => self.scan_star(),
			'^' => self.scan_caret(),
			'%' => self.scan_percent(),
			'/' => self.scan_forward_slash(),
			'!' => self.scan_bang(),
			'|' => self.scan_pipe(),
			'&' => self.scan_ampersand(),
			'<' => self.scan_left_angle_bracket(),
			'>' => self.scan_right_angle_bracket(),
			'\n' => self.scan_new_line(),
			'.' => self.scan_number(),
			_ => {
				if c.is_numeric() {
					self.scan_number()
				} else if c.is_alphabetic() {
					self.scan_identifier()
				} else {
					println!("unexpected character '{}' (line {}, column {})",
						c, self.line, self.column);
					Option::None
				}
			}
		}
	} // next

	fn scan_left_paren(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::LeftParen, 1)
	}

	fn scan_right_paren(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::RightParen, 1)
	}

	fn scan_plus(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Plus, 1)
	}

	fn scan_minus(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Minus, 1)
	}

	fn scan_star(&mut self) -> Option<Token> {
		self.skip_char();
		match self.peek_char() {
			Some('*') => {
				self.skip_char();
				self.new_token(TokenType::StarX2, 2)
			}
			_ => self.new_token(TokenType::Star, 1)
		}
	}

	fn scan_caret(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Caret, 1)
	}

	fn scan_percent(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Percent, 1)
	}

	fn scan_forward_slash(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::ForwardSlash, 1)
	}

	fn scan_bang(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Bang, 1)
	}

	fn scan_pipe(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Pipe, 1)
	}

	fn scan_ampersand(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Ampersand, 1)
	}

	fn scan_left_angle_bracket(&mut self) -> Option<Token> {
		self.skip_char();
		match self.expect_char('<') {
			Some(_) => {
				self.skip_char();
				self.new_token(TokenType::LeftAngleBracketX2, 2)
			},
			None => None,
		}
	}

	fn scan_right_angle_bracket(&mut self) -> Option<Token> {
		self.skip_char();
		match self.expect_char('>') {
			Some(_) => {
				self.skip_char();
				self.new_token(TokenType::RightAngleBracketX2, 2)
			},
			None => None,
		}
	}

	fn scan_new_line(&mut self) -> Option<Token> {
		self.skip_char();
		let t = self.new_token(TokenType::NewLine, 1);
		self.line += 1;
		self.column = 0;
		t
	}

	fn scan_number(&mut self) -> Option<Token> {
		let start = self.column;
		let mut is_float = false;
		let mut str = String::new();

		while let Some(c) = self.peek_char() {
			match c {
				'.' => {
					if is_float {
						break;
					}
					is_float = true;
				},
				'_' => {
					self.skip_char();
					continue;
				},
				_ => if !c.is_numeric() {
					break;
				}
			}

			self.skip_char();
			str.push(c);
		}

		self.new_token(
			TokenType::Number{ str: str },
			self.column - start
		)
	} // scan_number

	fn scan_identifier(&mut self) -> Option<Token> {
		let start = self.column;

		let mut str = String::new();
		str.push(self.get_char().unwrap());

		while let Some(c) = self.peek_char() {
			match c {
				'_' => { },
				_ => if !c.is_alphanumeric() {
					break;
				}
			}

			self.skip_char();
			str.push(c);
		}

		self.new_token(
			TokenType::Identifier{ str: str },
			self.column - start
		)
	} // scan_identifier
} // Scanner

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

	fn setup(input: &str) -> Scanner {
		Scanner::new(input)
	}

	fn expect(scanner: &mut Scanner, tt: TokenType) {
		let token = unwrap!(scanner.next(), {
			panic!("Expected token but found None");
		});

		assert_eq!(token.token_type, tt);
	}

	#[test]
	fn scan_ampersand() {
		let mut s = setup("&");
		expect(&mut s, TokenType::Ampersand);
	}

	#[test]
	fn scan_bang() {
		let mut s = setup("!");
		expect(&mut s, TokenType::Bang);
	}

	#[test]
	fn scan_caret() {
		let mut s = setup("^");
		expect(&mut s, TokenType::Caret);
	}

	#[test]
	fn scan_forward_slash() {
		let mut s = setup("/");
		expect(&mut s, TokenType::ForwardSlash);
	}

	#[test]
	fn scan_identifier() {
		let mut s = setup("ans");
		expect(&mut s, TokenType::Identifier { str: "ans".to_string() });
	}

	#[test]
	fn scan_left_angle_bracket_x2() {
		let mut s = setup("<<");
		expect(&mut s, TokenType::LeftAngleBracketX2);
	}

	#[test]
	fn scan_left_paren() {
		let mut s = setup("(");
		expect(&mut s, TokenType::LeftParen);
	}

	#[test]
	fn scan_minus() {
		let mut s = setup("-");
		expect(&mut s, TokenType::Minus);
	}

	#[test]
	fn scan_new_line() {
		let mut s = setup("\n");
		expect(&mut s, TokenType::NewLine);
	}

	#[test]
	fn scan_number() {
		let mut s = setup("123");
		expect(&mut s, TokenType::Number { str: "123".to_string() });
	}

	#[test]
	fn scan_percent() {
		let mut s = setup("%");
		expect(&mut s, TokenType::Percent);
	}

	#[test]
	fn scan_pipe() {
		let mut s = setup("|");
		expect(&mut s, TokenType::Pipe);
	}

	#[test]
	fn scan_plus() {
		let mut s = setup("+");
		expect(&mut s, TokenType::Plus);
	}

	#[test]
	fn scan_right_angle_bracket_x2() {
		let mut s = setup(">>");
		expect(&mut s, TokenType::RightAngleBracketX2);
	}

	#[test]
	fn scan_right_paren() {
		let mut s = setup(")");
		expect(&mut s, TokenType::RightParen);
	}

	#[test]
	fn scan_star() {
		let mut s = setup("*");
		expect(&mut s, TokenType::Star);
	}

	#[test]
	fn scan_star_x2() {
		let mut s = setup("**");
		expect(&mut s, TokenType::StarX2);
	}
} // mod tests
<commit_msg>Refactor the scanning module<commit_after>use std::str::Chars;
use buffered_iterator::*;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum TokenType {
	Ampersand,
	Bang,
	Caret,
	ForwardSlash,
	Identifier { str: String },
	LeftAngleBracketX2,
	LeftParen,
	Minus,
	NewLine,
	Number { str: String },
	Percent,
	Pipe,
	Plus,
	RightAngleBracketX2,
	RightParen,
	Star,
	StarX2,
}

pub struct Token {
	pub token_type: TokenType,
	pub line: u32,
	pub column: u32,
	pub length: u32
}

pub struct Scanner<'a> {
	chars: BufferedIterator<char, Chars<'a>>,
	line: u32,
	column: u32,
}

impl<'a> Iterator for Scanner<'a> {
	type Item = Token;

	fn next(&mut self) -> Option<Token> {
		self.next()
	}
}

impl<'a> Scanner<'a> {
	pub fn new(input: &'a str) -> Scanner<'a> {
		let chars = input.chars();
		let buf = BufferedIterator::new(chars);

		Scanner {
			chars: buf,
			line: 1,
			column: 1,
		}
	}

	fn expected_char(&self, expected: char, found: char) {
		println!("Expected '{}' but found '{}' instead (line {}, column {})",
			expected, found, self.line, self.column);
	}

	fn unexpected_char(&self, found: char) {
		println!("Unexpected character '{}' (line {}, column {})",
			found, self.line, self.column);
	}

	fn unexpected_end_of_input(&self) {
		println!("Unexpected end of input (line {}, column {})",
			self.line, self.column);
	}

	fn get_char(&mut self) -> Option<char> {
		self.column += 1;
		self.chars.pop()
	}

	fn put_char(&mut self, c: char) {
		self.column -= 1;
		self.chars.push(c)
	}

	fn expect_char(&mut self) -> Option<char> {
		match self.get_char() {
			Some(c) => Some(c),
			None => {
				self.unexpected_end_of_input();
				None
			}
		}
	}

	fn new_token(&self, token_type: TokenType, length: u32) -> Option<Token> {
		let t = Token {
			token_type: token_type,
			line: self.line,
			column: self.column - length,
			length: length
		};

		trace!("{:?} @{}:{}, len {}",
			t.token_type, t.line, t.column, t.length);

		Some(t)
	}

	fn next(&mut self) -> Option<Token> {
		let mut c;

		// find the next non-whitespace character
		loop {
			c = unwrap!(self.get_char(), {
				return None;
			});

			// keep new lines, even though they are "whitespace"
			if c == '\n' || !c.is_whitespace() {
				break;
			}
		}

		match c {
			'(' => self.new_token(TokenType::LeftParen, 1),
			')' => self.new_token(TokenType::RightParen, 1),
			'+' => self.new_token(TokenType::Plus, 1),
			'-' => self.new_token(TokenType::Minus, 1),
			'*' => self.scan_star(),
			'^' => self.new_token(TokenType::Caret, 1),
			'%' => self.new_token(TokenType::Percent, 1),
			'/' => self.new_token(TokenType::ForwardSlash, 1),
			'!' => self.new_token(TokenType::Bang, 1),
			'|' => self.new_token(TokenType::Pipe, 1),
			'&' => self.new_token(TokenType::Ampersand, 1),
			'<' => self.scan_left_angle_bracket(),
			'>' => self.scan_right_angle_bracket(),
			'\n' => self.scan_new_line(),
			'.' => {
				self.put_char(c);
				self.scan_number()
			},
			'_' => {
				self.put_char(c);
				self.scan_identifier()
			},
			_ => {
				self.put_char(c);
				if c.is_numeric() {
					self.scan_number()
				} else if c.is_alphabetic() {
					self.scan_identifier()
				} else {
					self.unexpected_char(c);
					None
				}
			},
		} // match
	} // next

	fn scan_star(&mut self) -> Option<Token> {
		match self.get_char() {
			Some('*') => return self.new_token(TokenType::StarX2, 2),
			Some(c) => self.put_char(c),
			None => {},
		}

		self.new_token(TokenType::Star, 1)
	} // scan_star

	fn scan_left_angle_bracket(&mut self) -> Option<Token> {
		match self.expect_char() {
			Some('<') => return self.new_token(TokenType::LeftAngleBracketX2, 2),
			Some(c) => self.expected_char('<', c),
			None => {},
		}

		None
	} // scan_left_angle_bracket

	fn scan_right_angle_bracket(&mut self) -> Option<Token> {
		match self.expect_char() {
			Some('>') => return self.new_token(TokenType::RightAngleBracketX2, 2),
			Some(c) => self.expected_char('>', c),
			None => {},
		}

		None
	} // scan_right_angle_bracket

	fn scan_new_line(&mut self) -> Option<Token> {
		let t = self.new_token(TokenType::NewLine, 1);
		self.line += 1;
		self.column = 0;
		t
	} // scan_new_line

	fn scan_number(&mut self) -> Option<Token> {
		let start = self.column;
		let mut is_float = false;
		let mut str = String::new();

		while let Some(c) = self.get_char() {
			match c {
				'.' => {
					if is_float {
						break;
					}
					is_float = true;
				},
				'_' => continue,
				_ => if !c.is_numeric() {
					self.put_char(c);
					break;
				}
			}

			str.push(c);
		}

		self.new_token(
			TokenType::Number{ str: str },
			self.column - start
		)
	} // scan_number

	fn scan_identifier(&mut self) -> Option<Token> {
		let start = self.column;
		let mut str = String::new();
		str.push(self.get_char().unwrap());

		while let Some(c) = self.get_char() {
			match c {
				'_' => { },
				_ => if !c.is_alphanumeric() {
					self.put_char(c);
					break;
				}
			}

			str.push(c);
		}

		self.new_token(
			TokenType::Identifier{ str: str },
			self.column - start
		)
	} // scan_identifier
} // Scanner

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

	fn setup(input: &str) -> Scanner {
		Scanner::new(input)
	}

	fn expect(scanner: &mut Scanner, tt: TokenType) {
		let token = unwrap!(scanner.next(), {
			panic!("Expected token but found None");
		});

		assert_eq!(token.token_type, tt);
	}

	#[test]
	fn scan_ampersand() {
		let mut s = setup("&");
		expect(&mut s, TokenType::Ampersand);
	}

	#[test]
	fn scan_bang() {
		let mut s = setup("!");
		expect(&mut s, TokenType::Bang);
	}

	#[test]
	fn scan_caret() {
		let mut s = setup("^");
		expect(&mut s, TokenType::Caret);
	}

	#[test]
	fn scan_forward_slash() {
		let mut s = setup("/");
		expect(&mut s, TokenType::ForwardSlash);
	}

	#[test]
	fn scan_identifier() {
		let mut s = setup("ans");
		expect(&mut s, TokenType::Identifier { str: "ans".to_string() });
	}

	#[test]
	fn scan_left_angle_bracket_x2() {
		let mut s = setup("<<");
		expect(&mut s, TokenType::LeftAngleBracketX2);
	}

	#[test]
	fn scan_left_paren() {
		let mut s = setup("(");
		expect(&mut s, TokenType::LeftParen);
	}

	#[test]
	fn scan_minus() {
		let mut s = setup("-");
		expect(&mut s, TokenType::Minus);
	}

	#[test]
	fn scan_new_line() {
		let mut s = setup("\n");
		expect(&mut s, TokenType::NewLine);
	}

	#[test]
	fn scan_number() {
		let mut s = setup("123");
		expect(&mut s, TokenType::Number { str: "123".to_string() });
	}

	#[test]
	fn scan_percent() {
		let mut s = setup("%");
		expect(&mut s, TokenType::Percent);
	}

	#[test]
	fn scan_pipe() {
		let mut s = setup("|");
		expect(&mut s, TokenType::Pipe);
	}

	#[test]
	fn scan_plus() {
		let mut s = setup("+");
		expect(&mut s, TokenType::Plus);
	}

	#[test]
	fn scan_right_angle_bracket_x2() {
		let mut s = setup(">>");
		expect(&mut s, TokenType::RightAngleBracketX2);
	}

	#[test]
	fn scan_right_paren() {
		let mut s = setup(")");
		expect(&mut s, TokenType::RightParen);
	}

	#[test]
	fn scan_star() {
		let mut s = setup("*");
		expect(&mut s, TokenType::Star);
	}

	#[test]
	fn scan_star_x2() {
		let mut s = setup("**");
		expect(&mut s, TokenType::StarX2);
	}
} // mod tests
<|endoftext|>


<commit_before>pub fn production_rate_per_hour(speed: u8) -> f64 {
    const CARS_PER_HOUR: u32 = 221;
    let production = CARS_PER_HOUR * speed as u32;
    let success_rate = success_rate(speed);
    return (success_rate * production as f64) as f64;
}

pub fn success_rate(speed: u8) -> f64 {
    if speed >= 1 && speed <= 4 {
        return 1.0;
    }
    if speed >= 5 && speed <= 8 {
        return 0.90;
    }
    if speed >= 9 && speed <= 10 {
        return 0.70;
    }
    // Ideally this would throw an error
    return 0.0;
}

pub fn working_items_per_minute(speed: u8) -> u32 {
    unimplemented!("calculate the amount of working items at speed: {}", speed)
}
<commit_msg>Remove unnecessary cast<commit_after>pub fn production_rate_per_hour(speed: u8) -> f64 {
    const CARS_PER_HOUR: u32 = 221;
    let production = CARS_PER_HOUR * speed as u32;
    let success_rate = success_rate(speed);
    return success_rate * production as f64;
}

pub fn success_rate(speed: u8) -> f64 {
    if speed >= 1 && speed <= 4 {
        return 1.0;
    }
    if speed >= 5 && speed <= 8 {
        return 0.90;
    }
    if speed >= 9 && speed <= 10 {
        return 0.70;
    }
    // Ideally this would throw an error
    return 0.0;
}

pub fn working_items_per_minute(speed: u8) -> u32 {
    unimplemented!("calculate the amount of working items at speed: {}", speed)
}
<|endoftext|>


<commit_before>//! This module provides a generic iterator and traits for decomposing
//! primitives and tessellating polygons.

use arrayvec::ArrayVec;
use std::collections::VecDeque;
use std::iter::IntoIterator;
use std::vec;

use math::{self, FScalar};
use super::primitive::{Line, Polygon, Polygonal, Primitive, Triangle, Quad};

// A type `F` constrained to `Fn(P, D) -> R` could be used here, but it would
// not be possible to name that type for anything but functions (not closures).
// Instead of a limited and somewhat redundant type `F`, just use `fn(P, D) ->
// R` for the member `f`.
pub struct Decompose<I, P, Q, R>
where
    R: IntoIterator<Item = Q>,
{
    input: I,
    output: VecDeque<Q>,
    f: fn(P) -> R,
}

impl<I, P, Q, R> Decompose<I, P, Q, R>
where
    R: IntoIterator<Item = Q>,
{
    pub(super) fn new(input: I, f: fn(P) -> R) -> Self {
        Decompose {
            input: input,
            output: VecDeque::new(),
            f: f,
        }
    }
}

impl<I, P, R> Decompose<I, P, P, R>
where
    I: Iterator<Item = P>,
    R: IntoIterator<Item = P>,
{
    pub fn remap(self, n: usize) -> Decompose<vec::IntoIter<P>, P, P, R> {
        let Decompose { input, output, f } = self;
        Decompose::new(
            output
                .into_iter()
                .rev()
                .chain(remap(n, input, f))
                .collect::<Vec<_>>() // TODO: Only needed to name the iterator.
                .into_iter(),
            f,
        )
    }
}

impl<I, P, Q, R> Iterator for Decompose<I, P, Q, R>
where
    I: Iterator<Item = P>,
    R: IntoIterator<Item = Q>,
{
    type Item = Q;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(primitive) = self.output.pop_front() {
                return Some(primitive);
            }
            if let Some(primitive) = self.input.next() {
                self.output.extend((self.f)(primitive));
            }
            else {
                return None;
            }
        }
    }
}

pub trait Interpolate: math::Interpolate<FScalar> {}

impl<T> Interpolate for T
where
    T: math::Interpolate<FScalar>,
{
}

pub trait IntoPoints: Primitive {
    type Output: IntoIterator<Item = Self::Point>;

    fn into_points(self) -> Self::Output;
}

pub trait IntoLines: Primitive {
    type Output: IntoIterator<Item = Line<Self::Point>>;

    fn into_lines(self) -> Self::Output;
}

pub trait IntoTriangles: Polygonal {
    type Output: IntoIterator<Item = Triangle<Self::Point>>;

    fn into_triangles(self) -> Self::Output;
}

pub trait IntoSubdivisions: Polygonal
where
    Self::Point: Clone + Interpolate,
{
    type Output: IntoIterator<Item = Self>;

    fn into_subdivisions(self) -> Self::Output;
}

pub trait IntoTetrahedrons: Polygonal
where
    Self::Point: Clone + Interpolate,
{
    fn into_tetrahedrons(self) -> ArrayVec<[Triangle<Self::Point>; 4]>;
}

impl<T> IntoPoints for Line<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Self::Point; 2]>;

    fn into_points(self) -> Self::Output {
        let Line { a, b } = self;
        ArrayVec::from([a, b])
    }
}

impl<T> IntoPoints for Triangle<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Self::Point; 3]>;

    fn into_points(self) -> Self::Output {
        let Triangle { a, b, c } = self;
        ArrayVec::from([a, b, c])
    }
}

impl<T> IntoPoints for Quad<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Self::Point; 4]>;

    fn into_points(self) -> Self::Output {
        let Quad { a, b, c, d } = self;
        ArrayVec::from([a, b, c, d])
    }
}

impl<T> IntoPoints for Polygon<T>
where
    T: Clone,
{
    type Output = Vec<Self::Point>;

    fn into_points(self) -> Self::Output {
        match self {
            Polygon::Triangle(triangle) => triangle.into_points().into_iter().collect(),
            Polygon::Quad(quad) => quad.into_points().into_iter().collect(),
        }
    }
}

impl<T> IntoLines for Line<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Line<Self::Point>; 1]>;

    fn into_lines(self) -> Self::Output {
        ArrayVec::from([self])
    }
}

impl<T> IntoLines for Triangle<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Line<Self::Point>; 3]>;

    fn into_lines(self) -> Self::Output {
        let Triangle { a, b, c } = self;
        ArrayVec::from(
            [
                Line::new(a.clone(), b.clone()),
                Line::new(b, c.clone()),
                Line::new(c, a),
            ],
        )
    }
}

impl<T> IntoLines for Quad<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Line<Self::Point>; 4]>;

    fn into_lines(self) -> Self::Output {
        let Quad { a, b, c, d } = self;
        ArrayVec::from(
            [
                Line::new(a.clone(), b.clone()),
                Line::new(b, c.clone()),
                Line::new(c, d.clone()),
                Line::new(d, a),
            ],
        )
    }
}

impl<T> IntoLines for Polygon<T>
where
    T: Clone,
{
    type Output = Vec<Line<Self::Point>>;

    fn into_lines(self) -> Self::Output {
        match self {
            Polygon::Triangle(triangle) => triangle.into_lines().into_iter().collect(),
            Polygon::Quad(quad) => quad.into_lines().into_iter().collect(),
        }
    }
}

impl<T> IntoTriangles for Triangle<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Triangle<Self::Point>; 1]>;

    fn into_triangles(self) -> Self::Output {
        ArrayVec::from([self])
    }
}

impl<T> IntoTriangles for Quad<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Triangle<Self::Point>; 2]>;

    fn into_triangles(self) -> Self::Output {
        let Quad { a, b, c, d } = self;
        ArrayVec::from(
            [
                Triangle::new(a.clone(), b, c.clone()),
                Triangle::new(c, d, a),
            ],
        )
    }
}

impl<T> IntoTriangles for Polygon<T>
where
    T: Clone,
{
    type Output = Vec<Triangle<Self::Point>>;

    fn into_triangles(self) -> Self::Output {
        match self {
            Polygon::Triangle(triangle) => triangle.into_triangles().into_iter().collect(),
            Polygon::Quad(quad) => quad.into_triangles().into_iter().collect(),
        }
    }
}

impl<T> IntoSubdivisions for Triangle<T>
where
    T: Clone + Interpolate,
{
    type Output = ArrayVec<[Triangle<Self::Point>; 2]>;

    fn into_subdivisions(self) -> Self::Output {
        let Triangle { a, b, c } = self;
        let ac = a.midpoint(&c);
        ArrayVec::from(
            [
                Triangle::new(b.clone(), ac.clone(), a),
                Triangle::new(c, ac, b),
            ],
        )
    }
}

impl<T> IntoSubdivisions for Quad<T>
where
    T: Clone + Interpolate,
{
    type Output = ArrayVec<[Quad<Self::Point>; 4]>;

    fn into_subdivisions(self) -> Self::Output {
        let Quad { a, b, c, d } = self;
        let ab = a.midpoint(&b);
        let bc = b.midpoint(&c);
        let cd = c.midpoint(&d);
        let da = d.midpoint(&a);
        let ac = a.midpoint(&c); // Diagonal.
        ArrayVec::from(
            [
                Quad::new(a, ab.clone(), ac.clone(), da.clone()),
                Quad::new(ab, b, bc.clone(), ac.clone()),
                Quad::new(ac.clone(), bc, c, cd.clone()),
                Quad::new(da, ac, cd, d),
            ],
        )
    }
}

impl<T> IntoTetrahedrons for Quad<T>
where
    T: Clone + Interpolate,
{
    fn into_tetrahedrons(self) -> ArrayVec<[Triangle<Self::Point>; 4]> {
        let Quad { a, b, c, d } = self;
        let ac = a.midpoint(&c); // Diagonal.
        ArrayVec::from(
            [
                Triangle::new(a.clone(), b.clone(), ac.clone()),
                Triangle::new(b, c.clone(), ac.clone()),
                Triangle::new(c, d.clone(), ac.clone()),
                Triangle::new(d, a, ac),
            ],
        )
    }
}

impl<T> IntoSubdivisions for Polygon<T>
where
    T: Clone + Interpolate,
{
    type Output = Vec<Self>;

    fn into_subdivisions(self) -> Self::Output {
        match self {
            Polygon::Triangle(triangle) => {
                triangle
                    .into_subdivisions()
                    .into_iter()
                    .map(|triangle| triangle.into())
                    .collect()
            }
            Polygon::Quad(quad) => {
                quad.into_subdivisions()
                    .into_iter()
                    .map(|quad| quad.into())
                    .collect()
            }
        }
    }
}

pub trait Points<P>: Sized
where
    P: IntoPoints,
{
    fn points(self) -> Decompose<Self, P, P::Point, P::Output>;
}

impl<I, P> Points<P> for I
where
    I: Iterator<Item = P>,
    P: IntoPoints,
    P::Point: Clone,
{
    fn points(self) -> Decompose<Self, P, P::Point, P::Output> {
        Decompose::new(self, P::into_points)
    }
}

pub trait Lines<P>: Sized
where
    P: IntoLines,
{
    fn lines(self) -> Decompose<Self, P, Line<P::Point>, P::Output>;
}

impl<I, P> Lines<P> for I
where
    I: Iterator<Item = P>,
    P: IntoLines,
    P::Point: Clone,
{
    fn lines(self) -> Decompose<Self, P, Line<P::Point>, P::Output> {
        Decompose::new(self, P::into_lines)
    }
}

pub trait Triangulate<P>: Sized
where
    P: IntoTriangles,
{
    fn triangulate(self) -> Decompose<Self, P, Triangle<P::Point>, P::Output>;
}

impl<I, P> Triangulate<P> for I
where
    I: Iterator<Item = P>,
    P: IntoTriangles,
    P::Point: Clone,
{
    fn triangulate(self) -> Decompose<Self, P, Triangle<P::Point>, P::Output> {
        Decompose::new(self, P::into_triangles)
    }
}

pub trait Subdivide<P>: Sized
where
    P: IntoSubdivisions,
    P::Point: Clone + Interpolate,
{
    fn subdivide(self) -> Decompose<Self, P, P, P::Output>;
}

impl<I, P> Subdivide<P> for I
where
    I: Iterator<Item = P>,
    P: IntoSubdivisions,
    P::Point: Clone + Interpolate,
{
    fn subdivide(self) -> Decompose<Self, P, P, P::Output> {
        Decompose::new(self, P::into_subdivisions)
    }
}

pub trait Tetrahedrons<T>: Sized {
    #[allow(type_complexity)]
    fn tetrahedrons(self) -> Decompose<Self, Quad<T>, Triangle<T>, ArrayVec<[Triangle<T>; 4]>>;
}

impl<I, T> Tetrahedrons<T> for I
where
    I: Iterator<Item = Quad<T>>,
    T: Clone + Interpolate,
{
    #[allow(type_complexity)]
    fn tetrahedrons(self) -> Decompose<Self, Quad<T>, Triangle<T>, ArrayVec<[Triangle<T>; 4]>> {
        Decompose::new(self, Quad::into_tetrahedrons)
    }
}

fn remap<I, P, R, F>(n: usize, primitives: I, f: F) -> Vec<P>
where
    I: IntoIterator<Item = P>,
    R: IntoIterator<Item = P>,
    F: Fn(P) -> R,
{
    let mut primitives: Vec<_> = primitives.into_iter().collect();
    for _ in 0..n {
        primitives = primitives.into_iter().flat_map(&f).collect();
    }
    primitives
}
<commit_msg>Add comment about dubious `remap` function.<commit_after>//! This module provides a generic iterator and traits for decomposing
//! primitives and tessellating polygons.

use arrayvec::ArrayVec;
use std::collections::VecDeque;
use std::iter::IntoIterator;
use std::vec;

use math::{self, FScalar};
use super::primitive::{Line, Polygon, Polygonal, Primitive, Triangle, Quad};

// A type `F` constrained to `Fn(P, D) -> R` could be used here, but it would
// not be possible to name that type for anything but functions (not closures).
// Instead of a limited and somewhat redundant type `F`, just use `fn(P, D) ->
// R` for the member `f`.
pub struct Decompose<I, P, Q, R>
where
    R: IntoIterator<Item = Q>,
{
    input: I,
    output: VecDeque<Q>,
    f: fn(P) -> R,
}

impl<I, P, Q, R> Decompose<I, P, Q, R>
where
    R: IntoIterator<Item = Q>,
{
    pub(super) fn new(input: I, f: fn(P) -> R) -> Self {
        Decompose {
            input: input,
            output: VecDeque::new(),
            f: f,
        }
    }
}

impl<I, P, R> Decompose<I, P, P, R>
where
    I: Iterator<Item = P>,
    R: IntoIterator<Item = P>,
{
    // TODO: This is questionable, but acts as a replacement for optional
    //       parameters used by the `Into*` traits. In particular,
    //       `into_subdivisions` no longer accepts a parameter `n`, and `remap`
    //       can be used to emulate that behavior. This is especially useful
    //       for larger `n` values, where chaining calls to `subdivide` is not
    //       practical.
    pub fn remap(self, n: usize) -> Decompose<vec::IntoIter<P>, P, P, R> {
        let Decompose { input, output, f } = self;
        Decompose::new(
            output
                .into_iter()
                .rev()
                .chain(remap(n, input, f))
                .collect::<Vec<_>>() // TODO: Only needed to name the iterator.
                .into_iter(),
            f,
        )
    }
}

impl<I, P, Q, R> Iterator for Decompose<I, P, Q, R>
where
    I: Iterator<Item = P>,
    R: IntoIterator<Item = Q>,
{
    type Item = Q;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(primitive) = self.output.pop_front() {
                return Some(primitive);
            }
            if let Some(primitive) = self.input.next() {
                self.output.extend((self.f)(primitive));
            }
            else {
                return None;
            }
        }
    }
}

pub trait Interpolate: math::Interpolate<FScalar> {}

impl<T> Interpolate for T
where
    T: math::Interpolate<FScalar>,
{
}

pub trait IntoPoints: Primitive {
    type Output: IntoIterator<Item = Self::Point>;

    fn into_points(self) -> Self::Output;
}

pub trait IntoLines: Primitive {
    type Output: IntoIterator<Item = Line<Self::Point>>;

    fn into_lines(self) -> Self::Output;
}

pub trait IntoTriangles: Polygonal {
    type Output: IntoIterator<Item = Triangle<Self::Point>>;

    fn into_triangles(self) -> Self::Output;
}

pub trait IntoSubdivisions: Polygonal
where
    Self::Point: Clone + Interpolate,
{
    type Output: IntoIterator<Item = Self>;

    fn into_subdivisions(self) -> Self::Output;
}

pub trait IntoTetrahedrons: Polygonal
where
    Self::Point: Clone + Interpolate,
{
    fn into_tetrahedrons(self) -> ArrayVec<[Triangle<Self::Point>; 4]>;
}

impl<T> IntoPoints for Line<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Self::Point; 2]>;

    fn into_points(self) -> Self::Output {
        let Line { a, b } = self;
        ArrayVec::from([a, b])
    }
}

impl<T> IntoPoints for Triangle<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Self::Point; 3]>;

    fn into_points(self) -> Self::Output {
        let Triangle { a, b, c } = self;
        ArrayVec::from([a, b, c])
    }
}

impl<T> IntoPoints for Quad<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Self::Point; 4]>;

    fn into_points(self) -> Self::Output {
        let Quad { a, b, c, d } = self;
        ArrayVec::from([a, b, c, d])
    }
}

impl<T> IntoPoints for Polygon<T>
where
    T: Clone,
{
    type Output = Vec<Self::Point>;

    fn into_points(self) -> Self::Output {
        match self {
            Polygon::Triangle(triangle) => triangle.into_points().into_iter().collect(),
            Polygon::Quad(quad) => quad.into_points().into_iter().collect(),
        }
    }
}

impl<T> IntoLines for Line<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Line<Self::Point>; 1]>;

    fn into_lines(self) -> Self::Output {
        ArrayVec::from([self])
    }
}

impl<T> IntoLines for Triangle<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Line<Self::Point>; 3]>;

    fn into_lines(self) -> Self::Output {
        let Triangle { a, b, c } = self;
        ArrayVec::from(
            [
                Line::new(a.clone(), b.clone()),
                Line::new(b, c.clone()),
                Line::new(c, a),
            ],
        )
    }
}

impl<T> IntoLines for Quad<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Line<Self::Point>; 4]>;

    fn into_lines(self) -> Self::Output {
        let Quad { a, b, c, d } = self;
        ArrayVec::from(
            [
                Line::new(a.clone(), b.clone()),
                Line::new(b, c.clone()),
                Line::new(c, d.clone()),
                Line::new(d, a),
            ],
        )
    }
}

impl<T> IntoLines for Polygon<T>
where
    T: Clone,
{
    type Output = Vec<Line<Self::Point>>;

    fn into_lines(self) -> Self::Output {
        match self {
            Polygon::Triangle(triangle) => triangle.into_lines().into_iter().collect(),
            Polygon::Quad(quad) => quad.into_lines().into_iter().collect(),
        }
    }
}

impl<T> IntoTriangles for Triangle<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Triangle<Self::Point>; 1]>;

    fn into_triangles(self) -> Self::Output {
        ArrayVec::from([self])
    }
}

impl<T> IntoTriangles for Quad<T>
where
    T: Clone,
{
    type Output = ArrayVec<[Triangle<Self::Point>; 2]>;

    fn into_triangles(self) -> Self::Output {
        let Quad { a, b, c, d } = self;
        ArrayVec::from(
            [
                Triangle::new(a.clone(), b, c.clone()),
                Triangle::new(c, d, a),
            ],
        )
    }
}

impl<T> IntoTriangles for Polygon<T>
where
    T: Clone,
{
    type Output = Vec<Triangle<Self::Point>>;

    fn into_triangles(self) -> Self::Output {
        match self {
            Polygon::Triangle(triangle) => triangle.into_triangles().into_iter().collect(),
            Polygon::Quad(quad) => quad.into_triangles().into_iter().collect(),
        }
    }
}

impl<T> IntoSubdivisions for Triangle<T>
where
    T: Clone + Interpolate,
{
    type Output = ArrayVec<[Triangle<Self::Point>; 2]>;

    fn into_subdivisions(self) -> Self::Output {
        let Triangle { a, b, c } = self;
        let ac = a.midpoint(&c);
        ArrayVec::from(
            [
                Triangle::new(b.clone(), ac.clone(), a),
                Triangle::new(c, ac, b),
            ],
        )
    }
}

impl<T> IntoSubdivisions for Quad<T>
where
    T: Clone + Interpolate,
{
    type Output = ArrayVec<[Quad<Self::Point>; 4]>;

    fn into_subdivisions(self) -> Self::Output {
        let Quad { a, b, c, d } = self;
        let ab = a.midpoint(&b);
        let bc = b.midpoint(&c);
        let cd = c.midpoint(&d);
        let da = d.midpoint(&a);
        let ac = a.midpoint(&c); // Diagonal.
        ArrayVec::from(
            [
                Quad::new(a, ab.clone(), ac.clone(), da.clone()),
                Quad::new(ab, b, bc.clone(), ac.clone()),
                Quad::new(ac.clone(), bc, c, cd.clone()),
                Quad::new(da, ac, cd, d),
            ],
        )
    }
}

impl<T> IntoTetrahedrons for Quad<T>
where
    T: Clone + Interpolate,
{
    fn into_tetrahedrons(self) -> ArrayVec<[Triangle<Self::Point>; 4]> {
        let Quad { a, b, c, d } = self;
        let ac = a.midpoint(&c); // Diagonal.
        ArrayVec::from(
            [
                Triangle::new(a.clone(), b.clone(), ac.clone()),
                Triangle::new(b, c.clone(), ac.clone()),
                Triangle::new(c, d.clone(), ac.clone()),
                Triangle::new(d, a, ac),
            ],
        )
    }
}

impl<T> IntoSubdivisions for Polygon<T>
where
    T: Clone + Interpolate,
{
    type Output = Vec<Self>;

    fn into_subdivisions(self) -> Self::Output {
        match self {
            Polygon::Triangle(triangle) => {
                triangle
                    .into_subdivisions()
                    .into_iter()
                    .map(|triangle| triangle.into())
                    .collect()
            }
            Polygon::Quad(quad) => {
                quad.into_subdivisions()
                    .into_iter()
                    .map(|quad| quad.into())
                    .collect()
            }
        }
    }
}

pub trait Points<P>: Sized
where
    P: IntoPoints,
{
    fn points(self) -> Decompose<Self, P, P::Point, P::Output>;
}

impl<I, P> Points<P> for I
where
    I: Iterator<Item = P>,
    P: IntoPoints,
    P::Point: Clone,
{
    fn points(self) -> Decompose<Self, P, P::Point, P::Output> {
        Decompose::new(self, P::into_points)
    }
}

pub trait Lines<P>: Sized
where
    P: IntoLines,
{
    fn lines(self) -> Decompose<Self, P, Line<P::Point>, P::Output>;
}

impl<I, P> Lines<P> for I
where
    I: Iterator<Item = P>,
    P: IntoLines,
    P::Point: Clone,
{
    fn lines(self) -> Decompose<Self, P, Line<P::Point>, P::Output> {
        Decompose::new(self, P::into_lines)
    }
}

pub trait Triangulate<P>: Sized
where
    P: IntoTriangles,
{
    fn triangulate(self) -> Decompose<Self, P, Triangle<P::Point>, P::Output>;
}

impl<I, P> Triangulate<P> for I
where
    I: Iterator<Item = P>,
    P: IntoTriangles,
    P::Point: Clone,
{
    fn triangulate(self) -> Decompose<Self, P, Triangle<P::Point>, P::Output> {
        Decompose::new(self, P::into_triangles)
    }
}

pub trait Subdivide<P>: Sized
where
    P: IntoSubdivisions,
    P::Point: Clone + Interpolate,
{
    fn subdivide(self) -> Decompose<Self, P, P, P::Output>;
}

impl<I, P> Subdivide<P> for I
where
    I: Iterator<Item = P>,
    P: IntoSubdivisions,
    P::Point: Clone + Interpolate,
{
    fn subdivide(self) -> Decompose<Self, P, P, P::Output> {
        Decompose::new(self, P::into_subdivisions)
    }
}

pub trait Tetrahedrons<T>: Sized {
    #[allow(type_complexity)]
    fn tetrahedrons(self) -> Decompose<Self, Quad<T>, Triangle<T>, ArrayVec<[Triangle<T>; 4]>>;
}

impl<I, T> Tetrahedrons<T> for I
where
    I: Iterator<Item = Quad<T>>,
    T: Clone + Interpolate,
{
    #[allow(type_complexity)]
    fn tetrahedrons(self) -> Decompose<Self, Quad<T>, Triangle<T>, ArrayVec<[Triangle<T>; 4]>> {
        Decompose::new(self, Quad::into_tetrahedrons)
    }
}

fn remap<I, P, R, F>(n: usize, primitives: I, f: F) -> Vec<P>
where
    I: IntoIterator<Item = P>,
    R: IntoIterator<Item = P>,
    F: Fn(P) -> R,
{
    let mut primitives: Vec<_> = primitives.into_iter().collect();
    for _ in 0..n {
        primitives = primitives.into_iter().flat_map(&f).collect();
    }
    primitives
}
<|endoftext|>


<commit_before>use devices::{NodeId, ServiceId, ServiceKind};
use util::Exactly;
use values;

use serde::ser::Serializer;
use serde::de::Deserializer;

use std::cmp;

fn merge<T>(mut a: Vec<T>, mut b: Vec<T>) -> Vec<T> where T: Ord {
    a.append(&mut b);
    a.sort();
    a.dedup();
    a
}

/// A request for one or more nodes.
///
///
/// # Example
///
/// ```
/// use fxbox_taxonomy::requests::*;
/// use fxbox_taxonomy::devices::*;
///
/// let request = NodeRequest::new()
///   .with_tags(vec!["entrance".to_owned()])
///   .with_inputs(vec![InputRequest::new() /* can be more restrictive */]);
/// ```
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct NodeRequest {
    /// If `Exactly(id)`, return only the node with the corresponding id.
    #[serde(default)]
    pub id: Exactly<NodeId>,

    ///  Restrict results to nodes that have all the tags in `tags`.
    #[serde(default)]
    pub tags: Vec<String>,

    /// Restrict results to nodes that have all the inputs in `inputs`.
    #[serde(default)]
    pub inputs: Vec<InputRequest>,

    /// Restrict results to nodes that have all the outputs in `outputs`.
    #[serde(default)]
    pub outputs: Vec<OutputRequest>,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

impl NodeRequest {
    /// Create a new request that accepts all nodes.
    pub fn new() -> Self {
        Self::default()
    }

    /// Request for a node with a specific id.
    pub fn with_id(self, id: NodeId) -> Self {
        NodeRequest {
            id: self.id.and(Exactly::Exactly(id)),
            .. self
        }
    }

    ///  Restrict results to nodes that have all the tags in `tags`.
    pub fn with_tags(self, tags: Vec<String>) -> Self {
        NodeRequest {
            tags: merge(self.tags, tags),
            .. self
        }
    }

    /// Restrict results to nodes that have all the inputs in `inputs`.
    pub fn with_inputs(mut self, mut inputs: Vec<InputRequest>) -> Self {
        NodeRequest {
            inputs: {self.inputs.append(&mut inputs); self.inputs},
            .. self
        }
    }

    /// Restrict results to nodes that have all the outputs in `outputs`.
    pub fn with_outputs(mut self, mut outputs: Vec<OutputRequest>) -> Self {
        NodeRequest {
            outputs: {self.outputs.append(&mut outputs); self.outputs},
            .. self
        }
    }

    /// Restrict results to nodes that are accepted by two requests.
    pub fn and(mut self, mut other: NodeRequest) -> Self {
        NodeRequest {
            id: self.id.and(other.id),
            tags: merge(self.tags, other.tags),
            inputs: {self.inputs.append(&mut other.inputs); self.inputs},
            outputs: {self.outputs.append(&mut other.outputs); self.outputs},
            private: (),
        }
    }
}

/// A request for one or more input services.
///
///
/// # Example
///
/// ```
/// use fxbox_taxonomy::requests::*;
/// use fxbox_taxonomy::devices::*;
///
/// let request = InputRequest::new()
///   .with_parent(NodeId::new("foxbox".to_owned()))
///   .with_kind(ServiceKind::CurrentTimeOfDay);
/// ```
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct InputRequest {
    /// If `Exactly(id)`, return only the service with the corresponding id.
    #[serde(default)]
    pub id: Exactly<ServiceId>,

    /// If `Eactly(id)`, return only services that are children of
    /// node `id`.
    #[serde(default)]
    pub parent: Exactly<NodeId>,

    ///  Restrict results to services that have all the tags in `tags`.
    #[serde(default)]
    pub tags: Vec<String>,

    /// If `Exatly(k)`, restrict results to services that produce values
    /// of kind `k`.
    #[serde(default)]
    pub kind: Exactly<ServiceKind>,

    /// If `Some(r)`, restrict results to services that support polling
    /// with the acceptable period.
    #[serde(default)]
    pub poll: Option<Period>,

    /// If `Some(r)`, restrict results to services that support trigger
    /// with the acceptable period.
    #[serde(default)]
    pub trigger: Option<Period>,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}
impl InputRequest {
    /// Create a new request that accepts all input services.
    pub fn new() -> Self {
        Self::default()
    }

    /// Restrict to a service with a specific id.
    pub fn with_id(self, id: ServiceId) -> Self {
        InputRequest {
            id: self.id.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Restrict to a service with a specific parent.
    pub fn with_parent(self, id: NodeId) -> Self {
        InputRequest {
            parent: self.parent.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Restrict to a service with a specific kind.
    pub fn with_kind(self, kind: ServiceKind) -> Self {
        InputRequest {
            kind: self.kind.and(Exactly::Exactly(kind)),
            .. self
        }
    }

    ///  Restrict to services that have all the tags in `tags`.
    pub fn with_tags(self, tags: Vec<String>) -> Self {
        InputRequest {
            tags: merge(self.tags, tags),
            .. self
        }
    }

    /// Restrict to services that support polling with the acceptable
    /// period
    pub fn with_poll(self, period: Period) -> Self {
        InputRequest {
            poll: Period::and_option(self.poll, Some(period)),
            .. self
        }
    }

    /// Restrict to services that support trigger with the acceptable
    /// period
    pub fn with_trigger(self, period: Period) -> Self {
        InputRequest {
            trigger: Period::and_option(self.trigger, Some(period)),
            .. self
        }
    }

    /// Restrict to services that are accepted by two requests.
    pub fn and(self, other: Self) -> Self {
        InputRequest {
            id: self.id.and(other.id),
            parent: self.parent.and(other.parent),
            tags: merge(self.tags, other.tags),
            kind: self.kind.and(other.kind),
            poll: Period::and_option(self.poll, other.poll),
            trigger: Period::and_option(self.trigger, other.trigger),
            private: (),
        }
    }
}

/// A request for one or more output services.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct OutputRequest {
    /// If `Exactly(id)`, return only the service with the corresponding id.
    #[serde(default)]
    pub id: Exactly<ServiceId>,

    /// If `Exactly(id)`, return only services that are immediate children
    /// of node `id`.
    #[serde(default)]
    pub parent: Exactly<NodeId>,

    ///  Restrict results to services that have all the tags in `tags`.
    #[serde(default)]
    pub tags: Vec<String>,

    /// If `Exactly(k)`, restrict results to services that accept values
    /// of kind `k`.
    #[serde(default)]
    pub kind: Exactly<ServiceKind>,

    /// If `Some(r)`, restrict results to services that support pushing
    /// with the acceptable period.
    #[serde(default)]
    pub push: Option<Period>,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

impl OutputRequest {
    /// Create a new request that accepts all input services.
    pub fn new() -> Self {
        OutputRequest::default()
    }

    /// Request to a service with a specific id.
    pub fn with_id(self, id: ServiceId) -> Self {
        OutputRequest {
            id: self.id.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Request to services with a specific parent.
    pub fn with_parent(self, id: NodeId) -> Self {
        OutputRequest {
            parent: self.parent.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Request to services with a specific kind.
    pub fn with_kind(self, kind: ServiceKind) -> Self {
        OutputRequest {
            kind: self.kind.and(Exactly::Exactly(kind)),
            .. self
        }
    }

    ///  Restrict to services that have all the tags in `tags`.
    pub fn with_tags(self, tags: Vec<String>) -> Self {
        OutputRequest {
            tags: merge(self.tags, tags),
            .. self
        }
    }

    /// Restrict to services that support push with the acceptable
    /// period
    pub fn with_push(self, period: Period) -> Self {
        OutputRequest {
            push: Period::and_option(self.push, Some(period)),
            .. self
        }
    }

    /// Restrict results to services that are accepted by two requests.
    pub fn and(self, other: Self) -> Self {
        OutputRequest {
            id: self.id.and(other.id),
            parent: self.parent.and(other.parent),
            tags: merge(self.tags, other.tags),
            kind: self.kind.and(other.kind),
            push: Period::and_option(self.push, other.push),
            private: (),
        }
    }
}

/// An acceptable interval of time.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Period {
    #[serde(default)]
    pub min: Option<values::ValDuration>,
    #[serde(default)]
    pub max: Option<values::ValDuration>,
}
impl Period {
    fn and(self, other: Self) -> Self {
        let min = match (self.min, other.min) {
            (None, x@_) => x,
            (x@_, None) => x,
            (Some(min1), Some(min2)) => Some(cmp::max(min1, min2))
        };
        let max = match (self.max, other.max) {
            (None, x@_) => x,
            (x@_, None) => x,
            (Some(max1), Some(max2)) => Some(cmp::min(max1, max2))
        };
        Period {
            min: min,
            max: max
        }
    }

    fn and_option(a: Option<Self>, b: Option<Self>) -> Option<Self> {
        match (a, b) {
            (None, x@_) => x,
            (x@_, None) => x,
            (Some(a), Some(b)) => Some(a.and(b))
        }
    }
}
<commit_msg>Period::match<commit_after>use devices::{NodeId, ServiceId, ServiceKind};
use util::Exactly;
use values;

use serde::ser::Serializer;
use serde::de::Deserializer;

use std::cmp;

fn merge<T>(mut a: Vec<T>, mut b: Vec<T>) -> Vec<T> where T: Ord {
    a.append(&mut b);
    a.sort();
    a.dedup();
    a
}

/// A request for one or more nodes.
///
///
/// # Example
///
/// ```
/// use fxbox_taxonomy::requests::*;
/// use fxbox_taxonomy::devices::*;
///
/// let request = NodeRequest::new()
///   .with_tags(vec!["entrance".to_owned()])
///   .with_inputs(vec![InputRequest::new() /* can be more restrictive */]);
/// ```
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct NodeRequest {
    /// If `Exactly(id)`, return only the node with the corresponding id.
    #[serde(default)]
    pub id: Exactly<NodeId>,

    ///  Restrict results to nodes that have all the tags in `tags`.
    #[serde(default)]
    pub tags: Vec<String>,

    /// Restrict results to nodes that have all the inputs in `inputs`.
    #[serde(default)]
    pub inputs: Vec<InputRequest>,

    /// Restrict results to nodes that have all the outputs in `outputs`.
    #[serde(default)]
    pub outputs: Vec<OutputRequest>,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

impl NodeRequest {
    /// Create a new request that accepts all nodes.
    pub fn new() -> Self {
        Self::default()
    }

    /// Request for a node with a specific id.
    pub fn with_id(self, id: NodeId) -> Self {
        NodeRequest {
            id: self.id.and(Exactly::Exactly(id)),
            .. self
        }
    }

    ///  Restrict results to nodes that have all the tags in `tags`.
    pub fn with_tags(self, tags: Vec<String>) -> Self {
        NodeRequest {
            tags: merge(self.tags, tags),
            .. self
        }
    }

    /// Restrict results to nodes that have all the inputs in `inputs`.
    pub fn with_inputs(mut self, mut inputs: Vec<InputRequest>) -> Self {
        NodeRequest {
            inputs: {self.inputs.append(&mut inputs); self.inputs},
            .. self
        }
    }

    /// Restrict results to nodes that have all the outputs in `outputs`.
    pub fn with_outputs(mut self, mut outputs: Vec<OutputRequest>) -> Self {
        NodeRequest {
            outputs: {self.outputs.append(&mut outputs); self.outputs},
            .. self
        }
    }

    /// Restrict results to nodes that are accepted by two requests.
    pub fn and(mut self, mut other: NodeRequest) -> Self {
        NodeRequest {
            id: self.id.and(other.id),
            tags: merge(self.tags, other.tags),
            inputs: {self.inputs.append(&mut other.inputs); self.inputs},
            outputs: {self.outputs.append(&mut other.outputs); self.outputs},
            private: (),
        }
    }
}

/// A request for one or more input services.
///
///
/// # Example
///
/// ```
/// use fxbox_taxonomy::requests::*;
/// use fxbox_taxonomy::devices::*;
///
/// let request = InputRequest::new()
///   .with_parent(NodeId::new("foxbox".to_owned()))
///   .with_kind(ServiceKind::CurrentTimeOfDay);
/// ```
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct InputRequest {
    /// If `Exactly(id)`, return only the service with the corresponding id.
    #[serde(default)]
    pub id: Exactly<ServiceId>,

    /// If `Eactly(id)`, return only services that are children of
    /// node `id`.
    #[serde(default)]
    pub parent: Exactly<NodeId>,

    ///  Restrict results to services that have all the tags in `tags`.
    #[serde(default)]
    pub tags: Vec<String>,

    /// If `Exatly(k)`, restrict results to services that produce values
    /// of kind `k`.
    #[serde(default)]
    pub kind: Exactly<ServiceKind>,

    /// If `Some(r)`, restrict results to services that support polling
    /// with the acceptable period.
    #[serde(default)]
    pub poll: Option<Period>,

    /// If `Some(r)`, restrict results to services that support trigger
    /// with the acceptable period.
    #[serde(default)]
    pub trigger: Option<Period>,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}
impl InputRequest {
    /// Create a new request that accepts all input services.
    pub fn new() -> Self {
        Self::default()
    }

    /// Restrict to a service with a specific id.
    pub fn with_id(self, id: ServiceId) -> Self {
        InputRequest {
            id: self.id.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Restrict to a service with a specific parent.
    pub fn with_parent(self, id: NodeId) -> Self {
        InputRequest {
            parent: self.parent.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Restrict to a service with a specific kind.
    pub fn with_kind(self, kind: ServiceKind) -> Self {
        InputRequest {
            kind: self.kind.and(Exactly::Exactly(kind)),
            .. self
        }
    }

    ///  Restrict to services that have all the tags in `tags`.
    pub fn with_tags(self, tags: Vec<String>) -> Self {
        InputRequest {
            tags: merge(self.tags, tags),
            .. self
        }
    }

    /// Restrict to services that support polling with the acceptable
    /// period
    pub fn with_poll(self, period: Period) -> Self {
        InputRequest {
            poll: Period::and_option(self.poll, Some(period)),
            .. self
        }
    }

    /// Restrict to services that support trigger with the acceptable
    /// period
    pub fn with_trigger(self, period: Period) -> Self {
        InputRequest {
            trigger: Period::and_option(self.trigger, Some(period)),
            .. self
        }
    }

    /// Restrict to services that are accepted by two requests.
    pub fn and(self, other: Self) -> Self {
        InputRequest {
            id: self.id.and(other.id),
            parent: self.parent.and(other.parent),
            tags: merge(self.tags, other.tags),
            kind: self.kind.and(other.kind),
            poll: Period::and_option(self.poll, other.poll),
            trigger: Period::and_option(self.trigger, other.trigger),
            private: (),
        }
    }
}

/// A request for one or more output services.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct OutputRequest {
    /// If `Exactly(id)`, return only the service with the corresponding id.
    #[serde(default)]
    pub id: Exactly<ServiceId>,

    /// If `Exactly(id)`, return only services that are immediate children
    /// of node `id`.
    #[serde(default)]
    pub parent: Exactly<NodeId>,

    ///  Restrict results to services that have all the tags in `tags`.
    #[serde(default)]
    pub tags: Vec<String>,

    /// If `Exactly(k)`, restrict results to services that accept values
    /// of kind `k`.
    #[serde(default)]
    pub kind: Exactly<ServiceKind>,

    /// If `Some(r)`, restrict results to services that support pushing
    /// with the acceptable period.
    #[serde(default)]
    pub push: Option<Period>,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

impl OutputRequest {
    /// Create a new request that accepts all input services.
    pub fn new() -> Self {
        OutputRequest::default()
    }

    /// Request to a service with a specific id.
    pub fn with_id(self, id: ServiceId) -> Self {
        OutputRequest {
            id: self.id.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Request to services with a specific parent.
    pub fn with_parent(self, id: NodeId) -> Self {
        OutputRequest {
            parent: self.parent.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Request to services with a specific kind.
    pub fn with_kind(self, kind: ServiceKind) -> Self {
        OutputRequest {
            kind: self.kind.and(Exactly::Exactly(kind)),
            .. self
        }
    }

    ///  Restrict to services that have all the tags in `tags`.
    pub fn with_tags(self, tags: Vec<String>) -> Self {
        OutputRequest {
            tags: merge(self.tags, tags),
            .. self
        }
    }

    /// Restrict to services that support push with the acceptable
    /// period
    pub fn with_push(self, period: Period) -> Self {
        OutputRequest {
            push: Period::and_option(self.push, Some(period)),
            .. self
        }
    }

    /// Restrict results to services that are accepted by two requests.
    pub fn and(self, other: Self) -> Self {
        OutputRequest {
            id: self.id.and(other.id),
            parent: self.parent.and(other.parent),
            tags: merge(self.tags, other.tags),
            kind: self.kind.and(other.kind),
            push: Period::and_option(self.push, other.push),
            private: (),
        }
    }
}

/// An acceptable interval of time.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Period {
    #[serde(default)]
    pub min: Option<values::ValDuration>,
    #[serde(default)]
    pub max: Option<values::ValDuration>,
}
impl Period {
    pub fn and(self, other: Self) -> Self {
        let min = match (self.min, other.min) {
            (None, x@_) => x,
            (x@_, None) => x,
            (Some(min1), Some(min2)) => Some(cmp::max(min1, min2))
        };
        let max = match (self.max, other.max) {
            (None, x@_) => x,
            (x@_, None) => x,
            (Some(max1), Some(max2)) => Some(cmp::min(max1, max2))
        };
        Period {
            min: min,
            max: max
        }
    }

    pub fn and_option(a: Option<Self>, b: Option<Self>) -> Option<Self> {
        match (a, b) {
            (None, x@_) => x,
            (x@_, None) => x,
            (Some(a), Some(b)) => Some(a.and(b))
        }
    }

    pub fn matches(&self, duration: &values::ValDuration) -> bool {
        if let Some(ref min) = self.min {
            if min > duration {
                return false;
            }
        }
        if let Some(ref max) = self.max {
            if max < duration {
                return false;
            }
        }
        return true;
    }
}
<|endoftext|>