<commit_before>// FIXME Remove once not dev anymore
#![allow(dead_code, unused_imports)]
#[macro_use]
extern crate slog;
extern crate slog_term;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;

extern crate futures;
extern crate hyper;
extern crate tokio_core;
extern crate hyper_tls;
extern crate time;

use std::env;
use std::io::{self, Write};

use serde::{Serialize, Serializer, Deserialize, Deserializer};
use futures::{Future, Stream};
use futures::future;
use slog::*;
use hyper::{Client, Uri, Method, Chunk, Error};
use hyper::header::{Authorization, Accept, UserAgent, qitem};
use hyper::client::Request;
use hyper::client::FutureResponse;
use tokio_core::reactor::Core;

#[derive(Serialize)]
struct HnTopStories {
    values: Vec<i32>,
}

impl Deserialize for HnTopStories {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer
    {
        Deserialize::deserialize(deserializer).map(|arr: Vec<i32>| HnTopStories { values: arr })
    }
}

#[derive(Serialize, Deserialize)]
struct HnItem {
    by: String,
    descendants: i32,
    id: i32,
    kids: Vec<i32>,
    title: String,
    score: i32,
    time: f64,
    #[serde(rename(deserialize = "type"))]
    type_str: String,
    url: String,
}

#[derive(Serialize, Deserialize)]
struct HnUser {
    about: String,
    created: f64,
    id: String,
    karma: i32,
    submitted: Vec<i32>,
}

fn main() {
    let logger = create_loggers();
    info!(logger, "Application started");

    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let client = Client::configure()
        // Does not check the validity of certificate
        .connector(hyper_tls::HttpsConnector::new(4, &handle))
        .build(&handle);
    let endpoint = HnNews::build_default();

    let work = endpoint.request_top_story_ids(&client)
        .and_then(|res| {
            info!(logger,
                  format!("Request to {} finished with status {}",
                          endpoint.get_top_stories_path(),
                          res.status()));
            // Consists of Chunks which is basically a vector of bytes (Vec<u8>)
            res.body()
                .fold(Vec::new(), |mut v, chunk| {
                    v.extend(&chunk[..]);
                    // _ = It's a placeholder. In this context, it means that there isn't enough information for the compiler to infer a type.
                    // http://stackoverflow.com/questions/37215739/what-does-it-mean-to-instantiate-a-rust-generic-with-an-underscore
                    future::ok::<_, Error>(v)
                })
                .map(|chunks| String::from_utf8(chunks).unwrap())
        });
    let result = core.run(work).unwrap();
    println!("{}", result);
}
fn common_headers(req: &mut Request) {
    req.headers_mut().set(UserAgent(String::from("rust-api")))
}
fn consume_request(client: &Client<hyper_tls::HttpsConnector>, request: Request) -> FutureResponse {
    client.request(request)
}

fn create_loggers() -> Logger {
    let drain = slog_term::streamer().build().fuse();
    let root_logger = Logger::root(drain, o!());
    return root_logger;
}

struct HnNews {
    base_url: String,
    top_news_suffix: String,
    item_suffix: String,
    max_item_suffix: String,
    json_suffix: String,
}

impl HnNews {
    pub fn build_default() -> HnNews {
        let e = HnNews {
            base_url: String::from("https://hacker-news.firebaseio.com/v0/"),
            top_news_suffix: String::from("topstories"),
            item_suffix: String::from("item/"),
            max_item_suffix: String::from("maxitem"),
            json_suffix: String::from(".json"),
        };
        e
    }

    pub fn get_top_stories_path(&self) -> String {
        combine_strings(vec![&self.base_url, &self.top_news_suffix, &self.json_suffix])
    }
    pub fn get_max_item_path(&self) -> String {
        combine_strings(vec![&self.base_url, &self.max_item_suffix, &self.json_suffix])
    }
    pub fn get_item_path(&self, id: &str) -> String {
        combine_strings(vec![&self.base_url, &self.item_suffix, id, &self.json_suffix])
    }

    fn request_top_story_ids(&self, client: &Client<hyper_tls::HttpsConnector>) -> FutureResponse {
        let url = parse_url_from_str(&self.get_top_stories_path());
        let mut request = Request::new(Method::Get, url);
        common_headers(&mut request);
        client.request(request)
    }
}

fn combine_strings(strings: Vec<&str>) -> String {
    let combine = strings.join("");
    combine
}

fn parse_url_from_str(url_str: &str) -> Uri {
    let url_str = String::from(url_str);
    let url = url_str.parse::<hyper::Uri>().unwrap();
    url
}

#[test]
fn parse_url_from_str_test() {
    let url = parse_url_from_str("http://www.google.fi");
    assert_eq!("http", url.scheme().unwrap());
    assert_eq!("www.google.fi", url.authority().unwrap());
}

#[test]
fn combine_strings_test() {
    let a = "Abc";
    let b = "Abc";
    let mut vec = Vec::new();
    vec.push(a);
    vec.push(b);
    assert_eq!("AbcAbc", combine_strings(vec));
    assert!(a.len() > 1);
    assert!(b.len() > 1);
}

#[test]
fn hn_item_serde_test() {
    use std::fs::File;
    use std::io::prelude::*;
    let mut contents = String::new();
    File::open("res/test/item.json")
        .and_then(|mut file| file.read_to_string(&mut contents))
        .unwrap();
    let deserialized: HnItem = serde_json::from_str(&contents).unwrap();
    assert_eq!(71, deserialized.descendants);
    assert_eq!("dhouston", deserialized.by);
    assert_eq!(8863, deserialized.id);
    assert_eq!(111, deserialized.score);
    assert_eq!(1175714200.0f64, deserialized.time);
    assert_eq!("My YC app: Dropbox - Throw away your USB drive",
               deserialized.title);
    assert_eq!("story", deserialized.type_str);
    assert_eq!("http://www.getdropbox.com/u/2/screencast.html",
               deserialized.url);
}
#[test]
fn hn_top_stories_serde_test() {
    use std::fs::File;
    use std::io::prelude::*;
    let mut contents = String::new();
    File::open("res/test/top-stories.json")
        .and_then(|mut file| file.read_to_string(&mut contents))
        .unwrap();
    let deserialized: HnTopStories = serde_json::from_str(&contents).unwrap();
    assert!(deserialized.values.len() > 3);
}
#[test]
fn hn_user_serde_test() {
    use std::fs::File;
    use std::io::prelude::*;
    let mut contents = String::new();
    File::open("res/test/user.json")
        .and_then(|mut file| file.read_to_string(&mut contents))
        .unwrap();
    let deserialized: HnUser = serde_json::from_str(&contents).unwrap();
    assert_eq!("This is a test", deserialized.about);
    assert_eq!(1173923446.0f64, deserialized.created);
    assert_eq!("jl", deserialized.id);
    assert_eq!(3496, deserialized.karma);
    assert!(deserialized.submitted.len() > 3);
}
<commit_msg>moved tests to module<commit_after>// FIXME Remove once not dev anymore
#![allow(dead_code, unused_imports)]
#[macro_use]
extern crate slog;
extern crate slog_term;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;

extern crate futures;
extern crate hyper;
extern crate tokio_core;
extern crate hyper_tls;
extern crate time;

use std::env;
use std::io::{self, Write};

use serde::{Serialize, Serializer, Deserialize, Deserializer};
use futures::{Future, Stream};
use futures::future;
use slog::*;
use hyper::{Client, Uri, Method, Chunk, Error};
use hyper::header::{Authorization, Accept, UserAgent, qitem};
use hyper::client::Request;
use hyper::client::FutureResponse;
use tokio_core::reactor::Core;

#[derive(Serialize)]
struct HnTopStories {
    values: Vec<i32>,
}

impl Deserialize for HnTopStories {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer
    {
        Deserialize::deserialize(deserializer).map(|arr: Vec<i32>| HnTopStories { values: arr })
    }
}

#[derive(Serialize, Deserialize)]
struct HnItem {
    by: String,
    descendants: i32,
    id: i32,
    kids: Vec<i32>,
    title: String,
    score: i32,
    time: f64,
    #[serde(rename(deserialize = "type"))]
    type_str: String,
    url: String,
}

#[derive(Serialize, Deserialize)]
struct HnUser {
    about: String,
    created: f64,
    id: String,
    karma: i32,
    submitted: Vec<i32>,
}

fn main() {
    let logger = create_loggers();
    info!(logger, "Application started");

    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let client = Client::configure()
        // Does not check the validity of certificate
        .connector(hyper_tls::HttpsConnector::new(4, &handle))
        .build(&handle);
    let endpoint = HnNews::build_default();

    let work = endpoint.request_top_story_ids(&client)
        .and_then(|res| {
            info!(logger,
                  format!("Request to {} finished with status {}",
                          endpoint.get_top_stories_path(),
                          res.status()));
            // Consists of Chunks which is basically a vector of bytes (Vec<u8>)
            res.body()
                .fold(Vec::new(), |mut v, chunk| {
                    v.extend(&chunk[..]);
                    // _ = It's a placeholder. In this context, it means that there isn't enough information for the compiler to infer a type.
                    // http://stackoverflow.com/questions/37215739/what-does-it-mean-to-instantiate-a-rust-generic-with-an-underscore
                    future::ok::<_, Error>(v)
                })
                .map(|chunks| String::from_utf8(chunks).unwrap())
        });
    let result = core.run(work).unwrap();
    println!("{}", result);
}
fn common_headers(req: &mut Request) {
    req.headers_mut().set(UserAgent(String::from("rust-api")))
}
fn consume_request(client: &Client<hyper_tls::HttpsConnector>, request: Request) -> FutureResponse {
    client.request(request)
}

fn create_loggers() -> Logger {
    let drain = slog_term::streamer().build().fuse();
    let root_logger = Logger::root(drain, o!());
    return root_logger;
}

struct HnNews {
    base_url: String,
    top_news_suffix: String,
    item_suffix: String,
    max_item_suffix: String,
    json_suffix: String,
}

impl HnNews {
    pub fn build_default() -> HnNews {
        let e = HnNews {
            base_url: String::from("https://hacker-news.firebaseio.com/v0/"),
            top_news_suffix: String::from("topstories"),
            item_suffix: String::from("item/"),
            max_item_suffix: String::from("maxitem"),
            json_suffix: String::from(".json"),
        };
        e
    }

    pub fn get_top_stories_path(&self) -> String {
        combine_strings(vec![&self.base_url, &self.top_news_suffix, &self.json_suffix])
    }
    pub fn get_max_item_path(&self) -> String {
        combine_strings(vec![&self.base_url, &self.max_item_suffix, &self.json_suffix])
    }
    pub fn get_item_path(&self, id: &str) -> String {
        combine_strings(vec![&self.base_url, &self.item_suffix, id, &self.json_suffix])
    }

    fn request_top_story_ids(&self, client: &Client<hyper_tls::HttpsConnector>) -> FutureResponse {
        let url = parse_url_from_str(&self.get_top_stories_path());
        let mut request = Request::new(Method::Get, url);
        common_headers(&mut request);
        client.request(request)
    }
}

fn combine_strings(strings: Vec<&str>) -> String {
    let combine = strings.join("");
    combine
}

fn parse_url_from_str(url_str: &str) -> Uri {
    let url_str = String::from(url_str);
    let url = url_str.parse::<hyper::Uri>().unwrap();
    url
}

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

    #[test]
    fn parse_url_from_str_test() {
        let url = parse_url_from_str("http://www.google.fi");
        assert_eq!("http", url.scheme().unwrap());
        assert_eq!("www.google.fi", url.authority().unwrap());
    }

    #[test]
    fn combine_strings_test() {
        let a = "Abc";
        let b = "Abc";
        let mut vec = Vec::new();
        vec.push(a);
        vec.push(b);
        assert_eq!("AbcAbc", combine_strings(vec));
        assert!(a.len() > 1);
        assert!(b.len() > 1);
    }

    #[test]
    fn hn_item_serde_test() {
        use std::fs::File;
        use std::io::prelude::*;
        let mut contents = String::new();
        File::open("res/test/item.json")
            .and_then(|mut file| file.read_to_string(&mut contents))
            .unwrap();
        let deserialized: HnItem = serde_json::from_str(&contents).unwrap();
        assert_eq!(71, deserialized.descendants);
        assert_eq!("dhouston", deserialized.by);
        assert_eq!(8863, deserialized.id);
        assert_eq!(111, deserialized.score);
        assert_eq!(1175714200.0f64, deserialized.time);
        assert_eq!("My YC app: Dropbox - Throw away your USB drive",
                   deserialized.title);
        assert_eq!("story", deserialized.type_str);
        assert_eq!("http://www.getdropbox.com/u/2/screencast.html",
                   deserialized.url);
    }
    #[test]
    fn hn_top_stories_serde_test() {
        use std::fs::File;
        use std::io::prelude::*;
        let mut contents = String::new();
        File::open("res/test/top-stories.json")
            .and_then(|mut file| file.read_to_string(&mut contents))
            .unwrap();
        let deserialized: HnTopStories = serde_json::from_str(&contents).unwrap();
        assert!(deserialized.values.len() > 3);
    }
    #[test]
    fn hn_user_serde_test() {
        use std::fs::File;
        use std::io::prelude::*;
        let mut contents = String::new();
        File::open("res/test/user.json")
            .and_then(|mut file| file.read_to_string(&mut contents))
            .unwrap();
        let deserialized: HnUser = serde_json::from_str(&contents).unwrap();
        assert_eq!("This is a test", deserialized.about);
        assert_eq!(1173923446.0f64, deserialized.created);
        assert_eq!("jl", deserialized.id);
        assert_eq!(3496, deserialized.karma);
        assert!(deserialized.submitted.len() > 3);
    }

}
<|endoftext|>


<commit_before>use std::f64::consts::*;

use cssparser::{Parser, Token};

use crate::error::ValueErrorKind;
use crate::parsers::{Parse, ParseError};

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Angle(f64);

impl Angle {
    pub fn new(rad: f64) -> Angle {
        Angle(Angle::normalize(rad))
    }

    pub fn from_degrees(deg: f64) -> Angle {
        Angle(Angle::normalize(deg.to_radians()))
    }

    pub fn from_vector(vx: f64, vy: f64) -> Angle {
        let rad = vy.atan2(vx);

        if rad.is_nan() {
            Angle(0.0)
        } else {
            Angle(Angle::normalize(rad))
        }
    }

    pub fn radians(&self) -> f64 {
        self.0
    }

    pub fn bisect(&self, other: Angle) -> Angle {
        let half_delta = (other.0 - self.0) * 0.5;

        if FRAC_PI_2 < half_delta.abs() {
            Angle(Angle::normalize(self.0 + half_delta - PI))
        } else {
            Angle(Angle::normalize(self.0 + half_delta))
        }
    }

    // Normalizes an angle to [0.0, 2*PI)
    fn normalize(rad: f64) -> f64 {
        let res = rad % (PI * 2.0);
        if res < 0.0 {
            res + PI * 2.0
        } else {
            res
        }
    }
}

// angle:
// https://www.w3.org/TR/SVG/types.html#DataTypeAngle
//
// angle ::= number ("deg" | "grad" | "rad")?
//
impl Parse for Angle {
    type Err = ValueErrorKind;

    fn parse(parser: &mut Parser<'_, '_>) -> Result<Angle, ValueErrorKind> {
        let angle = {
            let token = parser
                .next()
                .map_err(|_| ParseError::new("expected angle"))?;

            match *token {
                Token::Number { value, .. } => Angle::from_degrees(value as f64),

                Token::Dimension {
                    value, ref unit, ..
                } => {
                    let value = f64::from(value);

                    match unit.as_ref() {
                        "deg" => Angle::from_degrees(value),
                        "grad" => Angle::from_degrees(value * 360.0 / 400.0),
                        "rad" => Angle::new(value),
                        _ => {
                            return Err(ValueErrorKind::Parse(ParseError::new(
                                "expected 'deg' | 'grad' | 'rad'",
                            )));
                        }
                    }
                }

                _ => return Err(ValueErrorKind::Parse(ParseError::new("expected angle"))),
            }
        };

        parser
            .expect_exhausted()
            .map_err(|_| ValueErrorKind::Parse(ParseError::new("expected angle")))?;

        Ok(angle)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use float_cmp::ApproxEq;
    use std::f64;

    #[test]
    fn parses_angle() {
        assert_eq!(Angle::parse_str("0"), Ok(Angle::new(0.0)));
        assert_eq!(Angle::parse_str("15"), Ok(Angle::from_degrees(15.0)));
        assert_eq!(Angle::parse_str("180.5deg"), Ok(Angle::from_degrees(180.5)));
        assert_eq!(Angle::parse_str("1rad"), Ok(Angle::new(1.0)));
        assert_eq!(
            Angle::parse_str("-400grad"),
            Ok(Angle::from_degrees(-360.0))
        );

        assert!(Angle::parse_str("").is_err());
        assert!(Angle::parse_str("foo").is_err());
        assert!(Angle::parse_str("300foo").is_err());
    }

    fn test_bisection_angle(
        expected: f64,
        incoming_vx: f64,
        incoming_vy: f64,
        outgoing_vx: f64,
        outgoing_vy: f64,
    ) {
        let i = Angle::from_vector(incoming_vx, incoming_vy);
        let o = Angle::from_vector(outgoing_vx, outgoing_vy);
        let bisected = i.bisect(o);
        assert!(expected.approx_eq(&bisected.radians(), 2.0 * PI * f64::EPSILON, 1));
    }

    #[test]
    fn bisection_angle_is_correct_from_incoming_counterclockwise_to_outgoing() {
        // 1st quadrant
        test_bisection_angle(FRAC_PI_4, 1.0, 0.0, 0.0, 1.0);

        // 2nd quadrant
        test_bisection_angle(FRAC_PI_2 + FRAC_PI_4, 0.0, 1.0, -1.0, 0.0);

        // 3rd quadrant
        test_bisection_angle(PI + FRAC_PI_4, -1.0, 0.0, 0.0, -1.0);

        // 4th quadrant
        test_bisection_angle(PI + FRAC_PI_2 + FRAC_PI_4, 0.0, -1.0, 1.0, 0.0);
    }

    #[test]
    fn bisection_angle_is_correct_from_incoming_clockwise_to_outgoing() {
        // 1st quadrant
        test_bisection_angle(FRAC_PI_4, 0.0, 1.0, 1.0, 0.0);

        // 2nd quadrant
        test_bisection_angle(FRAC_PI_2 + FRAC_PI_4, -1.0, 0.0, 0.0, 1.0);

        // 3rd quadrant
        test_bisection_angle(PI + FRAC_PI_4, 0.0, -1.0, -1.0, 0.0);

        // 4th quadrant
        test_bisection_angle(PI + FRAC_PI_2 + FRAC_PI_4, 1.0, 0.0, 0.0, -1.0);
    }

    #[test]
    fn bisection_angle_is_correct_for_more_than_quarter_turn_angle() {
        test_bisection_angle(0.0, 0.1, -1.0, 0.1, 1.0);

        test_bisection_angle(FRAC_PI_2, 1.0, 0.1, -1.0, 0.1);

        test_bisection_angle(PI, -0.1, 1.0, -0.1, -1.0);

        test_bisection_angle(PI + FRAC_PI_2, -1.0, -0.1, 1.0, -0.1);
    }
}
<commit_msg>Fix rounding error on i386 (#455).<commit_after>use std::f64::consts::*;

use cssparser::{Parser, Token};

use crate::error::ValueErrorKind;
use crate::parsers::{Parse, ParseError};

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Angle(f64);

impl Angle {
    pub fn new(rad: f64) -> Angle {
        Angle(Angle::normalize(rad))
    }

    pub fn from_degrees(deg: f64) -> Angle {
        Angle(Angle::normalize(deg.to_radians()))
    }

    pub fn from_vector(vx: f64, vy: f64) -> Angle {
        let rad = vy.atan2(vx);

        if rad.is_nan() {
            Angle(0.0)
        } else {
            Angle(Angle::normalize(rad))
        }
    }

    pub fn radians(&self) -> f64 {
        self.0
    }

    pub fn bisect(&self, other: Angle) -> Angle {
        let half_delta = (other.0 - self.0) * 0.5;

        if FRAC_PI_2 < half_delta.abs() {
            Angle(Angle::normalize(self.0 + half_delta - PI))
        } else {
            Angle(Angle::normalize(self.0 + half_delta))
        }
    }

    // Normalizes an angle to [0.0, 2*PI)
    fn normalize(rad: f64) -> f64 {
        let res = rad % (PI * 2.0);
        if res.abs() < std::f64::EPSILON {
            res.abs()
        } else if res < 0.0 {
            res + PI * 2.0
        } else {
            res
        }
    }
}

// angle:
// https://www.w3.org/TR/SVG/types.html#DataTypeAngle
//
// angle ::= number ("deg" | "grad" | "rad")?
//
impl Parse for Angle {
    type Err = ValueErrorKind;

    fn parse(parser: &mut Parser<'_, '_>) -> Result<Angle, ValueErrorKind> {
        let angle = {
            let token = parser
                .next()
                .map_err(|_| ParseError::new("expected angle"))?;

            match *token {
                Token::Number { value, .. } => Angle::from_degrees(value as f64),

                Token::Dimension {
                    value, ref unit, ..
                } => {
                    let value = f64::from(value);

                    match unit.as_ref() {
                        "deg" => Angle::from_degrees(value),
                        "grad" => Angle::from_degrees(value * 360.0 / 400.0),
                        "rad" => Angle::new(value),
                        _ => {
                            return Err(ValueErrorKind::Parse(ParseError::new(
                                "expected 'deg' | 'grad' | 'rad'",
                            )));
                        }
                    }
                }

                _ => return Err(ValueErrorKind::Parse(ParseError::new("expected angle"))),
            }
        };

        parser
            .expect_exhausted()
            .map_err(|_| ValueErrorKind::Parse(ParseError::new("expected angle")))?;

        Ok(angle)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use float_cmp::ApproxEq;
    use std::f64;

    #[test]
    fn parses_angle() {
        assert_eq!(Angle::parse_str("0"), Ok(Angle::new(0.0)));
        assert_eq!(Angle::parse_str("15"), Ok(Angle::from_degrees(15.0)));
        assert_eq!(Angle::parse_str("180.5deg"), Ok(Angle::from_degrees(180.5)));
        assert_eq!(Angle::parse_str("1rad"), Ok(Angle::new(1.0)));
        assert_eq!(
            Angle::parse_str("-400grad"),
            Ok(Angle::from_degrees(-360.0))
        );

        assert!(Angle::parse_str("").is_err());
        assert!(Angle::parse_str("foo").is_err());
        assert!(Angle::parse_str("300foo").is_err());
    }

    fn test_bisection_angle(
        expected: f64,
        incoming_vx: f64,
        incoming_vy: f64,
        outgoing_vx: f64,
        outgoing_vy: f64,
    ) {
        let i = Angle::from_vector(incoming_vx, incoming_vy);
        let o = Angle::from_vector(outgoing_vx, outgoing_vy);
        let bisected = i.bisect(o);
        assert!(expected.approx_eq(&bisected.radians(), 2.0 * PI * f64::EPSILON, 1));
    }

    #[test]
    fn bisection_angle_is_correct_from_incoming_counterclockwise_to_outgoing() {
        // 1st quadrant
        test_bisection_angle(FRAC_PI_4, 1.0, 0.0, 0.0, 1.0);

        // 2nd quadrant
        test_bisection_angle(FRAC_PI_2 + FRAC_PI_4, 0.0, 1.0, -1.0, 0.0);

        // 3rd quadrant
        test_bisection_angle(PI + FRAC_PI_4, -1.0, 0.0, 0.0, -1.0);

        // 4th quadrant
        test_bisection_angle(PI + FRAC_PI_2 + FRAC_PI_4, 0.0, -1.0, 1.0, 0.0);
    }

    #[test]
    fn bisection_angle_is_correct_from_incoming_clockwise_to_outgoing() {
        // 1st quadrant
        test_bisection_angle(FRAC_PI_4, 0.0, 1.0, 1.0, 0.0);

        // 2nd quadrant
        test_bisection_angle(FRAC_PI_2 + FRAC_PI_4, -1.0, 0.0, 0.0, 1.0);

        // 3rd quadrant
        test_bisection_angle(PI + FRAC_PI_4, 0.0, -1.0, -1.0, 0.0);

        // 4th quadrant
        test_bisection_angle(PI + FRAC_PI_2 + FRAC_PI_4, 1.0, 0.0, 0.0, -1.0);
    }

    #[test]
    fn bisection_angle_is_correct_for_more_than_quarter_turn_angle() {
        test_bisection_angle(0.0, 0.1, -1.0, 0.1, 1.0);

        test_bisection_angle(FRAC_PI_2, 1.0, 0.1, -1.0, 0.1);

        test_bisection_angle(PI, -0.1, 1.0, -0.1, -1.0);

        test_bisection_angle(PI + FRAC_PI_2, -1.0, -0.1, 1.0, -0.1);
    }
}
<|endoftext|>


<commit_before>//! Implementation of input backend trait for types provided by `libinput`

use backend::SeatInternal;
use backend::input::{InputBackend, InputHandler, Seat, SeatCapabilities};
use input::{Libinput, Device, Seat as LibinputSeat, DeviceCapability};
use input::event::*;

use std::io::Error as IoError;
use std::collections::hash_map::{DefaultHasher, Entry, HashMap};
use std::hash::{Hash, Hasher};

pub struct LibinputInputBackend {
    context: Libinput,
    devices: Vec<Device>,
    seats: HashMap<LibinputSeat, Seat>,
    handler: Option<Box<InputHandler<LibinputInputBackend> + 'static>>,
    logger: ::slog::Logger,
}

impl InputBackend for LibinputInputBackend {
    type InputConfig = [Device];
    type EventError = IoError;

    fn set_handler<H: InputHandler<Self> + 'static>(&mut self, mut handler: H) {
        if self.handler.is_some() {
            self.clear_handler();
        }
        info!(self.logger, "New input handler set.");
        for seat in self.seats.values() {
            trace!(self.logger, "Calling on_seat_created with {:?}", seat);
            handler.on_seat_created(&seat);
        }
        self.handler = Some(Box::new(handler));
    }

    fn get_handler(&mut self) -> Option<&mut InputHandler<Self>> {
        self.handler
            .as_mut()
            .map(|handler| handler as &mut InputHandler<Self>)
    }

    fn clear_handler(&mut self) {
        if let Some(mut handler) = self.handler.take() {
            for seat in self.seats.values() {
                trace!(self.logger, "Calling on_seat_destroyed with {:?}", seat);
                handler.on_seat_destroyed(&seat);
            }
            info!(self.logger, "Removing input handler");
        }
    }

    fn input_config(&mut self) -> &mut Self::InputConfig {
        &mut self.devices
    }

    fn set_cursor_position(&mut self, _x: u32, _y: u32) -> Result<(), ()> {
        // FIXME later.
        // This will be doable with the hardware cursor api and probably some more cases
        warn!(self.logger, "Setting the cursor position is currently unsupported by the libinput backend");
        Err(())
    }

    fn dispatch_new_events(&mut self) -> Result<(), IoError> {
        self.context.dispatch()?;
        for event in &mut self.context {
            match event {
                Event::Device(device_event) => {
                    use input::event::device::*;
                    match device_event {
                        DeviceEvent::Added(device_added_event) => {
                            let added = device_added_event.into_event().device();

                            let new_caps = SeatCapabilities {
                                pointer: added.has_capability(DeviceCapability::Pointer),
                                keyboard: added.has_capability(DeviceCapability::Keyboard),
                                touch: added.has_capability(DeviceCapability::Touch),
                            };

                            let device_seat = added.seat();
                            self.devices.push(added);

                            match self.seats.entry(device_seat) {
                                Entry::Occupied(mut seat_entry) => {
                                    let old_seat = seat_entry.get_mut();
                                    {
                                        let caps = old_seat.capabilities_mut();
                                        caps.pointer = new_caps.pointer || caps.pointer;
                                        caps.keyboard = new_caps.keyboard || caps.keyboard;
                                        caps.touch = new_caps.touch || caps.touch;
                                    }
                                    if let Some(ref mut handler) = self.handler {
                                        trace!(self.logger, "Calling on_seat_changed with {:?}", old_seat);
                                        handler.on_seat_changed(old_seat);
                                    }
                                },
                                Entry::Vacant(seat_entry) => {
                                    let mut hasher = DefaultHasher::default();
                                    seat_entry.key().hash(&mut hasher);
                                    let seat = seat_entry.insert(Seat::new(hasher.finish(), new_caps));
                                    if let Some(ref mut handler) = self.handler {
                                        trace!(self.logger, "Calling on_seat_created with {:?}", seat);
                                        handler.on_seat_created(seat);
                                    }
                                }
                            }
                        },
                        DeviceEvent::Removed(device_removed_event) => {
                            let removed = device_removed_event.into_event().device();

                            // remove device
                            self.devices.retain(|dev| *dev == removed);

                            let device_seat = removed.seat();

                            // update capabilities, so they appear correctly on `on_seat_changed` and `on_seat_destroyed`.
                            if let Some(seat) = self.seats.get_mut(&device_seat) {
                                let caps = seat.capabilities_mut();
                                caps.pointer = self.devices.iter().filter(|x| x.seat() == device_seat).any(|x| x.has_capability(DeviceCapability::Pointer));
                                caps.keyboard = self.devices.iter().filter(|x| x.seat() == device_seat).any(|x| x.has_capability(DeviceCapability::Keyboard));
                                caps.touch = self.devices.iter().filter(|x| x.seat() == device_seat).any(|x| x.has_capability(DeviceCapability::Touch));
                            } else {
                                panic!("Seat changed that was never created")
                            }

                            // check if the seat has any other devices
                            if !self.devices.iter().any(|x| x.seat() == device_seat) {
                                // it has not, lets destroy it
                                if let Some(seat) = self.seats.remove(&device_seat) {
                                    if let Some(ref mut handler) = self.handler {
                                        trace!(self.logger, "Calling on_seat_destroyed with {:?}", seat);
                                        handler.on_seat_destroyed(&seat);
                                    }
                                } else {
                                    panic!("Seat destroyed that was never created");
                                }
                            } else {
                                // it has, notify about updates
                                if let Some(ref mut handler) = self.handler {
                                    let seat = self.seats.get(&device_seat).unwrap();
                                    trace!(self.logger, "Calling on_seat_changed with {:?}", seat);
                                    handler.on_seat_changed(seat);
                                }
                            }
                        },
                    }
                    if let Some(ref mut handler) = self.handler {
                       handler.on_input_config_changed(&mut self.devices);
                    }
                },
                Event::Touch(touch_event) => {},
                Event::Keyboard(keyboard_event) => {},
                Event::Pointer(pointer_event) => {},
                _ => {}, //FIXME: What to do with the rest.
            }
        };
        Ok(())
    }
}
<commit_msg>Impl key events<commit_after>//! Implementation of input backend trait for types provided by `libinput`

use backend::SeatInternal;
use backend::input::{InputBackend, InputHandler, Seat, SeatCapabilities};
use input::{Libinput, Device, Seat as LibinputSeat, DeviceCapability};
use input::event::*;

use std::io::Error as IoError;
use std::collections::hash_map::{DefaultHasher, Entry, HashMap};
use std::hash::{Hash, Hasher};

pub struct LibinputInputBackend {
    context: Libinput,
    devices: Vec<Device>,
    seats: HashMap<LibinputSeat, Seat>,
    handler: Option<Box<InputHandler<LibinputInputBackend> + 'static>>,
    logger: ::slog::Logger,
}

impl InputBackend for LibinputInputBackend {
    type InputConfig = [Device];
    type EventError = IoError;

    fn set_handler<H: InputHandler<Self> + 'static>(&mut self, mut handler: H) {
        if self.handler.is_some() {
            self.clear_handler();
        }
        info!(self.logger, "New input handler set.");
        for seat in self.seats.values() {
            trace!(self.logger, "Calling on_seat_created with {:?}", seat);
            handler.on_seat_created(&seat);
        }
        self.handler = Some(Box::new(handler));
    }

    fn get_handler(&mut self) -> Option<&mut InputHandler<Self>> {
        self.handler
            .as_mut()
            .map(|handler| handler as &mut InputHandler<Self>)
    }

    fn clear_handler(&mut self) {
        if let Some(mut handler) = self.handler.take() {
            for seat in self.seats.values() {
                trace!(self.logger, "Calling on_seat_destroyed with {:?}", seat);
                handler.on_seat_destroyed(&seat);
            }
            info!(self.logger, "Removing input handler");
        }
    }

    fn input_config(&mut self) -> &mut Self::InputConfig {
        &mut self.devices
    }

    fn set_cursor_position(&mut self, _x: u32, _y: u32) -> Result<(), ()> {
        // FIXME later.
        // This will be doable with the hardware cursor api and probably some more cases
        warn!(self.logger, "Setting the cursor position is currently unsupported by the libinput backend");
        Err(())
    }

    fn dispatch_new_events(&mut self) -> Result<(), IoError> {
        self.context.dispatch()?;
        for event in &mut self.context {
            match event {
                Event::Device(device_event) => {
                    use input::event::device::*;
                    match device_event {
                        DeviceEvent::Added(device_added_event) => {
                            let added = device_added_event.into_event().device();

                            let new_caps = SeatCapabilities {
                                pointer: added.has_capability(DeviceCapability::Pointer),
                                keyboard: added.has_capability(DeviceCapability::Keyboard),
                                touch: added.has_capability(DeviceCapability::Touch),
                            };

                            let device_seat = added.seat();
                            self.devices.push(added);

                            match self.seats.entry(device_seat) {
                                Entry::Occupied(mut seat_entry) => {
                                    let old_seat = seat_entry.get_mut();
                                    {
                                        let caps = old_seat.capabilities_mut();
                                        caps.pointer = new_caps.pointer || caps.pointer;
                                        caps.keyboard = new_caps.keyboard || caps.keyboard;
                                        caps.touch = new_caps.touch || caps.touch;
                                    }
                                    if let Some(ref mut handler) = self.handler {
                                        trace!(self.logger, "Calling on_seat_changed with {:?}", old_seat);
                                        handler.on_seat_changed(old_seat);
                                    }
                                },
                                Entry::Vacant(seat_entry) => {
                                    let mut hasher = DefaultHasher::default();
                                    seat_entry.key().hash(&mut hasher);
                                    let seat = seat_entry.insert(Seat::new(hasher.finish(), new_caps));
                                    if let Some(ref mut handler) = self.handler {
                                        trace!(self.logger, "Calling on_seat_created with {:?}", seat);
                                        handler.on_seat_created(seat);
                                    }
                                }
                            }
                        },
                        DeviceEvent::Removed(device_removed_event) => {
                            let removed = device_removed_event.into_event().device();

                            // remove device
                            self.devices.retain(|dev| *dev == removed);

                            let device_seat = removed.seat();

                            // update capabilities, so they appear correctly on `on_seat_changed` and `on_seat_destroyed`.
                            if let Some(seat) = self.seats.get_mut(&device_seat) {
                                let caps = seat.capabilities_mut();
                                caps.pointer = self.devices.iter().filter(|x| x.seat() == device_seat).any(|x| x.has_capability(DeviceCapability::Pointer));
                                caps.keyboard = self.devices.iter().filter(|x| x.seat() == device_seat).any(|x| x.has_capability(DeviceCapability::Keyboard));
                                caps.touch = self.devices.iter().filter(|x| x.seat() == device_seat).any(|x| x.has_capability(DeviceCapability::Touch));
                            } else {
                                panic!("Seat changed that was never created")
                            }

                            // check if the seat has any other devices
                            if !self.devices.iter().any(|x| x.seat() == device_seat) {
                                // it has not, lets destroy it
                                if let Some(seat) = self.seats.remove(&device_seat) {
                                    if let Some(ref mut handler) = self.handler {
                                        trace!(self.logger, "Calling on_seat_destroyed with {:?}", seat);
                                        handler.on_seat_destroyed(&seat);
                                    }
                                } else {
                                    panic!("Seat destroyed that was never created");
                                }
                            } else {
                                // it has, notify about updates
                                if let Some(ref mut handler) = self.handler {
                                    let seat = self.seats.get(&device_seat).unwrap();
                                    trace!(self.logger, "Calling on_seat_changed with {:?}", seat);
                                    handler.on_seat_changed(seat);
                                }
                            }
                        },
                    }
                    if let Some(ref mut handler) = self.handler {
                       handler.on_input_config_changed(&mut self.devices);
                    }
                },
                Event::Touch(touch_event) => {},
                Event::Keyboard(keyboard_event) => {
                    use ::input::event::keyboard::*;
                    match keyboard_event {
                        KeyboardEvent::Key(event) => {
                            if let Some(ref mut handler) = self.handler {
                                let device_seat = event.device().seat();
                                handler.on_keyboard_key(self.seats.get(&device_seat).expect("Recieved key event of non existing Seat"),
                                                        event.time(), event.key(), event.key_state().into(), event.seat_key_count());
                            }
                        }
                    }
                },
                Event::Pointer(pointer_event) => {},
                _ => {}, //FIXME: What to do with the rest.
            }
        };
        Ok(())
    }
}

impl From<::input::event::keyboard::KeyState> for ::backend::input::KeyState {
    fn from(libinput: ::input::event::keyboard::KeyState) -> Self {
        match libinput {
            ::input::event::keyboard::KeyState::Pressed => ::backend::input::KeyState::Pressed,
            ::input::event::keyboard::KeyState::Released => ::backend::input::KeyState::Released,
        }
    }
}
<|endoftext|>


<commit_before>use super::prelude::*;
use std::hash::{Hash, Hasher};
use stencila_schema::{Boolean, Integer, Number};

/// Macro to generate `impl Patchable` for atomic types
macro_rules! patchable_atomic {
    ($type:ty) => {
        impl Patchable for $type {
            patchable_is_same!();

            fn is_equal(&self, other: &Self) -> Result<()> {
                match self == other {
                    true => Ok(()),
                    false => bail!(Error::NotEqual),
                }
            }

            fn make_hash<H: Hasher>(&self, state: &mut H) {
                self.hash(state)
            }

            patchable_diff!();

            fn diff_same(&self, differ: &mut Differ, other: &Self) {
                if self != other {
                    differ.replace(other)
                }
            }

            fn apply_maybe(&mut self, _id: &str, _patch: &Patch) -> Result<bool> {
                Ok(false)
            }

            fn apply_replace(
                &mut self,
                _address: &mut Address,
                _items: usize,
                value: &Value,
            ) -> Result<()> {
                *self = Self::from_value(value)?;
                Ok(())
            }
        }
    };
}

// Implementations for types used in some struct fields
// instead of the Stencila primitives (usually as optimizations)

patchable_atomic!(u8);
patchable_atomic!(i32);
patchable_atomic!(u32);

// Implementations for Stencila primitive types

patchable_atomic!(Boolean);
patchable_atomic!(Integer);

impl Patchable for Number {
    patchable_is_same!();

    fn is_equal(&self, other: &Self) -> Result<()> {
        #[allow(clippy::float_cmp)]
        if self == other {
            Ok(())
        } else {
            bail!(Error::NotEqual)
        }
    }

    fn make_hash<H: Hasher>(&self, state: &mut H) {
        // See caveats to this approach
        // https://stackoverflow.com/a/39647997
        self.to_bits().hash(state)
    }

    patchable_diff!();

    fn diff_same(&self, differ: &mut Differ, other: &Self) {
        #[allow(clippy::float_cmp)]
        if self != other {
            differ.replace(other)
        }
    }

    fn apply_maybe(&mut self, _id: &str, _patch: &Patch) -> Result<bool> {
        Ok(false)
    }

    fn apply_replace(
        &mut self,
        _address: &mut Address,
        _items: usize,
        value: &Value,
    ) -> Result<()> {
        *self = Self::from_value(value)?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        assert_json,
        patches::{apply_new, diff, equal},
    };

    #[test]
    fn booleans() -> Result<()> {
        assert!(equal(&true, &true));
        assert!(equal(&false, &false));
        assert!(!equal(&true, &false));

        assert_json!(diff(&true, &true), []);
        assert_json!(diff(&false, &false), []);
        assert_json!(diff(&true, &false), [{"type": "Replace", "address": [], "items": 1, "value": false, "length": 1}]);

        assert_json!(apply_new(&true, &diff(&true, &false))?, false);
        assert_json!(apply_new(&false, &diff(&false, &true))?, true);

        Ok(())
    }

    #[test]
    fn integers() -> Result<()> {
        assert!(equal(&42, &42));
        assert!(!equal(&42, &1));

        assert_json!(diff(&42, &42), []);
        assert_json!(diff(&42, &1), [{"type": "Replace", "address": [], "items": 1, "value": 1, "length": 1}]);

        assert_json!(apply_new(&1, &diff(&1, &42))?, 42);

        Ok(())
    }

    #[test]
    fn numbers() -> Result<()> {
        assert!(equal(&3.14, &3.14));
        assert!(!equal(&3.14, &1e6));

        assert_json!(diff(&3.14, &3.14), []);
        assert_json!(diff(&3.14, &1e6), [{"type": "Replace", "address": [], "items": 1, "value": 1e6, "length": 1}]);

        assert_json!(apply_new(&1e6, &diff(&1e6, &3.14))?, 3.14);

        Ok(())
    }
}
<commit_msg>refactor(Patches):  Simplify atomics<commit_after>use super::prelude::*;
use std::hash::{Hash, Hasher};
use stencila_schema::{Boolean, Integer, Number};

/// Macro to generate `impl Patchable` for atomic types
macro_rules! patchable_atomic {
    ($type:ty, $hash:ident) => {
        impl Patchable for $type {
            patchable_is_same!();

            fn is_equal(&self, other: &Self) -> Result<()> {
                #[allow(clippy::float_cmp)]
                match self == other {
                    true => Ok(()),
                    false => bail!(Error::NotEqual),
                }
            }

            fn make_hash<H: Hasher>(&self, state: &mut H) {
                $hash(self, state)
            }

            patchable_diff!();

            fn diff_same(&self, differ: &mut Differ, other: &Self) {
                #[allow(clippy::float_cmp)]
                if self != other {
                    differ.replace(other)
                }
            }

            fn apply_maybe(&mut self, _id: &str, _patch: &Patch) -> Result<bool> {
                Ok(false)
            }

            fn apply_replace(
                &mut self,
                _address: &mut Address,
                _items: usize,
                value: &Value,
            ) -> Result<()> {
                *self = Self::from_value(value)?;
                Ok(())
            }
        }
    };
}

/// Hash an atomic
fn hash<T: Hash, H: Hasher>(value: &T, state: &mut H) {
    value.hash(state)
}

/// Hash a float
///
/// See caveats to this approach: https://stackoverflow.com/a/39647997
fn hash_float<H: Hasher>(value: &f64, state: &mut H) {
    value.to_bits().hash(state)
}

// Implementations for types used in some struct fields
// instead of the Stencila primitives (usually as optimizations)

patchable_atomic!(u8, hash);
patchable_atomic!(i32, hash);
patchable_atomic!(u32, hash);

// Implementations for Stencila primitive types

patchable_atomic!(Boolean, hash);
patchable_atomic!(Integer, hash);
patchable_atomic!(Number, hash_float);

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        assert_json,
        patches::{apply_new, diff, equal},
    };

    #[test]
    fn booleans() -> Result<()> {
        assert!(equal(&true, &true));
        assert!(equal(&false, &false));
        assert!(!equal(&true, &false));

        assert_json!(diff(&true, &true), []);
        assert_json!(diff(&false, &false), []);
        assert_json!(diff(&true, &false), [{"type": "Replace", "address": [], "items": 1, "value": false, "length": 1}]);

        assert_json!(apply_new(&true, &diff(&true, &false))?, false);
        assert_json!(apply_new(&false, &diff(&false, &true))?, true);

        Ok(())
    }

    #[test]
    fn integers() -> Result<()> {
        assert!(equal(&42, &42));
        assert!(!equal(&42, &1));

        assert_json!(diff(&42, &42), []);
        assert_json!(diff(&42, &1), [{"type": "Replace", "address": [], "items": 1, "value": 1, "length": 1}]);

        assert_json!(apply_new(&1, &diff(&1, &42))?, 42);

        Ok(())
    }

    #[test]
    fn numbers() -> Result<()> {
        assert!(equal(&3.14, &3.14));
        assert!(!equal(&3.14, &1e6));

        assert_json!(diff(&3.14, &3.14), []);
        assert_json!(diff(&3.14, &1e6), [{"type": "Replace", "address": [], "items": 1, "value": 1e6, "length": 1}]);

        assert_json!(apply_new(&1e6, &diff(&1e6, &3.14))?, 3.14);

        Ok(())
    }
}
<|endoftext|>


<commit_before>use client::Context;
use model::{Message, Permissions};
use std::collections::HashMap;
use std::fmt;
use std::fmt::{Debug, Formatter};
use std::sync::Arc;
use utils::Colour;
use super::{Args, Configuration, HelpBehaviour};

pub type Check = Fn(&mut Context, &Message, &mut Args, &CommandOptions) -> bool
                     + Send
                     + Sync
                     + 'static;

pub type HelpFunction = fn(&mut Context, &Message, &HelpOptions, HashMap<String, Arc<CommandGroup>>, Args)
                   -> Result<(), Error>;

pub struct Help(pub HelpFunction, pub Arc<HelpOptions>);

impl Debug for Help {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "fn()")
    }
}

impl HelpCommand for Help {
    fn execute(&self, c: &mut Context, m: &Message, ho: &HelpOptions,hm: HashMap<String, Arc<CommandGroup>>, a: Args) -> Result<(), Error> {
        (self.0)(c, m, ho, hm, a)
    }
}

pub type BeforeHook = Fn(&mut Context, &Message, &str) -> bool + Send + Sync + 'static;
pub type AfterHook = Fn(&mut Context, &Message, &str, Result<(), Error>) + Send + Sync + 'static;
pub(crate) type InternalCommand = Arc<Command>;
pub type PrefixCheck = Fn(&mut Context, &Message) -> Option<String> + Send + Sync + 'static;

pub enum CommandOrAlias {
    Alias(String),
    Command(InternalCommand),
}

impl fmt::Debug for CommandOrAlias {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CommandOrAlias::Alias(ref s) => f.debug_tuple("CommandOrAlias::Alias").field(&s).finish(),
            _ => Ok(())
        }
    }
}

/// An error from a command.
#[derive(Clone, Debug)]
pub struct Error(pub String);

// TODO: Have seperate `From<(&)String>` and `From<&str>` impls via specialization
impl<D: fmt::Display> From<D> for Error {
    fn from(d: D) -> Self {
        Error(d.to_string())
    }
}

#[derive(Debug)]
pub struct CommandGroup {
    pub prefix: Option<String>,
    pub commands: HashMap<String, CommandOrAlias>,
    /// Some fields taken from Command
    pub bucket: Option<String>,
    pub required_permissions: Permissions,
    pub allowed_roles: Vec<String>,
    pub help_available: bool,
    pub dm_only: bool,
    pub guild_only: bool,
    pub owners_only: bool,
    pub help: Option<Arc<Help>>,
}

impl Default for CommandGroup {
    fn default() -> CommandGroup {
        CommandGroup {
            prefix: None,
            commands: HashMap::new(),
            bucket: None,
            required_permissions: Permissions::empty(),
            dm_only: false,
            guild_only: false,
            help_available: true,
            owners_only: false,
            allowed_roles: Vec::new(),
            help: None,
        }
    }
}

pub struct CommandOptions {
    /// A set of checks to be called prior to executing the command. The checks
    /// will short-circuit on the first check that returns `false`.
    pub checks: Vec<Box<Check>>,
    /// Ratelimit bucket.
    pub bucket: Option<String>,
    /// Command description, used by other commands.
    pub desc: Option<String>,
    /// Example arguments, used by other commands.
    pub example: Option<String>,
    /// Command usage schema, used by other commands.
    pub usage: Option<String>,
    /// Minumum amount of arguments that should be passed.
    pub min_args: Option<i32>,
    /// Maximum amount of arguments that can be passed.
    pub max_args: Option<i32>,
    /// Permissions required to use this command.
    pub required_permissions: Permissions,
    /// Roles allowed to use this command.
    pub allowed_roles: Vec<String>,
    /// Whether command should be displayed in help list or not, used by other commands.
    pub help_available: bool,
    /// Whether command can be used only privately or not.
    pub dm_only: bool,
    /// Whether command can be used only in guilds or not.
    pub guild_only: bool,
    /// Whether command can only be used by owners or not.
    pub owners_only: bool,
    /// Other names that can be used to call this command instead.
    pub aliases: Vec<String>,
}

#[derive(Debug)]
pub struct HelpOptions {
    /// Suggests a command's name.
    pub suggestion_text: String,
    /// If no help is available, this text will be displayed.
    pub no_help_available_text: String,
    /// How to use a command, `{usage_label}: {command_name} {args}`
    pub usage_label: String,
    /// Actual sample label, `{usage_sample_label}: {command_name} {args}`
    pub usage_sample_label: String,
    /// Text labeling ungrouped commands, `{ungrouped_label}: ...`
    pub ungrouped_label: String,
    /// Text labeling the start of the description.
    pub description_label: String,
    /// Text labeling grouped commands, `{grouped_label} {group_name}: ...`
    pub grouped_label: String,
    /// Text labeling a command's alternative names (aliases).
    pub aliases_label: String,
    /// Text specifying that a command is only usable in a guild.
    pub guild_only_text: String,
    /// Text specifying that a command is only usable in via DM.
    pub dm_only_text: String,
    /// Text specifying that a command can be used via DM and in guilds.
    pub dm_and_guild_text: String,
    /// Text expressing that a command is available.
    pub available_text: String,
    /// Error-message once a command could not be found.
    /// Output-example (without whitespace between both substitutions: `{command_not_found_text}{command_name}`
    /// `{command_name}` describes user's input as in: `{prefix}help {command_name}`.
    pub command_not_found_text: String,
    /// Explains the user on how to use access a single command's details.
    pub individual_command_tip: String,
    /// Explains reasoning behind striked commands, see fields requiring `HelpBehaviour` for further information.
    /// If `HelpBehaviour::Strike` is unused, this field will evaluate to `None` during creation
    /// inside of `CreateHelpCommand`.
    pub striked_commands_tip: Option<String>,
    /// Announcing a group's prefix as in: {group_prefix} {prefix}.
    pub group_prefix: String,
    /// If a user lacks required roles, this will treat how these commands will be displayed.
    pub lacking_role: HelpBehaviour,
    /// If a user lacks permissions, this will treat how these commands will be displayed.
    pub lacking_permissions: HelpBehaviour,
    /// If a user is using the help-command in a channel where a command is not available,
    /// this behaviour will be executed.
    pub wrong_channel: HelpBehaviour,
    /// Colour help-embed will use upon encountering an error.
    pub embed_error_colour: Colour,
    /// Colour help-embed will use if no error occured.
    pub embed_success_colour: Colour,
}

pub trait HelpCommand: Send + Sync + 'static {
    fn execute(&self, &mut Context, &Message, &HelpOptions, HashMap<String, Arc<CommandGroup>>, Args) -> Result<(), Error>;

    fn options(&self) -> Arc<CommandOptions> {
        Arc::clone(&DEFAULT_OPTIONS)
    }
}

impl HelpCommand for Arc<HelpCommand> {
    fn execute(&self, c: &mut Context, m: &Message, ho: &HelpOptions, hm: HashMap<String, Arc<CommandGroup>>, a: Args) -> Result<(), Error> {
        (**self).execute(c, m, ho, hm, a)
    }
}

impl Default for HelpOptions {
    fn default() -> HelpOptions {
        HelpOptions {
            suggestion_text: "Did you mean {}?".to_string(),
            no_help_available_text: "**Error**: No help available.".to_string(),
            usage_label: "Usage".to_string(),
            usage_sample_label: "Sample usage".to_string(),
            ungrouped_label: "Ungrouped".to_string(),
            grouped_label: "Group".to_string(),
            aliases_label: "Aliases".to_string(),
            description_label: "Description".to_string(),
            guild_only_text: "Only in guilds".to_string(),
            dm_only_text: "Only in DM".to_string(),
            dm_and_guild_text: "In DM and guilds".to_string(),
            available_text: "Available".to_string(),
            command_not_found_text: "**Error**: Command `{}` not found.".to_string(),
            individual_command_tip: "To get help with an individual command, pass its \
                 name as an argument to this command.".to_string(),
            group_prefix: "Prefix".to_string(),
            striked_commands_tip: Some(String::new()),
            lacking_role: HelpBehaviour::Strike,
            lacking_permissions: HelpBehaviour::Strike,
            wrong_channel: HelpBehaviour::Strike,
            embed_error_colour: Colour::dark_red(),
            embed_success_colour: Colour::rosewater(),
        }
    }
}

lazy_static! {
    static ref DEFAULT_OPTIONS: Arc<CommandOptions> = Arc::new(CommandOptions::default());
}

/// A framework command.
pub trait Command: Send + Sync + 'static {
    fn execute(&self, &mut Context, &Message, Args) -> Result<(), Error>;

    fn options(&self) -> Arc<CommandOptions> {
        Arc::clone(&DEFAULT_OPTIONS)
    }

    /// Called when the command gets registered.
    fn init(&self) {}

    /// "before" middleware. Is called alongside the global middleware in the framework.
    fn before(&self, &mut Context, &Message) -> bool { true }

    /// "after" middleware. Is called alongside the global middleware in the framework.
    fn after(&self, &mut Context, &Message, &Result<(), Error>) { }
}

impl Command for Arc<Command> {
    fn execute(&self, c: &mut Context, m: &Message, a: Args) -> Result<(), Error> {
        (**self).execute(c, m, a)
    }

    fn options(&self) -> Arc<CommandOptions> {
        (**self).options()
    }

    fn init(&self) {
        (**self).init()
    }

    fn before(&self, c: &mut Context, m: &Message) -> bool {
        (**self).before(c, m)
    }

    fn after(&self, c: &mut Context, m: &Message, res: &Result<(), Error>) {
        (**self).after(c, m, res)
    }
}

impl Command for Box<Command> {
    fn execute(&self, c: &mut Context, m: &Message, a: Args) -> Result<(), Error> {
        (**self).execute(c, m, a)
    }

    fn options(&self) -> Arc<CommandOptions> {
        (**self).options()
    }

    fn init(&self) {
        (**self).init()
    }

    fn before(&self, c: &mut Context, m: &Message) -> bool {
        (**self).before(c, m)
    }

    fn after(&self, c: &mut Context, m: &Message, res: &Result<(), Error>) {
        (**self).after(c, m, res)
    }
}

impl<F> Command for F where F: Fn(&mut Context, &Message, Args) -> Result<(), Error>
    + Send
    + Sync
    + ?Sized
    + 'static {
    fn execute(&self, c: &mut Context, m: &Message, a: Args) -> Result<(), Error> {
        (*self)(c, m, a)
    }
}

impl fmt::Debug for CommandOptions {
    // TODO: add CommandOptions::checks somehow?
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("CommandOptions")
            .field("bucket", &self.bucket)
            .field("desc", &self.desc)
            .field("example", &self.example)
            .field("usage", &self.usage)
            .field("min_args", &self.min_args)
            .field("required_permissions", &self.required_permissions)
            .field("allowed_roles", &self.allowed_roles)
            .field("help_available", &self.help_available)
            .field("dm_only", &self.dm_only)
            .field("guild_only", &self.guild_only)
            .field("owners_only", &self.owners_only)
            .finish()
    }
}

impl Default for CommandOptions {
    fn default() -> CommandOptions {
        CommandOptions {
            aliases: Vec::new(),
            checks: Vec::default(),
            desc: None,
            usage: None,
            example: None,
            min_args: None,
            bucket: None,
            max_args: None,
            required_permissions: Permissions::empty(),
            dm_only: false,
            guild_only: false,
            help_available: true,
            owners_only: false,
            allowed_roles: Vec::new(),
        }
    }
}

pub fn positions(ctx: &mut Context, msg: &Message, conf: &Configuration) -> Option<Vec<usize>> {
    if !conf.prefixes.is_empty() || conf.dynamic_prefix.is_some() {
        // Find out if they were mentioned. If not, determine if the prefix
        // was used. If not, return None.
        let mut positions: Vec<usize> = vec![];

        if let Some(mention_end) = find_mention_end(&msg.content, conf) {
            positions.push(mention_end);
            return Some(positions);
        } else if let Some(ref func) = conf.dynamic_prefix {
            if let Some(x) = func(ctx, msg) {
                if msg.content.starts_with(&x) {
                    positions.push(x.len());
                }
            } else {
                for n in &conf.prefixes {
                    if msg.content.starts_with(n) {
                        positions.push(n.len());
                    }
                }
            }
        } else {
            for n in &conf.prefixes {
                if msg.content.starts_with(n) {
                    positions.push(n.len());
                }
            }
        };

        if positions.is_empty() {
            return None;
        }

        let pos = *unsafe { positions.get_unchecked(0) };

        if conf.allow_whitespace {
            positions.insert(0, find_end_of_prefix_with_whitespace(&msg.content, pos).unwrap_or(pos));
        } else if find_end_of_prefix_with_whitespace(&msg.content, pos).is_some() {
            return None;
        }

        Some(positions)
    } else if conf.on_mention.is_some() {
        find_mention_end(&msg.content, conf).map(|mention_end| {
            vec![mention_end] // This can simply be returned without trying to find the end whitespaces as trim will remove it later
        })
    } else {
        None
    }
}

fn find_mention_end(content: &str, conf: &Configuration) -> Option<usize> {
    conf.on_mention.as_ref().and_then(|mentions| {
        mentions
            .iter()
            .find(|mention| content.starts_with(&mention[..]))
            .map(|m| m.len())
    })
}

// Finds the end of the first continuous block of whitespace after the prefix
fn find_end_of_prefix_with_whitespace(content: &str, position: usize) -> Option<usize> {
    let content_len = content.len();
    if position >= content_len { return None; }

    let slice = unsafe { content.slice_unchecked(position, content_len) }.as_bytes();
    for i in 0..slice.len() {
        match slice[i] {
            // \t \n \r [space]
            0x09 | 0x0a | 0x0d | 0x20 => {}
            _ => return if i == 0 { None } else { Some(position + i) }
        }
    }
    Some(content.len())
}
<commit_msg>Remove the `Box<Command>` impl<commit_after>use client::Context;
use model::{Message, Permissions};
use std::collections::HashMap;
use std::fmt;
use std::fmt::{Debug, Formatter};
use std::sync::Arc;
use utils::Colour;
use super::{Args, Configuration, HelpBehaviour};

pub type Check = Fn(&mut Context, &Message, &mut Args, &CommandOptions) -> bool
                     + Send
                     + Sync
                     + 'static;

pub type HelpFunction = fn(&mut Context, &Message, &HelpOptions, HashMap<String, Arc<CommandGroup>>, Args)
                   -> Result<(), Error>;

pub struct Help(pub HelpFunction, pub Arc<HelpOptions>);

impl Debug for Help {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "fn()")
    }
}

impl HelpCommand for Help {
    fn execute(&self, c: &mut Context, m: &Message, ho: &HelpOptions,hm: HashMap<String, Arc<CommandGroup>>, a: Args) -> Result<(), Error> {
        (self.0)(c, m, ho, hm, a)
    }
}

pub type BeforeHook = Fn(&mut Context, &Message, &str) -> bool + Send + Sync + 'static;
pub type AfterHook = Fn(&mut Context, &Message, &str, Result<(), Error>) + Send + Sync + 'static;
pub(crate) type InternalCommand = Arc<Command>;
pub type PrefixCheck = Fn(&mut Context, &Message) -> Option<String> + Send + Sync + 'static;

pub enum CommandOrAlias {
    Alias(String),
    Command(InternalCommand),
}

impl fmt::Debug for CommandOrAlias {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CommandOrAlias::Alias(ref s) => f.debug_tuple("CommandOrAlias::Alias").field(&s).finish(),
            _ => Ok(())
        }
    }
}

/// An error from a command.
#[derive(Clone, Debug)]
pub struct Error(pub String);

// TODO: Have seperate `From<(&)String>` and `From<&str>` impls via specialization
impl<D: fmt::Display> From<D> for Error {
    fn from(d: D) -> Self {
        Error(d.to_string())
    }
}

#[derive(Debug)]
pub struct CommandGroup {
    pub prefix: Option<String>,
    pub commands: HashMap<String, CommandOrAlias>,
    /// Some fields taken from Command
    pub bucket: Option<String>,
    pub required_permissions: Permissions,
    pub allowed_roles: Vec<String>,
    pub help_available: bool,
    pub dm_only: bool,
    pub guild_only: bool,
    pub owners_only: bool,
    pub help: Option<Arc<Help>>,
}

impl Default for CommandGroup {
    fn default() -> CommandGroup {
        CommandGroup {
            prefix: None,
            commands: HashMap::new(),
            bucket: None,
            required_permissions: Permissions::empty(),
            dm_only: false,
            guild_only: false,
            help_available: true,
            owners_only: false,
            allowed_roles: Vec::new(),
            help: None,
        }
    }
}

pub struct CommandOptions {
    /// A set of checks to be called prior to executing the command. The checks
    /// will short-circuit on the first check that returns `false`.
    pub checks: Vec<Box<Check>>,
    /// Ratelimit bucket.
    pub bucket: Option<String>,
    /// Command description, used by other commands.
    pub desc: Option<String>,
    /// Example arguments, used by other commands.
    pub example: Option<String>,
    /// Command usage schema, used by other commands.
    pub usage: Option<String>,
    /// Minumum amount of arguments that should be passed.
    pub min_args: Option<i32>,
    /// Maximum amount of arguments that can be passed.
    pub max_args: Option<i32>,
    /// Permissions required to use this command.
    pub required_permissions: Permissions,
    /// Roles allowed to use this command.
    pub allowed_roles: Vec<String>,
    /// Whether command should be displayed in help list or not, used by other commands.
    pub help_available: bool,
    /// Whether command can be used only privately or not.
    pub dm_only: bool,
    /// Whether command can be used only in guilds or not.
    pub guild_only: bool,
    /// Whether command can only be used by owners or not.
    pub owners_only: bool,
    /// Other names that can be used to call this command instead.
    pub aliases: Vec<String>,
}

#[derive(Debug)]
pub struct HelpOptions {
    /// Suggests a command's name.
    pub suggestion_text: String,
    /// If no help is available, this text will be displayed.
    pub no_help_available_text: String,
    /// How to use a command, `{usage_label}: {command_name} {args}`
    pub usage_label: String,
    /// Actual sample label, `{usage_sample_label}: {command_name} {args}`
    pub usage_sample_label: String,
    /// Text labeling ungrouped commands, `{ungrouped_label}: ...`
    pub ungrouped_label: String,
    /// Text labeling the start of the description.
    pub description_label: String,
    /// Text labeling grouped commands, `{grouped_label} {group_name}: ...`
    pub grouped_label: String,
    /// Text labeling a command's alternative names (aliases).
    pub aliases_label: String,
    /// Text specifying that a command is only usable in a guild.
    pub guild_only_text: String,
    /// Text specifying that a command is only usable in via DM.
    pub dm_only_text: String,
    /// Text specifying that a command can be used via DM and in guilds.
    pub dm_and_guild_text: String,
    /// Text expressing that a command is available.
    pub available_text: String,
    /// Error-message once a command could not be found.
    /// Output-example (without whitespace between both substitutions: `{command_not_found_text}{command_name}`
    /// `{command_name}` describes user's input as in: `{prefix}help {command_name}`.
    pub command_not_found_text: String,
    /// Explains the user on how to use access a single command's details.
    pub individual_command_tip: String,
    /// Explains reasoning behind striked commands, see fields requiring `HelpBehaviour` for further information.
    /// If `HelpBehaviour::Strike` is unused, this field will evaluate to `None` during creation
    /// inside of `CreateHelpCommand`.
    pub striked_commands_tip: Option<String>,
    /// Announcing a group's prefix as in: {group_prefix} {prefix}.
    pub group_prefix: String,
    /// If a user lacks required roles, this will treat how these commands will be displayed.
    pub lacking_role: HelpBehaviour,
    /// If a user lacks permissions, this will treat how these commands will be displayed.
    pub lacking_permissions: HelpBehaviour,
    /// If a user is using the help-command in a channel where a command is not available,
    /// this behaviour will be executed.
    pub wrong_channel: HelpBehaviour,
    /// Colour help-embed will use upon encountering an error.
    pub embed_error_colour: Colour,
    /// Colour help-embed will use if no error occured.
    pub embed_success_colour: Colour,
}

pub trait HelpCommand: Send + Sync + 'static {
    fn execute(&self, &mut Context, &Message, &HelpOptions, HashMap<String, Arc<CommandGroup>>, Args) -> Result<(), Error>;

    fn options(&self) -> Arc<CommandOptions> {
        Arc::clone(&DEFAULT_OPTIONS)
    }
}

impl HelpCommand for Arc<HelpCommand> {
    fn execute(&self, c: &mut Context, m: &Message, ho: &HelpOptions, hm: HashMap<String, Arc<CommandGroup>>, a: Args) -> Result<(), Error> {
        (**self).execute(c, m, ho, hm, a)
    }
}

impl Default for HelpOptions {
    fn default() -> HelpOptions {
        HelpOptions {
            suggestion_text: "Did you mean {}?".to_string(),
            no_help_available_text: "**Error**: No help available.".to_string(),
            usage_label: "Usage".to_string(),
            usage_sample_label: "Sample usage".to_string(),
            ungrouped_label: "Ungrouped".to_string(),
            grouped_label: "Group".to_string(),
            aliases_label: "Aliases".to_string(),
            description_label: "Description".to_string(),
            guild_only_text: "Only in guilds".to_string(),
            dm_only_text: "Only in DM".to_string(),
            dm_and_guild_text: "In DM and guilds".to_string(),
            available_text: "Available".to_string(),
            command_not_found_text: "**Error**: Command `{}` not found.".to_string(),
            individual_command_tip: "To get help with an individual command, pass its \
                 name as an argument to this command.".to_string(),
            group_prefix: "Prefix".to_string(),
            striked_commands_tip: Some(String::new()),
            lacking_role: HelpBehaviour::Strike,
            lacking_permissions: HelpBehaviour::Strike,
            wrong_channel: HelpBehaviour::Strike,
            embed_error_colour: Colour::dark_red(),
            embed_success_colour: Colour::rosewater(),
        }
    }
}

lazy_static! {
    static ref DEFAULT_OPTIONS: Arc<CommandOptions> = Arc::new(CommandOptions::default());
}

/// A framework command.
pub trait Command: Send + Sync + 'static {
    fn execute(&self, &mut Context, &Message, Args) -> Result<(), Error>;

    fn options(&self) -> Arc<CommandOptions> {
        Arc::clone(&DEFAULT_OPTIONS)
    }

    /// Called when the command gets registered.
    fn init(&self) {}

    /// "before" middleware. Is called alongside the global middleware in the framework.
    fn before(&self, &mut Context, &Message) -> bool { true }

    /// "after" middleware. Is called alongside the global middleware in the framework.
    fn after(&self, &mut Context, &Message, &Result<(), Error>) { }
}

impl Command for Arc<Command> {
    fn execute(&self, c: &mut Context, m: &Message, a: Args) -> Result<(), Error> {
        (**self).execute(c, m, a)
    }

    fn options(&self) -> Arc<CommandOptions> {
        (**self).options()
    }

    fn init(&self) {
        (**self).init()
    }

    fn before(&self, c: &mut Context, m: &Message) -> bool {
        (**self).before(c, m)
    }

    fn after(&self, c: &mut Context, m: &Message, res: &Result<(), Error>) {
        (**self).after(c, m, res)
    }
}

impl<F> Command for F where F: Fn(&mut Context, &Message, Args) -> Result<(), Error>
    + Send
    + Sync
    + ?Sized
    + 'static {
    fn execute(&self, c: &mut Context, m: &Message, a: Args) -> Result<(), Error> {
        (*self)(c, m, a)
    }
}

impl fmt::Debug for CommandOptions {
    // TODO: add CommandOptions::checks somehow?
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("CommandOptions")
            .field("bucket", &self.bucket)
            .field("desc", &self.desc)
            .field("example", &self.example)
            .field("usage", &self.usage)
            .field("min_args", &self.min_args)
            .field("required_permissions", &self.required_permissions)
            .field("allowed_roles", &self.allowed_roles)
            .field("help_available", &self.help_available)
            .field("dm_only", &self.dm_only)
            .field("guild_only", &self.guild_only)
            .field("owners_only", &self.owners_only)
            .finish()
    }
}

impl Default for CommandOptions {
    fn default() -> CommandOptions {
        CommandOptions {
            aliases: Vec::new(),
            checks: Vec::default(),
            desc: None,
            usage: None,
            example: None,
            min_args: None,
            bucket: None,
            max_args: None,
            required_permissions: Permissions::empty(),
            dm_only: false,
            guild_only: false,
            help_available: true,
            owners_only: false,
            allowed_roles: Vec::new(),
        }
    }
}

pub fn positions(ctx: &mut Context, msg: &Message, conf: &Configuration) -> Option<Vec<usize>> {
    if !conf.prefixes.is_empty() || conf.dynamic_prefix.is_some() {
        // Find out if they were mentioned. If not, determine if the prefix
        // was used. If not, return None.
        let mut positions: Vec<usize> = vec![];

        if let Some(mention_end) = find_mention_end(&msg.content, conf) {
            positions.push(mention_end);
            return Some(positions);
        } else if let Some(ref func) = conf.dynamic_prefix {
            if let Some(x) = func(ctx, msg) {
                if msg.content.starts_with(&x) {
                    positions.push(x.len());
                }
            } else {
                for n in &conf.prefixes {
                    if msg.content.starts_with(n) {
                        positions.push(n.len());
                    }
                }
            }
        } else {
            for n in &conf.prefixes {
                if msg.content.starts_with(n) {
                    positions.push(n.len());
                }
            }
        };

        if positions.is_empty() {
            return None;
        }

        let pos = *unsafe { positions.get_unchecked(0) };

        if conf.allow_whitespace {
            positions.insert(0, find_end_of_prefix_with_whitespace(&msg.content, pos).unwrap_or(pos));
        } else if find_end_of_prefix_with_whitespace(&msg.content, pos).is_some() {
            return None;
        }

        Some(positions)
    } else if conf.on_mention.is_some() {
        find_mention_end(&msg.content, conf).map(|mention_end| {
            vec![mention_end] // This can simply be returned without trying to find the end whitespaces as trim will remove it later
        })
    } else {
        None
    }
}

fn find_mention_end(content: &str, conf: &Configuration) -> Option<usize> {
    conf.on_mention.as_ref().and_then(|mentions| {
        mentions
            .iter()
            .find(|mention| content.starts_with(&mention[..]))
            .map(|m| m.len())
    })
}

// Finds the end of the first continuous block of whitespace after the prefix
fn find_end_of_prefix_with_whitespace(content: &str, position: usize) -> Option<usize> {
    let content_len = content.len();
    if position >= content_len { return None; }

    let slice = unsafe { content.slice_unchecked(position, content_len) }.as_bytes();
    for i in 0..slice.len() {
        match slice[i] {
            // \t \n \r [space]
            0x09 | 0x0a | 0x0d | 0x20 => {}
            _ => return if i == 0 { None } else { Some(position + i) }
        }
    }
    Some(content.len())
}
<|endoftext|>


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

#[derive(Debug,Hash,PartialEq,PartialOrd,Eq,Ord,Clone)]
struct Name {
    name: String,
}

impl Name {
    fn label(&self) -> &str {
        if let Some(index) = self.name.find('.') {
            let (label, _) = self.name.split_at(index);
            label
        } else {
            self.name.as_ref()
        }
    }

    fn parent(&self) -> Option<Name> {
        if let Some(index) = self.name.find('.') {
            let (_, p) = self.name.split_at(index + 1);
            return Some(Name { name: String::from(p) });
        }
        if self.name.len() > 0 {
            return Some( Name { name: String::from("") });
        }
        None
    }
}

#[derive(Debug,PartialEq)]
enum NameError {
    NameTooLong(usize),
    LabelTooLong(usize)
}

impl FromStr for Name {
    type Err = NameError;
    fn from_str(s: &str) -> Result<Name, NameError> {
        let name = String::from(s);
        if name.len() > 255 {
            return Err(NameError::NameTooLong(name.len()));
        }
        let result = Name { name: name };
        let label_len = result.label().len();
        if label_len > 63 {
            return Err(NameError::LabelTooLong(label_len));
        }
        Ok(result)
    }
}

#[cfg(test)]
mod tests {
    use super::{Name, NameError};

    #[test]
    fn root_label_is_valid() {
        let name = "".parse::<Name>().unwrap();
        assert_eq!("", name.label());
    }

    #[test]
    fn root_parent_is_none() {
        let name = "".parse::<Name>().unwrap();
        assert_eq!(None, name.parent());
    }

    #[test]
    fn simple_label_is_valid() {
        let name = "raspberry".parse::<Name>().unwrap();
        assert_eq!("raspberry", name.label());
    }

    #[test]
    fn simple_parent_is_root() {
        let name = "raspberry".parse::<Name>().unwrap();
        let parent = name.parent().unwrap();
        assert_eq!("", parent.label());
    }

    #[test]
    fn multi_label_is_valid() {
        let name = "test.example.com".parse::<Name>().unwrap();
        assert_eq!("test", name.label());
    }

    #[test]
    fn multi_parent_is_valid() {
        let name = "test.example.com".parse::<Name>().unwrap();
        let parent1 = name.parent().unwrap();
        assert_eq!("example", parent1.label());
        let parent2 = parent1.parent().unwrap();
        assert_eq!("com", parent2.label());
        let parent3 = parent2.parent().unwrap();
        assert_eq!("", parent3.label());
    }

    #[test]
    fn long_name_is_invalid() {
        let raw_name = String::from_utf8(vec!['A' as u8; 256]).unwrap();
        let result = raw_name.parse::<Name>();
        assert_eq!(result.err(), Some(NameError::NameTooLong(256)));
    }

    #[test]
    fn long_first_label_is_invalid() {
        let raw_name = String::from_utf8(vec!['A' as u8; 150]).unwrap();
        let result = raw_name.parse::<Name>();
        assert_eq!(result.err(), Some(NameError::LabelTooLong(150)));
    }
}
<commit_msg>Try out new name parse logic structures<commit_after>use std::str::FromStr;

#[derive(Debug,Hash,PartialEq,PartialOrd,Eq,Ord,Clone)]
pub struct Name {
    name: String,
}

fn first_label(name: &str) -> &str {
    match name.find(".") {
        Some(index) => &name[..index],
        None => name,
    }
}

impl Name {
    fn label(&self) -> &str {
        first_label(&self.name)
    }

    fn parent(&self) -> Option<Name> {
        match self.name.find(".") {
            Some(index) => Some(Name { name: String::from(&self.name[(index + 1)..]) }),
            None => {
                match self.name.len() {
                    0 => None,
                    _ => Some(Name { name: String::from("") }),
                }
            }
        }
    }
}

#[derive(Debug,PartialEq)]
pub enum NameError {
    NameTooLong(usize, String),
    LabelTooLong(usize, String),
    EmptyNonRootLabel,
}

impl FromStr for Name {
    type Err = NameError;
    fn from_str(s: &str) -> Result<Name, NameError> {
        let name = String::from(s);
        if name.len() > 255 {
            return Err(NameError::NameTooLong(name.len(), name));
        }

        if name.len() > 0 {
            let mut name_part = s;
            loop {
                let label = first_label(&name_part);
                if label.len() > 63 {
                    return Err(NameError::LabelTooLong(label.len(), String::from(label)));
                }
                if label.len() == 0 {
                    return Err(NameError::EmptyNonRootLabel);
                }
                if label.len() == name_part.len() {
                    // Non-empty last element
                    break;
                }
                name_part = &name_part[(label.len() + 1)..];
            }
        }
        Ok(Name { name: name })
    }
}

#[cfg(test)]
mod tests {
    use super::{Name, NameError};

    #[test]
    fn root_label_is_valid() {
        let name = "".parse::<Name>().unwrap();
        assert_eq!("", name.label());
    }

    #[test]
    fn root_parent_is_none() {
        let name = "".parse::<Name>().unwrap();
        assert_eq!(None, name.parent());
    }

    #[test]
    fn simple_label_is_valid() {
        let name = "raspberry".parse::<Name>().unwrap();
        assert_eq!("raspberry", name.label());
    }

    #[test]
    fn simple_parent_is_root() {
        let name = "raspberry".parse::<Name>().unwrap();
        let parent = name.parent().unwrap();
        assert_eq!("", parent.label());
    }

    #[test]
    fn multi_label_is_valid() {
        let name = "test.example.com".parse::<Name>().unwrap();
        assert_eq!("test", name.label());
    }

    #[test]
    fn multi_parent_is_valid() {
        let name = "test.example.com".parse::<Name>().unwrap();
        let parent1 = name.parent().unwrap();
        assert_eq!("example", parent1.label());
        let parent2 = parent1.parent().unwrap();
        assert_eq!("com", parent2.label());
        let parent3 = parent2.parent().unwrap();
        assert_eq!("", parent3.label());
    }

    #[test]
    fn long_name_is_invalid() {
        let raw_name = String::from_utf8(vec!['A' as u8; 256]).unwrap();
        let result = raw_name.parse::<Name>();
        assert_eq!(result.err(), Some(NameError::NameTooLong(256, raw_name)));
    }

    #[test]
    fn long_first_label_is_invalid() {
        let raw_name = String::from_utf8(vec!['A' as u8; 150]).unwrap();
        let result = raw_name.parse::<Name>();
        assert_eq!(result.err(), Some(NameError::LabelTooLong(150, raw_name)));
    }
}
<|endoftext|>