<commit_before>use ammonia::Ammonia;
use comrak;

use util::CargoResult;

/// Context for markdown to HTML rendering.
#[allow(missing_debug_implementations)]
pub struct MarkdownRenderer<'a> {
    html_sanitizer: Ammonia<'a>,
}

impl<'a> MarkdownRenderer<'a> {
    /// Creates a new renderer instance.
    pub fn new() -> MarkdownRenderer<'a> {
        let tags = [
            "a",
            "b",
            "blockquote",
            "br",
            "code",
            "dd",
            "del",
            "dl",
            "dt",
            "em",
            "h1",
            "h2",
            "h3",
            "hr",
            "i",
            "img",
            "input",
            "kbd",
            "li",
            "ol",
            "p",
            "pre",
            "s",
            "strike",
            "strong",
            "sub",
            "sup",
            "table",
            "tbody",
            "td",
            "th",
            "thead",
            "tr",
            "ul",
            "hr",
            "span",
        ].iter()
            .cloned()
            .collect();
        let tag_attributes = [
            ("a", ["href", "target"].iter().cloned().collect()),
            ("code", ["class"].iter().cloned().collect()),
            (
                "img",
                ["width", "height", "src", "alt", "align"]
                    .iter()
                    .cloned()
                    .collect(),
            ),
            (
                "input",
                ["checked", "disabled", "type"].iter().cloned().collect(),
            ),
        ].iter()
            .cloned()
            .collect();
        let allowed_classes = [
            (
                "code",
                [
                    "language-bash",
                    "language-clike",
                    "language-glsl",
                    "language-go",
                    "language-ini",
                    "language-javascript",
                    "language-json",
                    "language-markup",
                    "language-protobuf",
                    "language-ruby",
                    "language-rust",
                    "language-scss",
                    "language-sql",
                    "yaml",
                ].iter()
                    .cloned()
                    .collect(),
            ),
        ].iter()
            .cloned()
            .collect();
        let html_sanitizer = Ammonia {
            link_rel: Some("nofollow noopener noreferrer"),
            keep_cleaned_elements: true,
            tags: tags,
            tag_attributes: tag_attributes,
            allowed_classes: allowed_classes,
            ..Ammonia::default()
        };
        MarkdownRenderer {
            html_sanitizer: html_sanitizer,
        }
    }

    /// Renders the given markdown to HTML using the current settings.
    pub fn to_html(&self, text: &str) -> CargoResult<String> {
        let options = comrak::ComrakOptions {
            ext_autolink: true,
            ext_strikethrough: true,
            ext_table: true,
            ext_tagfilter: true,
            ext_tasklist: true,
            ..comrak::ComrakOptions::default()
        };
        let rendered = comrak::markdown_to_html(text, &options);
        Ok(self.html_sanitizer.clean(&rendered))
    }
}

impl<'a> Default for MarkdownRenderer<'a> {
    fn default() -> Self {
        Self::new()
    }
}

/// Renders a markdown text to sanitized HTML.
///
/// The returned text should not contain any harmful HTML tag or attribute (such as iframe,
/// onclick, onmouseover, etc.).
///
/// # Examples
///
/// ```
/// use render::markdown_to_html;
///
/// let text = "[Rust](https://rust-lang.org/) is an awesome *systems programming* language!";
/// let rendered = markdown_to_html(text)?;
/// ```
pub fn markdown_to_html(text: &str) -> CargoResult<String> {
    let renderer = MarkdownRenderer::new();
    renderer.to_html(text)
}

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

    #[test]
    fn empty_text() {
        let text = "";
        let result = markdown_to_html(text).unwrap();
        assert_eq!(result, "");
    }

    #[test]
    fn text_with_script_tag() {
        let text = "foo_readme\n\n";
        let result = markdown_to_html(text).unwrap();
        assert_eq!(
            result,
            "
foo_readme
\n<script>alert(\'Hello World\')</script>\n"
        );
    }

    #[test]
    fn text_with_iframe_tag() {
        let text = "foo_readme\n\nalert('Hello World')";
        let result = markdown_to_html(text).unwrap();
        assert_eq!(
            result,
            "
foo_readme
\n<iframe>alert(\'Hello World\')</iframe>\n"
        );
    }

    #[test]
    fn text_with_unknown_tag() {
        let text = "foo_readme\n\n<unknown>alert('Hello World')</unknown>";
        let result = markdown_to_html(text).unwrap();
        assert_eq!(result, "
foo_readme
\n
alert(\'Hello World\')
\n");
    }

    #[test]
    fn text_with_inline_javascript() {
        let text = r#"foo_readme\n\nCrate page"#;
        let result = markdown_to_html(text).unwrap();
        assert_eq!(
            result,
            "
foo_readme\\n\\nCrate page
\n"
        );
    }

    // See https://github.com/kivikakk/comrak/issues/37. This panic happened
    // in comrak 0.1.8 but was fixed in 0.1.9.
    #[test]
    fn text_with_fancy_single_quotes() {
        let text = r#"wb’"#;
        let result = markdown_to_html(text).unwrap();
        assert_eq!(result, "
wb’
\n");
    }

    #[test]
    fn code_block_with_syntax_highlighting() {
        let code_block = r#"```rust \
                            println!("Hello World"); \
                           ```"#;
        let result = markdown_to_html(code_block).unwrap();
        assert!(result.contains(""));
    }

    #[test]
    fn text_with_forbidden_class_attribute() {
        let text = "
Hello World!
";
        let result = markdown_to_html(text).unwrap();
        assert_eq!(result, "
Hello World!
\n");
    }
}
<commit_msg>Enable ext_header_ids<commit_after>use ammonia::Ammonia;
use comrak;

use util::CargoResult;

/// Context for markdown to HTML rendering.
#[allow(missing_debug_implementations)]
pub struct MarkdownRenderer<'a> {
    html_sanitizer: Ammonia<'a>,
}

impl<'a> MarkdownRenderer<'a> {
    /// Creates a new renderer instance.
    pub fn new() -> MarkdownRenderer<'a> {
        let tags = [
            "a",
            "b",
            "blockquote",
            "br",
            "code",
            "dd",
            "del",
            "dl",
            "dt",
            "em",
            "h1",
            "h2",
            "h3",
            "hr",
            "i",
            "img",
            "input",
            "kbd",
            "li",
            "ol",
            "p",
            "pre",
            "s",
            "strike",
            "strong",
            "sub",
            "sup",
            "table",
            "tbody",
            "td",
            "th",
            "thead",
            "tr",
            "ul",
            "hr",
            "span",
        ].iter()
            .cloned()
            .collect();
        let tag_attributes = [
            ("a", ["href", "target"].iter().cloned().collect()),
            ("code", ["class"].iter().cloned().collect()),
            (
                "img",
                ["width", "height", "src", "alt", "align"]
                    .iter()
                    .cloned()
                    .collect(),
            ),
            (
                "input",
                ["checked", "disabled", "type"].iter().cloned().collect(),
            ),
        ].iter()
            .cloned()
            .collect();
        let allowed_classes = [
            (
                "code",
                [
                    "language-bash",
                    "language-clike",
                    "language-glsl",
                    "language-go",
                    "language-ini",
                    "language-javascript",
                    "language-json",
                    "language-markup",
                    "language-protobuf",
                    "language-ruby",
                    "language-rust",
                    "language-scss",
                    "language-sql",
                    "yaml",
                ].iter()
                    .cloned()
                    .collect(),
            ),
        ].iter()
            .cloned()
            .collect();
        let html_sanitizer = Ammonia {
            link_rel: Some("nofollow noopener noreferrer"),
            keep_cleaned_elements: true,
            tags: tags,
            tag_attributes: tag_attributes,
            allowed_classes: allowed_classes,
            ..Ammonia::default()
        };
        MarkdownRenderer {
            html_sanitizer: html_sanitizer,
        }
    }

    /// Renders the given markdown to HTML using the current settings.
    pub fn to_html(&self, text: &str) -> CargoResult<String> {
        let options = comrak::ComrakOptions {
            ext_autolink: true,
            ext_strikethrough: true,
            ext_table: true,
            ext_tagfilter: true,
            ext_tasklist: true,
            ext_header_ids: Some("user-content-".to_string()),
            ..comrak::ComrakOptions::default()
        };
        let rendered = comrak::markdown_to_html(text, &options);
        Ok(self.html_sanitizer.clean(&rendered))
    }
}

impl<'a> Default for MarkdownRenderer<'a> {
    fn default() -> Self {
        Self::new()
    }
}

/// Renders a markdown text to sanitized HTML.
///
/// The returned text should not contain any harmful HTML tag or attribute (such as iframe,
/// onclick, onmouseover, etc.).
///
/// # Examples
///
/// ```
/// use render::markdown_to_html;
///
/// let text = "[Rust](https://rust-lang.org/) is an awesome *systems programming* language!";
/// let rendered = markdown_to_html(text)?;
/// ```
pub fn markdown_to_html(text: &str) -> CargoResult<String> {
    let renderer = MarkdownRenderer::new();
    renderer.to_html(text)
}

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

    #[test]
    fn empty_text() {
        let text = "";
        let result = markdown_to_html(text).unwrap();
        assert_eq!(result, "");
    }

    #[test]
    fn text_with_script_tag() {
        let text = "foo_readme\n\n";
        let result = markdown_to_html(text).unwrap();
        assert_eq!(
            result,
            "
foo_readme
\n<script>alert(\'Hello World\')</script>\n"
        );
    }

    #[test]
    fn text_with_iframe_tag() {
        let text = "foo_readme\n\nalert('Hello World')";
        let result = markdown_to_html(text).unwrap();
        assert_eq!(
            result,
            "
foo_readme
\n<iframe>alert(\'Hello World\')</iframe>\n"
        );
    }

    #[test]
    fn text_with_unknown_tag() {
        let text = "foo_readme\n\n<unknown>alert('Hello World')</unknown>";
        let result = markdown_to_html(text).unwrap();
        assert_eq!(result, "
foo_readme
\n
alert(\'Hello World\')
\n");
    }

    #[test]
    fn text_with_inline_javascript() {
        let text = r#"foo_readme\n\nCrate page"#;
        let result = markdown_to_html(text).unwrap();
        assert_eq!(
            result,
            "
foo_readme\\n\\nCrate page
\n"
        );
    }

    // See https://github.com/kivikakk/comrak/issues/37. This panic happened
    // in comrak 0.1.8 but was fixed in 0.1.9.
    #[test]
    fn text_with_fancy_single_quotes() {
        let text = r#"wb’"#;
        let result = markdown_to_html(text).unwrap();
        assert_eq!(result, "
wb’
\n");
    }

    #[test]
    fn code_block_with_syntax_highlighting() {
        let code_block = r#"```rust \
                            println!("Hello World"); \
                           ```"#;
        let result = markdown_to_html(code_block).unwrap();
        assert!(result.contains(""));
    }

    #[test]
    fn text_with_forbidden_class_attribute() {
        let text = "
Hello World!
";
        let result = markdown_to_html(text).unwrap();
        assert_eq!(result, "
Hello World!
\n");
    }
}
<|endoftext|>


<commit_before>use std::io:: { Error as IOError };
use std::convert::From;
use std::result:: { Result };
use std::collections:: { HashMap };
use std::default::Default;
use lcov_parser::parser:: { LCOVParser, RecordParseError };
use lcov_parser::record:: { LCOVRecord };

pub enum ParseError {
    IOError(IOError),
    RecordParseError(RecordParseError)
}

impl From<IOError> for ParseError {
    fn from(error: IOError) -> Self {
        ParseError::IOError(error)
    }
}

impl From<RecordParseError> for ParseError {
    fn from(error: RecordParseError) -> Self {
        ParseError::RecordParseError(error)
    }
}

pub fn records_from_file(file: &str) -> Result<Vec<LCOVRecord>, ParseError> {
    let parser = try!(LCOVParser::from_file(file));
    Ok(try!(parser.parse()))
}

//
// $testcount = $testdata->{$testname};
// $testfnccount = $testfncdata->{$testname};
// $testbrcount = $testbrdata->{$testname};
//

#[derive(Clone)]
struct Test {
    test_count: HashMap<u32, u32>, // key: line number, value: test count
    test_fn_count: HashMap<String, u32>, // key: function name, value: line number
    test_br_count: u32 // FIXME br data structure
}

impl Default for Test {
    fn default() -> Self {
        Test {
            test_count: HashMap::new(),
            test_fn_count: HashMap::new(),
            test_br_count: 0
        }
    }
}

// my $sumcount
// my $sumbrcount
// my $sumfnccount
struct SumCount {
    sum_count: HashMap<u32, u32>, // key: line number, value: count
    sum_br_count: HashMap<String, u32>, // key: function name, value: execution count
    sum_fn_count: HashMap<String, u32> // FIXME br data structure
}

// key: line_number, value: checksum value
type CheckSum = HashMap<u32, String>;
type FunctionData = HashMap<String, u32>;

struct ReportParser {
    test_name: Option<String>,
    source_name: Option<String>,
    test: Option<Test>,
    tests: HashMap<String, Test>,
    sum: SumCount,
    checksum: CheckSum,
    func: FunctionData
}

impl ReportParser {
    fn parse(&mut self, file: &str) -> Result<(), ParseError> {
        let records = try!(records_from_file(file));

        for record in records.iter() {
            match record {
                &LCOVRecord::TestName(ref name) => self.on_test_name(name),
                &LCOVRecord::SourceFile(ref name) => self.on_source_file(name),
                &LCOVRecord::Data(ref line_number, ref execution_count, ref checksum) => self.on_data(
                    line_number,
                    execution_count,
                    checksum,
                ),
                &LCOVRecord::FunctionName(ref line_number, ref func_name, ) => self.on_func_data(
                    func_name,
                    line_number
                ),
                _ => { continue; }
            };
        }
        Ok(())
    }
    fn on_test_name(&mut self, test_name: &Option<String>) {
        self.test_name = test_name.clone();
    }
    fn on_source_file(&mut self, source_name: &String) {
        self.source_name = Some(source_name.clone());

        match self.test_name {
            Some(ref current_test_name) => {
                // $testcount = $testdata->{$testname};
                // $testfnccount = $testfncdata->{$testname};
                // $testbrcount = $testbrdata->{$testname};
                if !self.tests.contains_key(current_test_name) {
                    self.tests.insert(current_test_name.to_string(), Test::default());
                }
                let test = self.tests.get(current_test_name);
                self.test = Some(test.unwrap().clone());
            },
            None => self.test = Some(Test::default())
        }
    }
    fn on_data(&mut self, line_number: &u32, execution_count: &u32, checksum: &Option<String>) {
        let mut sum_count = self.sum.sum_count.entry(line_number.clone()).or_insert(0);
        *sum_count += *execution_count;

        if self.test_name.is_some() {
            if self.test.is_some() {
                let mut test = self.test.as_mut().unwrap();
                let mut test_count = test.test_count.entry(line_number.clone()).or_insert(0);
                *test_count += *execution_count;
            }
        }

        if checksum.is_none() {
            return;
        }

        if !self.checksum.contains_key(line_number) {
            let checksum_value = checksum.clone().unwrap();
            self.checksum.insert(line_number.clone(), checksum_value);
            return;
        }

        let checksum_value = checksum.clone().unwrap();
        let current_checksum = self.checksum.get(line_number).unwrap();
        if current_checksum != &checksum_value {
            println!("{} {}", current_checksum, checksum_value);
        }
    }
    fn on_func_data(&mut self, func_name: &String, line_number: &u32) {
        let _ = self.func.entry(func_name.clone())
            .or_insert(line_number.clone());

        let _ = self.sum.sum_fn_count.entry(func_name.clone())
            .or_insert(0);

        if self.test_name.is_some() {
            if self.test.is_some() {
                let mut test = self.test.as_mut().unwrap();
                let _ = test.test_fn_count.entry(func_name.clone()).or_insert(0);
            }
        }

        if !(self.test_name.is_some() && self.test.is_some()) {
            return;
        }
        let mut test = self.test.as_mut().unwrap();
        let _ = test.test_fn_count.entry(func_name.clone()).or_insert(0);
    }
}
<commit_msg>paser func data<commit_after>use std::io:: { Error as IOError };
use std::convert::From;
use std::result:: { Result };
use std::collections:: { HashMap };
use std::default::Default;
use lcov_parser::parser:: { LCOVParser, RecordParseError };
use lcov_parser::record:: { LCOVRecord };

pub enum ParseError {
    IOError(IOError),
    RecordParseError(RecordParseError)
}

impl From<IOError> for ParseError {
    fn from(error: IOError) -> Self {
        ParseError::IOError(error)
    }
}

impl From<RecordParseError> for ParseError {
    fn from(error: RecordParseError) -> Self {
        ParseError::RecordParseError(error)
    }
}

pub fn records_from_file(file: &str) -> Result<Vec<LCOVRecord>, ParseError> {
    let parser = try!(LCOVParser::from_file(file));
    Ok(try!(parser.parse()))
}

//
// $testcount = $testdata->{$testname};
// $testfnccount = $testfncdata->{$testname};
// $testbrcount = $testbrdata->{$testname};
//

#[derive(Clone)]
struct Test {
    test_count: HashMap<u32, u32>, // key: line number, value: test count
    test_fn_count: HashMap<String, u32>, // key: function name, value: line number
    test_br_count: u32 // FIXME br data structure
}

impl Default for Test {
    fn default() -> Self {
        Test {
            test_count: HashMap::new(),
            test_fn_count: HashMap::new(),
            test_br_count: 0
        }
    }
}

// my $sumcount
// my $sumbrcount
// my $sumfnccount
struct SumCount {
    sum_count: HashMap<u32, u32>, // key: line number, value: count
    sum_br_count: HashMap<String, u32>, // key: function name, value: execution count
    sum_fn_count: HashMap<String, u32> // FIXME br data structure
}

// key: line_number, value: checksum value
type CheckSum = HashMap<u32, String>;
type FunctionData = HashMap<String, u32>;

struct ReportParser {
    test_name: Option<String>,
    source_name: Option<String>,
    test: Option<Test>,
    tests: HashMap<String, Test>,
    sum: SumCount,
    checksum: CheckSum,
    func: FunctionData
}

impl ReportParser {
    fn parse(&mut self, file: &str) -> Result<(), ParseError> {
        let records = try!(records_from_file(file));

        for record in records.iter() {
            match record {
                &LCOVRecord::TestName(ref name) => self.on_test_name(name),
                &LCOVRecord::SourceFile(ref name) => self.on_source_file(name),
                &LCOVRecord::Data(ref line_number, ref execution_count, ref checksum) => self.on_data(
                    line_number,
                    execution_count,
                    checksum,
                ),
                &LCOVRecord::FunctionName(ref line_number, ref func_name, ) => self.on_func_name(
                    func_name,
                    line_number
                ),
                &LCOVRecord::FunctionData(ref execution_count, ref func_name) => self.on_func_data(
                    func_name,
                    execution_count
                ),
                _ => { continue; }
            };
        }
        Ok(())
    }
    fn on_test_name(&mut self, test_name: &Option<String>) {
        self.test_name = test_name.clone();
    }
    fn on_source_file(&mut self, source_name: &String) {
        self.source_name = Some(source_name.clone());

        match self.test_name {
            Some(ref current_test_name) => {
                // $testcount = $testdata->{$testname};
                // $testfnccount = $testfncdata->{$testname};
                // $testbrcount = $testbrdata->{$testname};
                if !self.tests.contains_key(current_test_name) {
                    self.tests.insert(current_test_name.to_string(), Test::default());
                }
                let test = self.tests.get(current_test_name);
                self.test = Some(test.unwrap().clone());
            },
            None => self.test = Some(Test::default())
        }
    }
    fn on_data(&mut self, line_number: &u32, execution_count: &u32, checksum: &Option<String>) {
        let mut sum_count = self.sum.sum_count.entry(line_number.clone()).or_insert(0);
        *sum_count += *execution_count;

        if self.test_name.is_some() {
            if self.test.is_some() {
                let mut test = self.test.as_mut().unwrap();
                let mut test_count = test.test_count.entry(line_number.clone()).or_insert(0);
                *test_count += *execution_count;
            }
        }

        if checksum.is_none() {
            return;
        }

        if !self.checksum.contains_key(line_number) {
            let checksum_value = checksum.clone().unwrap();
            self.checksum.insert(line_number.clone(), checksum_value);
            return;
        }

        let checksum_value = checksum.clone().unwrap();
        let current_checksum = self.checksum.get(line_number).unwrap();
        if current_checksum != &checksum_value {
            println!("{} {}", current_checksum, checksum_value);
        }
    }
    fn on_func_name(&mut self, func_name: &String, line_number: &u32) {
        let _ = self.func.entry(func_name.clone())
            .or_insert(line_number.clone());

        let _ = self.sum.sum_fn_count.entry(func_name.clone())
            .or_insert(0);

        if self.test_name.is_some() {
            if self.test.is_some() {
                let mut test = self.test.as_mut().unwrap();
                let _ = test.test_fn_count.entry(func_name.clone()).or_insert(0);
            }
        }

        if !(self.test_name.is_some() && self.test.is_some()) {
            return;
        }
        let mut test = self.test.as_mut().unwrap();
        let _ = test.test_fn_count.entry(func_name.clone()).or_insert(0);
    }
    fn on_func_data(&mut self, func_name: &String, execution_count: &u32) {
        let mut sum_fn_count = self.sum.sum_fn_count.entry(func_name.clone()).or_insert(0);
        *sum_fn_count += *execution_count;

        if self.test_name.is_none() {
            return;
        }

        let mut test = self.test.as_mut().unwrap();
        let mut test_fn_count = test.test_fn_count.entry(func_name.clone()).or_insert(0);
        *test_fn_count += *execution_count;
    }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate hyper_native_tls;
extern crate rustc_serialize;

use std::io::*;
use std::result::Result;
use std::fs::File;
use std::fs::OpenOptions;
use self::rustc_serialize::json::Json;
use std::collections::BTreeMap;

use hyper::Client;
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;

pub struct TTVEmoteData {
    pub template: String,
    pub data: Vec<(String, String)>,
    sub_emotes: Option<Json>,
}

pub struct BTTVEmoteData {
    pub template: String,
    pub data: Vec<(String, String)>,
}

pub struct Config {
    pub global_ttv: bool,
    pub global_bttv: bool,
    pub ttv_channels: Vec<String>,
    pub bttv_channels: Vec<String>,
}

impl TTVEmoteData {
    pub fn new() -> TTVEmoteData {
        TTVEmoteData {
            template: String::new(),
            data: Vec::new(),
            sub_emotes: None,
        }
    }

    pub fn get_global_emotes(&mut self) -> Result<(), String> {

        let obj = match download_json("https://twitchemotes.com/api_cache/v2/global.json") {
            Ok(v) => v,
            Err(e) => return Err(e),
        };

        let templates = obj.get("template").unwrap().as_object().unwrap();
        self.template = templates
            .get("small")
            .unwrap()
            .as_string()
            .unwrap()
            .to_owned();

        let emotes = obj.get("emotes").unwrap();

        for (name, value) in emotes.as_object().unwrap().iter() {
            let id = value
                .as_object()
                .unwrap()
                .get("image_id")
                .unwrap()
                .as_u64()
                .unwrap();
            self.data.push((name.to_owned(), id.to_string()));
        }

        Ok(())
    }

    pub fn update_sub_emote_data(&mut self) -> Result<(), String> {

        println!("Downloading subscriber emote data");
        let obj = match download_json("https://twitchemotes.com/api_cache/v2/subscriber.json") {
            Ok(v) => v,
            Err(e) => return Err(e),
        };

        let templates = obj.get("template").unwrap().as_object().unwrap();

        self.template = templates
            .get("small")
            .unwrap()
            .as_string()
            .unwrap()
            .to_owned();
        self.sub_emotes = obj.get("channels").cloned();

        Ok(())
    }

    pub fn get_subscriber_emotes(&mut self, channel: &str) -> Result<(), String> {

        if self.sub_emotes == None {
            if let Err(e) = self.update_sub_emote_data() {
                return Err(e);
            }
        }

        let mut count = 0;

        for (channel_name, value) in
            self.sub_emotes
                .as_ref()
                .unwrap()
                .as_object()
                .unwrap()
                .iter() {

            if channel.to_lowercase() != channel_name.to_lowercase() { continue; }

            let emotes = value
                .as_object()
                .unwrap()
                .get("emotes")
                .unwrap()
                .as_array()
                .unwrap();

            for ref emote in emotes.iter() {
                let object = emote.as_object().unwrap();

                let name = object.get("code").unwrap().as_string().unwrap();
                let id = object.get("image_id").unwrap().as_u64().unwrap();

                self.data.push((name.to_owned(), id.to_string()));
                count += 1;
            }
        }
        match count {
            0 => Err("No emotes found".to_owned()),
            _ => Ok(()),
        }
    }
}

impl BTTVEmoteData {
    pub fn new() -> BTTVEmoteData {
        BTTVEmoteData {
            template: String::new(),
            data: Vec::new(),
        }
    }

    pub fn get_global_bttv_emotes(&mut self) -> Result<(), String> {

        let obj = match download_json("https://api.betterttv.net/2/emotes") {
            Ok(v) => v,
            Err(e) => return Err(e),
        };

        self.template = obj.get("urlTemplate")
            .unwrap()
            .as_string()
            .unwrap()
            .to_owned()
            .replace("{{image}}", "1x");
        self.template.insert_str(0, "https:");

        let emotes = obj.get("emotes").unwrap().as_array().unwrap();

        for ref emote in emotes.iter() {

            let object = emote.as_object().unwrap();

            let name = object.get("code").unwrap().as_string().unwrap();
            let id = object.get("id").unwrap().as_string().unwrap();
            let img_type = object.get("imageType").unwrap().as_string().unwrap();

            match img_type {
                "png" => self.data.push((name.to_owned(), id.to_string())),
                "gif" => {},
                _     => println!("Unexpected image type: {}", img_type),
            };
        }

        Ok(())
    }

    pub fn get_channel_bttv_emotes(&mut self, channel: &str) -> Result<(), String> {

        let obj = match download_json(&format!("https://api.betterttv.net/2/channels/{}",
                                               channel)) {
            Ok(v) => v,
            Err(e) => return Err(e),
        };

        self.template = obj.get("urlTemplate")
            .unwrap()
            .as_string()
            .unwrap()
            .to_owned()
            .replace("{{image}}", "1x");
        self.template.insert_str(0, "https:");

        let emotes = obj.get("emotes").unwrap().as_array().unwrap();

        for ref emote in emotes.iter() {
            let object = emote.as_object().unwrap();

            let name = object.get("code").unwrap().as_string().unwrap();
            let id = object.get("id").unwrap().as_string().unwrap();
            let img_type = object.get("imageType").unwrap().as_string().unwrap();

            match img_type {
                "png" => self.data.push((name.to_owned(), id.to_string())),
                "gif" => {},
                _     => println!("Unexpected image type: {}", img_type),
            };
        }

        Ok(())
    }
}

impl Config {
    pub fn new() -> Config {
        Config {
            global_ttv: false,
            global_bttv: false,
            ttv_channels: Vec::new(),
            bttv_channels: Vec::new(),
        }
    }

    pub fn create_from_file(mut self, path: &str) -> Config {

        let cfgfile = match OpenOptions::new().read(true).open(path) {
            Ok(v) => v,
            Err(e) => {
                println!("{}", e);
                return self;
            }
        };
        let buf_reader = BufReader::new(cfgfile);

        for v in buf_reader.lines() {

            let line = v.unwrap();
            let s: Vec<&str> = line.split(":").collect();
            let data = *s.last().unwrap();

            match *s.first().unwrap() {
                "TTV-Global"   => self.global_ttv = data == "true",
                "TTV-Channel"  => self.ttv_channels.push(String::from(data)),
                "BTTV-Global"  => self.global_bttv = data == "true",
                "BTTV-Channel" => self.bttv_channels.push(String::from(data)),
                ""             => {},
                _              => println!("Invalid Line!({})", *s.first().unwrap()),
            }
        }
        self
    }

    pub fn write_to_file(&mut self, path: &str) {

        let mut cfgfile = match OpenOptions::new().open(path) {
            Ok(v) => v,
            Err(_) => {
                match File::create(path) {
                    Ok(v) => v,
                    Err(e) => {
                        println!("{}", e);
                        return;
                    }
                }
            }
        };

        if let Err(e) = writeln!(cfgfile, "TTV-Global:{}", self.global_ttv.to_string()) {
            println!("{}", e);
        }

        for channel in self.ttv_channels.clone() {
            if let Err(e) = writeln!(cfgfile, "TTV-Channel:{}", channel) {
                println!("{}", e);
            }
        }

        if let Err(e) = writeln!(cfgfile, "BTTV-Global:{}", self.global_ttv.to_string()) {
            println!("{}", e);
        }

        for channel in self.bttv_channels.clone() {
            if let Err(e) = writeln!(cfgfile, "BTTV-Channel:{}", channel) {
                println!("{}", e);
            }
        }
    }
}

fn download_json(url: &str) -> Result<BTreeMap<String, Json>, String> {

    let ssl = NativeTlsClient::new().unwrap();
    let connector = HttpsConnector::new(ssl);
    let client = Client::with_connector(connector);

    let mut res = match client.get(url).send() {
        Ok(v) => v,
        Err(e) => return Err(format!("{}", e)),
    };

    let mut s = String::new();
    if let Err(e) = res.read_to_string(&mut s) {
        return Err(format!("{}", e));
    }

    let data = Json::from_str(&s).unwrap();
    let obj = data.as_object().unwrap();

    match obj.get("status") {
        Some(v) => {
            match v.as_u64().unwrap() {
                200 => return Ok(obj.clone()),
                _ => {
                    Err(obj.get("message")
                            .unwrap()
                            .as_string()
                            .unwrap()
                            .to_owned())
                }
            }
        }
        None => return Ok(obj.clone()),
    }
}
<commit_msg>Fix crash on empty response<commit_after>extern crate hyper;
extern crate hyper_native_tls;
extern crate rustc_serialize;

use std::io::*;
use std::result::Result;
use std::fs::File;
use std::fs::OpenOptions;
use self::rustc_serialize::json::Json;
use std::collections::BTreeMap;

use hyper::Client;
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;

pub struct TTVEmoteData {
    pub template: String,
    pub data: Vec<(String, String)>,
    sub_emotes: Option<Json>,
}

pub struct BTTVEmoteData {
    pub template: String,
    pub data: Vec<(String, String)>,
}

pub struct Config {
    pub global_ttv: bool,
    pub global_bttv: bool,
    pub ttv_channels: Vec<String>,
    pub bttv_channels: Vec<String>,
}

impl TTVEmoteData {
    pub fn new() -> TTVEmoteData {
        TTVEmoteData {
            template: String::new(),
            data: Vec::new(),
            sub_emotes: None,
        }
    }

    pub fn get_global_emotes(&mut self) -> Result<(), String> {

        let obj = match download_json("https://twitchemotes.com/api_cache/v2/global.json") {
            Ok(v) => v,
            Err(e) => return Err(e),
        };

        let templates = obj.get("template").unwrap().as_object().unwrap();
        self.template = templates
            .get("small")
            .unwrap()
            .as_string()
            .unwrap()
            .to_owned();

        let emotes = obj.get("emotes").unwrap();

        for (name, value) in emotes.as_object().unwrap().iter() {
            let id = value
                .as_object()
                .unwrap()
                .get("image_id")
                .unwrap()
                .as_u64()
                .unwrap();
            self.data.push((name.to_owned(), id.to_string()));
        }

        Ok(())
    }

    pub fn update_sub_emote_data(&mut self) -> Result<(), String> {

        println!("Downloading subscriber emote data");
        let obj = match download_json("https://twitchemotes.com/api_cache/v2/subscriber.json") {
            Ok(v) => v,
            Err(e) => return Err(e),
        };

        let templates = obj.get("template").unwrap().as_object().unwrap();

        self.template = templates
            .get("small")
            .unwrap()
            .as_string()
            .unwrap()
            .to_owned();
        self.sub_emotes = obj.get("channels").cloned();

        Ok(())
    }

    pub fn get_subscriber_emotes(&mut self, channel: &str) -> Result<(), String> {

        if self.sub_emotes == None {
            if let Err(e) = self.update_sub_emote_data() {
                return Err(e);
            }
        }

        let mut count = 0;

        for (channel_name, value) in
            self.sub_emotes
                .as_ref()
                .unwrap()
                .as_object()
                .unwrap()
                .iter() {

            if channel.to_lowercase() != channel_name.to_lowercase() { continue; }

            let emotes = value
                .as_object()
                .unwrap()
                .get("emotes")
                .unwrap()
                .as_array()
                .unwrap();

            for ref emote in emotes.iter() {
                let object = emote.as_object().unwrap();

                let name = object.get("code").unwrap().as_string().unwrap();
                let id = object.get("image_id").unwrap().as_u64().unwrap();

                self.data.push((name.to_owned(), id.to_string()));
                count += 1;
            }
        }
        match count {
            0 => Err("No emotes found".to_owned()),
            _ => Ok(()),
        }
    }
}

impl BTTVEmoteData {
    pub fn new() -> BTTVEmoteData {
        BTTVEmoteData {
            template: String::new(),
            data: Vec::new(),
        }
    }

    pub fn get_global_bttv_emotes(&mut self) -> Result<(), String> {

        let obj = match download_json("https://api.betterttv.net/2/emotes") {
            Ok(v) => v,
            Err(e) => return Err(e),
        };

        self.template = obj.get("urlTemplate")
            .unwrap()
            .as_string()
            .unwrap()
            .to_owned()
            .replace("{{image}}", "1x");
        self.template.insert_str(0, "https:");

        let emotes = obj.get("emotes").unwrap().as_array().unwrap();

        for ref emote in emotes.iter() {

            let object = emote.as_object().unwrap();

            let name = object.get("code").unwrap().as_string().unwrap();
            let id = object.get("id").unwrap().as_string().unwrap();
            let img_type = object.get("imageType").unwrap().as_string().unwrap();

            match img_type {
                "png" => self.data.push((name.to_owned(), id.to_string())),
                "gif" => {},
                _     => println!("Unexpected image type: {}", img_type),
            };
        }

        Ok(())
    }

    pub fn get_channel_bttv_emotes(&mut self, channel: &str) -> Result<(), String> {

        let obj = match download_json(&format!("https://api.betterttv.net/2/channels/{}",
                                               channel)) {
            Ok(v) => v,
            Err(e) => return Err(e),
        };

        self.template = obj.get("urlTemplate")
            .unwrap()
            .as_string()
            .unwrap()
            .to_owned()
            .replace("{{image}}", "1x");
        self.template.insert_str(0, "https:");

        let emotes = obj.get("emotes").unwrap().as_array().unwrap();

        for ref emote in emotes.iter() {
            let object = emote.as_object().unwrap();

            let name = object.get("code").unwrap().as_string().unwrap();
            let id = object.get("id").unwrap().as_string().unwrap();
            let img_type = object.get("imageType").unwrap().as_string().unwrap();

            match img_type {
                "png" => self.data.push((name.to_owned(), id.to_string())),
                "gif" => {},
                _     => println!("Unexpected image type: {}", img_type),
            };
        }

        Ok(())
    }
}

impl Config {
    pub fn new() -> Config {
        Config {
            global_ttv: false,
            global_bttv: false,
            ttv_channels: Vec::new(),
            bttv_channels: Vec::new(),
        }
    }

    pub fn create_from_file(mut self, path: &str) -> Config {

        let cfgfile = match OpenOptions::new().read(true).open(path) {
            Ok(v) => v,
            Err(e) => {
                println!("{}", e);
                return self;
            }
        };
        let buf_reader = BufReader::new(cfgfile);

        for v in buf_reader.lines() {

            let line = v.unwrap();
            let s: Vec<&str> = line.split(":").collect();
            let data = *s.last().unwrap();

            match *s.first().unwrap() {
                "TTV-Global"   => self.global_ttv = data == "true",
                "TTV-Channel"  => self.ttv_channels.push(String::from(data)),
                "BTTV-Global"  => self.global_bttv = data == "true",
                "BTTV-Channel" => self.bttv_channels.push(String::from(data)),
                ""             => {},
                _              => println!("Invalid Line!({})", *s.first().unwrap()),
            }
        }
        self
    }

    pub fn write_to_file(&mut self, path: &str) {

        let mut cfgfile = match OpenOptions::new().open(path) {
            Ok(v) => v,
            Err(_) => {
                match File::create(path) {
                    Ok(v) => v,
                    Err(e) => {
                        println!("{}", e);
                        return;
                    }
                }
            }
        };

        if let Err(e) = writeln!(cfgfile, "TTV-Global:{}", self.global_ttv.to_string()) {
            println!("{}", e);
        }

        for channel in self.ttv_channels.clone() {
            if let Err(e) = writeln!(cfgfile, "TTV-Channel:{}", channel) {
                println!("{}", e);
            }
        }

        if let Err(e) = writeln!(cfgfile, "BTTV-Global:{}", self.global_ttv.to_string()) {
            println!("{}", e);
        }

        for channel in self.bttv_channels.clone() {
            if let Err(e) = writeln!(cfgfile, "BTTV-Channel:{}", channel) {
                println!("{}", e);
            }
        }
    }
}

fn download_json(url: &str) -> Result<BTreeMap<String, Json>, String> {

    let ssl = NativeTlsClient::new().unwrap();
    let connector = HttpsConnector::new(ssl);
    let client = Client::with_connector(connector);

    let mut res = match client.get(url).send() {
        Ok(v) => v,
        Err(e) => return Err(format!("{}", e)),
    };

    let mut s = String::new();
    if let Err(e) = res.read_to_string(&mut s) {
        return Err(format!("{}", e));
    }

    if s.is_empty() {
        return Err(format!("Response from {} was empty", url));
    }

    let data = Json::from_str(&s).unwrap();
    let obj = data.as_object().unwrap();

    match obj.get("status") {
        Some(v) => {
            match v.as_u64().unwrap() {
                200 => return Ok(obj.clone()),
                _ => {
                    Err(obj.get("message")
                            .unwrap()
                            .as_string()
                            .unwrap()
                            .to_owned())
                }
            }
        }
        None => return Ok(obj.clone()),
    }
}
<|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/.

use config::Config;
use domain_store::{DomainError, DomainRecord};
use errors::*;
use iron::headers::ContentType;
use iron::prelude::*;
use iron::status::{self, Status};
use params::{FromValue, Params, Value};
use pdns::pdns;
use router::Router;
use serde_json;
use std::time::{SystemTime, UNIX_EPOCH};
use uuid::Uuid;

fn domain_for_name(name: &str, config: &Config) -> String {
    format!("{}.box.{}.", name, config.domain).to_lowercase()
}

fn register(req: &mut Request, config: &Config) -> IronResult<Response> {
    // Extract the local_ip and token parameter,
    // and the public IP from the socket.
    let public_ip = format!("{}", req.remote_addr.ip());

    let map = req.get_ref::<Params>().unwrap(); // TODO: don't unwrap.
    let token = map.find(&["token"]);
    let local_ip = map.find(&["local_ip"]);

    // Both parameters are mandatory.
    if token.is_none() || local_ip.is_none() {
        return EndpointError::with(status::BadRequest, 400);
    }

    let token = String::from_value(token.unwrap()).unwrap();
    let local_ip = String::from_value(local_ip.unwrap()).unwrap();

    info!("GET /register token={} local_ip={} public_ip={}",
          token,
          local_ip,
          public_ip);

    // Save this registration in the database if we know about this token.
    // Check if we have a record with this token, bail out if not.
    match config
              .domain_db
              .get_record_by_token(&token)
              .recv()
              .unwrap() {
        Ok(record) => {
            // Update the record with the challenge.
            let dns_challenge = match record.dns_challenge {
                Some(ref challenge) => Some(challenge.as_str()),
                None => None,
            };
            // Update the timestamp to be current.
            let timestamp = SystemTime::now()
                .duration_since(UNIX_EPOCH)
                .unwrap()
                .as_secs() as i64;

            let new_record = DomainRecord::new(&record.name,
                                               &record.token,
                                               dns_challenge,
                                               Some(&local_ip),
                                               Some(&public_ip),
                                               timestamp);
            match config
                      .domain_db
                      .update_record(new_record)
                      .recv()
                      .unwrap() {
                Ok(()) => {
                    // Everything went fine, return an empty 200 OK for now.
                    let mut response = Response::new();
                    response.status = Some(Status::Ok);

                    Ok(response)
                }
                Err(_) => EndpointError::with(status::InternalServerError, 501),
            }
        }
        Err(DomainError::NoRecord) => EndpointError::with(status::BadRequest, 400),
        Err(_) => EndpointError::with(status::InternalServerError, 501),
    }
}

fn info(req: &mut Request, config: &Config) -> IronResult<Response> {
    info!("GET /info");

    let map = req.get_ref::<Params>().unwrap(); // TODO: don't unwrap.
    let token = map.find(&["token"]);
    if token.is_none() {
        return EndpointError::with(status::BadRequest, 400);
    }
    let token = String::from_value(token.unwrap()).unwrap();

    match config
              .domain_db
              .get_record_by_token(&token)
              .recv()
              .unwrap() {
        Ok(record) => {
            let mut response = Response::with(serde_json::to_string(&record).unwrap());
            response.headers.set(ContentType::json());
            Ok(response)
        }
        Err(DomainError::NoRecord) => EndpointError::with(status::BadRequest, 400),
        Err(_) => EndpointError::with(status::InternalServerError, 501),
    }
}

fn discovery(req: &mut Request, config: &Config) -> IronResult<Response> {
    info!("GET /discovery");

    let remote_ip = format!("{}", req.remote_addr.ip());

    let map = req.get_ref::<Params>().unwrap(); // TODO: don't unwrap.
    let token = map.find(&["token"]);
    if token.is_none() {
        return EndpointError::with(status::BadRequest, 400);
    }
    let token = String::from_value(token.unwrap()).unwrap();

    match config
              .domain_db
              .get_record_by_token(&token)
              .recv()
              .unwrap() {
        Ok(record) => {
            if record.public_ip.is_none() {
                return EndpointError::with(status::BadRequest, 400);
            }

            #[derive(Serialize)]
            struct Discovery {
                href: String,
                kind: String,
            }
            let answer = if record.public_ip.unwrap() == remote_ip {
                // This is a connection from the same network.
                Discovery {
                    href: record.name,
                    kind: "local".to_owned(),
                }
            } else {
                Discovery {
                    href: record.name,
                    kind: "remote".to_owned(),
                }
            };

            let mut response = Response::with(serde_json::to_string(&answer).unwrap());
            response.headers.set(ContentType::json());
            Ok(response)
        }
        Err(DomainError::NoRecord) => EndpointError::with(status::BadRequest, 400),
        Err(_) => EndpointError::with(status::InternalServerError, 501),
    }
}

fn unsubscribe(req: &mut Request, config: &Config) -> IronResult<Response> {
    info!("GET /unsubscribe");

    let map = req.get_ref::<Params>().unwrap(); // TODO: don't unwrap.
    let token = map.find(&["token"]);
    if token.is_none() {
        return EndpointError::with(status::BadRequest, 400);
    }
    let token = String::from_value(token.unwrap()).unwrap();

    match config
              .domain_db
              .delete_record_by_token(&token)
              .recv()
              .unwrap() {
        Ok(0) => EndpointError::with(status::BadRequest, 400), // No record found for this token.
        Ok(_) => {
            let mut response = Response::new();
            response.status = Some(Status::Ok);

            Ok(response)
        }
        Err(_) => EndpointError::with(status::InternalServerError, 501),
    }
}

fn subscribe(req: &mut Request, config: &Config) -> IronResult<Response> {
    info!("GET /subscribe");

    // Extract the name parameter.
    let map = req.get_ref::<Params>().unwrap(); // TODO: don't unwrap.
    match map.find(&["name"]) {
        Some(&Value::String(ref name)) => {
            let full_name = domain_for_name(name, config);
            info!("trying to subscribe {}", full_name);

            let record = config
                .domain_db
                .get_record_by_name(&full_name)
                .recv()
                .unwrap();
            match record {
                Ok(_) => {
                    // We already have a record for this name, return an error.
                    let mut response = Response::with("{\"error\": \"UnavailableName\"}");
                    response.status = Some(Status::BadRequest);
                    response.headers.set(ContentType::json());
                    Ok(response)
                }
                Err(DomainError::NoRecord) => {
                    // Create a token, create and store a record and finally return the token.
                    let token = format!("{}", Uuid::new_v4());
                    let record = DomainRecord::new(&full_name, &token, None, None, None, 0);
                    match config.domain_db.add_record(record).recv().unwrap() {
                        Ok(()) => {
                            // We don't want the full domain name or the dns challenge in the
                            // response so we create a local struct.
                            #[derive(Serialize)]
                            struct NameAndToken {
                                name: String,
                                token: String,
                            }
                            let n_and_t = NameAndToken {
                                name: name.to_owned(),
                                token: token,
                            };
                            match serde_json::to_string(&n_and_t) {
                                Ok(serialized) => {
                                    let mut response = Response::with(serialized);
                                    response.status = Some(Status::Ok);
                                    response.headers.set(ContentType::json());

                                    Ok(response)
                                }
                                Err(_) => EndpointError::with(status::InternalServerError, 501)
                            }
                        }
                        Err(_) => EndpointError::with(status::InternalServerError, 501),
                    }
                }
                // Other error, like a db issue.
                Err(_) => EndpointError::with(status::InternalServerError, 501),
            }
        }
        // Missing `name` parameter.
        _ => EndpointError::with(status::BadRequest, 400),
    }
}

fn dnsconfig(req: &mut Request, config: &Config) -> IronResult<Response> {
    info!("GET /dnsconfig");

    // Extract the challenge and token parameter.
    let map = req.get_ref::<Params>().unwrap(); // TODO: don't unwrap.
    let challenge = map.find(&["challenge"]);
    let token = map.find(&["token"]);

    // Both parameters are mandatory.
    if challenge.is_none() || token.is_none() {
        return EndpointError::with(status::BadRequest, 400);
    }

    let challenge = String::from_value(challenge.unwrap()).unwrap();
    let token = String::from_value(token.unwrap()).unwrap();

    // Check if we have a record with this token, bail out if not.
    match config
              .domain_db
              .get_record_by_token(&token)
              .recv()
              .unwrap() {
        Ok(record) => {
            // Update the record with the challenge.
            let local_ip = match record.local_ip {
                Some(ref ip) => Some(ip.as_str()),
                None => None,
            };
            let public_ip = match record.public_ip {
                Some(ref ip) => Some(ip.as_str()),
                None => None,
            };

            let new_record = DomainRecord::new(&record.name,
                                               &record.token,
                                               Some(&challenge),
                                               local_ip,
                                               public_ip,
                                               record.timestamp);
            match config
                      .domain_db
                      .update_record(new_record)
                      .recv()
                      .unwrap() {
                Ok(()) => {
                    // Everything went fine, return an empty 200 OK for now.
                    let mut response = Response::new();
                    response.status = Some(Status::Ok);

                    Ok(response)
                }
                Err(_) => EndpointError::with(status::InternalServerError, 501),
            }
        }
        Err(DomainError::NoRecord) => EndpointError::with(status::BadRequest, 400),
        Err(_) => EndpointError::with(status::InternalServerError, 501),
    }
}

pub fn create(config: &Config) -> Router {
    let mut router = Router::new();

    macro_rules! handler {
        ($name:ident) => (
            let config_ = config.clone();
            router.get(stringify!($name),
                       move |req: &mut Request| -> IronResult<Response> {
                $name(req, &config_)
            }, stringify!($name));
        )
    }

    handler!(register);
    handler!(info);
    handler!(subscribe);
    handler!(unsubscribe);
    handler!(dnsconfig);
    handler!(discovery);

    if config.socket_path.is_none() {
        handler!(pdns);
    }

    router
}
<commit_msg>Improve the discovery payload<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/.

use config::Config;
use domain_store::{DomainError, DomainRecord};
use errors::*;
use iron::headers::ContentType;
use iron::prelude::*;
use iron::status::{self, Status};
use params::{FromValue, Params, Value};
use pdns::pdns;
use router::Router;
use serde_json;
use std::time::{SystemTime, UNIX_EPOCH};
use uuid::Uuid;

fn domain_for_name(name: &str, config: &Config) -> String {
    format!("{}.box.{}.", name, config.domain).to_lowercase()
}

fn register(req: &mut Request, config: &Config) -> IronResult<Response> {
    // Extract the local_ip and token parameter,
    // and the public IP from the socket.
    let public_ip = format!("{}", req.remote_addr.ip());

    let map = req.get_ref::<Params>().unwrap(); // TODO: don't unwrap.
    let token = map.find(&["token"]);
    let local_ip = map.find(&["local_ip"]);

    // Both parameters are mandatory.
    if token.is_none() || local_ip.is_none() {
        return EndpointError::with(status::BadRequest, 400);
    }

    let token = String::from_value(token.unwrap()).unwrap();
    let local_ip = String::from_value(local_ip.unwrap()).unwrap();

    info!("GET /register token={} local_ip={} public_ip={}",
          token,
          local_ip,
          public_ip);

    // Save this registration in the database if we know about this token.
    // Check if we have a record with this token, bail out if not.
    match config
              .domain_db
              .get_record_by_token(&token)
              .recv()
              .unwrap() {
        Ok(record) => {
            // Update the record with the challenge.
            let dns_challenge = match record.dns_challenge {
                Some(ref challenge) => Some(challenge.as_str()),
                None => None,
            };
            // Update the timestamp to be current.
            let timestamp = SystemTime::now()
                .duration_since(UNIX_EPOCH)
                .unwrap()
                .as_secs() as i64;

            let new_record = DomainRecord::new(&record.name,
                                               &record.token,
                                               dns_challenge,
                                               Some(&local_ip),
                                               Some(&public_ip),
                                               timestamp);
            match config
                      .domain_db
                      .update_record(new_record)
                      .recv()
                      .unwrap() {
                Ok(()) => {
                    // Everything went fine, return an empty 200 OK for now.
                    let mut response = Response::new();
                    response.status = Some(Status::Ok);

                    Ok(response)
                }
                Err(_) => EndpointError::with(status::InternalServerError, 501),
            }
        }
        Err(DomainError::NoRecord) => EndpointError::with(status::BadRequest, 400),
        Err(_) => EndpointError::with(status::InternalServerError, 501),
    }
}

fn info(req: &mut Request, config: &Config) -> IronResult<Response> {
    info!("GET /info");

    let map = req.get_ref::<Params>().unwrap(); // TODO: don't unwrap.
    let token = map.find(&["token"]);
    if token.is_none() {
        return EndpointError::with(status::BadRequest, 400);
    }
    let token = String::from_value(token.unwrap()).unwrap();

    match config
              .domain_db
              .get_record_by_token(&token)
              .recv()
              .unwrap() {
        Ok(record) => {
            let mut response = Response::with(serde_json::to_string(&record).unwrap());
            response.headers.set(ContentType::json());
            Ok(response)
        }
        Err(DomainError::NoRecord) => EndpointError::with(status::BadRequest, 400),
        Err(_) => EndpointError::with(status::InternalServerError, 501),
    }
}

fn discovery(req: &mut Request, config: &Config) -> IronResult<Response> {
    info!("GET /discovery");

    let remote_ip = format!("{}", req.remote_addr.ip());

    let map = req.get_ref::<Params>().unwrap(); // TODO: don't unwrap.
    let token = map.find(&["token"]);
    if token.is_none() {
        return EndpointError::with(status::BadRequest, 400);
    }
    let token = String::from_value(token.unwrap()).unwrap();

    match config
              .domain_db
              .get_record_by_token(&token)
              .recv()
              .unwrap() {
        Ok(record) => {
            if record.public_ip.is_none() {
                return EndpointError::with(status::BadRequest, 400);
            }

            #[derive(Serialize)]
            struct Discovery {
                href: String,
                local: bool,
            }

            // We don't know the local port but we consider that it defaults
            // to the standard https one.
            // We need to remove the extra dot at the end of the name...
            let href = format!("https://{}", record.name[..record.name.len() - 1].to_owned());
            let answer = Discovery {
                href: href,
                local: record.public_ip.unwrap() == remote_ip,
            };

            let mut response = Response::with(serde_json::to_string(&answer).unwrap());
            response.headers.set(ContentType::json());
            Ok(response)
        }
        Err(DomainError::NoRecord) => EndpointError::with(status::BadRequest, 400),
        Err(_) => EndpointError::with(status::InternalServerError, 501),
    }
}

fn unsubscribe(req: &mut Request, config: &Config) -> IronResult<Response> {
    info!("GET /unsubscribe");

    let map = req.get_ref::<Params>().unwrap(); // TODO: don't unwrap.
    let token = map.find(&["token"]);
    if token.is_none() {
        return EndpointError::with(status::BadRequest, 400);
    }
    let token = String::from_value(token.unwrap()).unwrap();

    match config
              .domain_db
              .delete_record_by_token(&token)
              .recv()
              .unwrap() {
        Ok(0) => EndpointError::with(status::BadRequest, 400), // No record found for this token.
        Ok(_) => {
            let mut response = Response::new();
            response.status = Some(Status::Ok);

            Ok(response)
        }
        Err(_) => EndpointError::with(status::InternalServerError, 501),
    }
}

fn subscribe(req: &mut Request, config: &Config) -> IronResult<Response> {
    info!("GET /subscribe");

    // Extract the name parameter.
    let map = req.get_ref::<Params>().unwrap(); // TODO: don't unwrap.
    match map.find(&["name"]) {
        Some(&Value::String(ref name)) => {
            let full_name = domain_for_name(name, config);
            info!("trying to subscribe {}", full_name);

            let record = config
                .domain_db
                .get_record_by_name(&full_name)
                .recv()
                .unwrap();
            match record {
                Ok(_) => {
                    // We already have a record for this name, return an error.
                    let mut response = Response::with("{\"error\": \"UnavailableName\"}");
                    response.status = Some(Status::BadRequest);
                    response.headers.set(ContentType::json());
                    Ok(response)
                }
                Err(DomainError::NoRecord) => {
                    // Create a token, create and store a record and finally return the token.
                    let token = format!("{}", Uuid::new_v4());
                    let record = DomainRecord::new(&full_name, &token, None, None, None, 0);
                    match config.domain_db.add_record(record).recv().unwrap() {
                        Ok(()) => {
                            // We don't want the full domain name or the dns challenge in the
                            // response so we create a local struct.
                            #[derive(Serialize)]
                            struct NameAndToken {
                                name: String,
                                token: String,
                            }
                            let n_and_t = NameAndToken {
                                name: name.to_owned(),
                                token: token,
                            };
                            match serde_json::to_string(&n_and_t) {
                                Ok(serialized) => {
                                    let mut response = Response::with(serialized);
                                    response.status = Some(Status::Ok);
                                    response.headers.set(ContentType::json());

                                    Ok(response)
                                }
                                Err(_) => EndpointError::with(status::InternalServerError, 501)
                            }
                        }
                        Err(_) => EndpointError::with(status::InternalServerError, 501),
                    }
                }
                // Other error, like a db issue.
                Err(_) => EndpointError::with(status::InternalServerError, 501),
            }
        }
        // Missing `name` parameter.
        _ => EndpointError::with(status::BadRequest, 400),
    }
}

fn dnsconfig(req: &mut Request, config: &Config) -> IronResult<Response> {
    info!("GET /dnsconfig");

    // Extract the challenge and token parameter.
    let map = req.get_ref::<Params>().unwrap(); // TODO: don't unwrap.
    let challenge = map.find(&["challenge"]);
    let token = map.find(&["token"]);

    // Both parameters are mandatory.
    if challenge.is_none() || token.is_none() {
        return EndpointError::with(status::BadRequest, 400);
    }

    let challenge = String::from_value(challenge.unwrap()).unwrap();
    let token = String::from_value(token.unwrap()).unwrap();

    // Check if we have a record with this token, bail out if not.
    match config
              .domain_db
              .get_record_by_token(&token)
              .recv()
              .unwrap() {
        Ok(record) => {
            // Update the record with the challenge.
            let local_ip = match record.local_ip {
                Some(ref ip) => Some(ip.as_str()),
                None => None,
            };
            let public_ip = match record.public_ip {
                Some(ref ip) => Some(ip.as_str()),
                None => None,
            };

            let new_record = DomainRecord::new(&record.name,
                                               &record.token,
                                               Some(&challenge),
                                               local_ip,
                                               public_ip,
                                               record.timestamp);
            match config
                      .domain_db
                      .update_record(new_record)
                      .recv()
                      .unwrap() {
                Ok(()) => {
                    // Everything went fine, return an empty 200 OK for now.
                    let mut response = Response::new();
                    response.status = Some(Status::Ok);

                    Ok(response)
                }
                Err(_) => EndpointError::with(status::InternalServerError, 501),
            }
        }
        Err(DomainError::NoRecord) => EndpointError::with(status::BadRequest, 400),
        Err(_) => EndpointError::with(status::InternalServerError, 501),
    }
}

pub fn create(config: &Config) -> Router {
    let mut router = Router::new();

    macro_rules! handler {
        ($name:ident) => (
            let config_ = config.clone();
            router.get(stringify!($name),
                       move |req: &mut Request| -> IronResult<Response> {
                $name(req, &config_)
            }, stringify!($name));
        )
    }

    handler!(register);
    handler!(info);
    handler!(subscribe);
    handler!(unsubscribe);
    handler!(dnsconfig);
    handler!(discovery);

    if config.socket_path.is_none() {
        handler!(pdns);
    }

    router
}
<|endoftext|>


<commit_before>//! Licensed under the Apache License, Version 2.0
//! http://www.apache.org/licenses/LICENSE-2.0 or the MIT license
//! http://opensource.org/licenses/MIT, at your
//! option. This file may not be copied, modified, or distributed
//! except according to those terms.

use std::fmt;
use std::kinds;
use std::mem;
use std::num;

/// Similar to the slice iterator, but with a certain number of steps
/// (stride) skipped per iteration.
///
/// Does not support zero-sized `A`.
///
/// Iterator element type is `&'a A`
pub struct Stride<'a, A> {
    /// base pointer -- does not change during iteration
    begin: *const A,
    /// current offset from begin
    offset: int,
    /// offset where we end (exclusive end).
    end: int,
    stride: int,
    life: kinds::marker::ContravariantLifetime<'a>,
}

/// Stride with mutable elements
///
/// Iterator element type is `&'a mut A`
pub struct StrideMut<'a, A> {
    begin: *mut A,
    offset: int,
    end: int,
    stride: int,
    life: kinds::marker::ContravariantLifetime<'a>,
    nocopy: kinds::marker::NoCopy
}

impl<'a, A> Stride<'a, A>
{
    /// Create Stride iterator from a raw pointer.
    pub unsafe fn from_ptr_len(begin: *const A, nelem: uint, stride: int) -> Stride<'a, A>
    {
        Stride {
            begin: begin,
            offset: 0,
            end: stride * nelem as int,
            stride: stride,
            life: kinds::marker::ContravariantLifetime,
        }
    }
}

impl<'a, A> StrideMut<'a, A>
{
    /// Create Stride iterator from a raw pointer.
    pub unsafe fn from_ptr_len(begin: *mut A, nelem: uint, stride: int) -> StrideMut<'a, A>
    {
        StrideMut {
            begin: begin,
            offset: 0,
            end: stride * nelem as int,
            stride: stride,
            life: kinds::marker::ContravariantLifetime,
            nocopy: kinds::marker::NoCopy,
        }
    }
}

macro_rules! stride_impl {
    (struct $name:ident -> $slice:ty, $getptr:ident, $ptr:ty, $elem:ty) => {
        impl<'a, A> $name<'a, A>
        {
            /// Create Stride iterator from a slice and the element step count.
            ///
            /// If `step` is negative, start from the back.
            ///
            /// ## Example
            ///
            /// ```
            /// use itertools::Stride;
            ///
            /// let xs = [0i, 1, 2, 3, 4, 5];
            ///
            /// let mut front = Stride::from_slice(xs.as_slice(), 2);
            /// assert_eq!(front[0], 0);
            /// assert_eq!(front[1], 2);
            ///
            /// let mut back = Stride::from_slice(xs.as_slice(), -2);
            /// assert_eq!(back[0], 5);
            /// assert_eq!(back[1], 3);
            /// ```
            #[inline]
            pub fn from_slice(xs: $slice, step: int) -> $name<'a, A>
            {
                assert!(mem::size_of::<A>() != 0);
                let ustep = if step < 0 { -step } else { step } as uint;
                let nelem = if ustep <= 1 {
                    xs.len()
                } else {
                    let (d, r) = num::div_rem(xs.len(), ustep);
                    d + if r > 0 { 1 } else { 0 }
                };
                let mut begin = xs. $getptr ();
                unsafe {
                    if step > 0 {
                        $name::from_ptr_len(begin, nelem, step)
                    } else {
                        if nelem != 0 {
                            begin = begin.offset(xs.len() as int - 1)
                        }
                        $name::from_ptr_len(begin, nelem, step)
                    }
                }
            }

            /// Create Stride iterator from an existing Stride iterator
            #[inline]
            pub fn from_stride(mut it: $name<'a, A>, mut step: int) -> $name<'a, A>
            {
                assert!(step != 0);
                if step < 0 {
                    it.swap_ends();
                    step = -step;
                }
                let len = (it.end - it.offset) / it.stride;
                let newstride = it.stride * step;
                let (d, r) = num::div_rem(len as uint, step as uint);
                let len = d as uint + if r > 0 { 1 } else { 0 };
                unsafe {
                    $name::from_ptr_len(it.begin, len, newstride)
                }
            }

            /// Swap the begin and end and reverse the stride,
            /// in effect reversing the iterator.
            #[inline]
            pub fn swap_ends(&mut self) {
                let len = (self.end - self.offset) / self.stride;
                if len > 0 {
                    unsafe {
                        let endptr = self.begin.offset((len - 1) * self.stride);
                        *self = $name::from_ptr_len(endptr, len as uint, -self.stride);
                    }
                }
            }

            /// Return the number of elements in the iterator.
            #[inline]
            pub fn len(&self) -> uint {
                ((self.end - self.offset) / self.stride) as uint
            }
        }

        impl<'a, A> Iterator<$elem> for $name<'a, A>
        {
            #[inline]
            fn next(&mut self) -> Option<$elem>
            {
                if self.offset == self.end {
                    None
                } else {
                    unsafe {
                        let elt: $elem =
                            mem::transmute(self.begin.offset(self.offset));
                        self.offset += self.stride;
                        Some(elt)
                    }
                }
            }

            #[inline]
            fn size_hint(&self) -> (uint, Option<uint>) {
                let len = self.len();
                (len, Some(len))
            }
        }

        impl<'a, A> DoubleEndedIterator<$elem> for $name<'a, A>
        {
            #[inline]
            fn next_back(&mut self) -> Option<$elem>
            {
                if self.offset == self.end {
                    None
                } else {
                    unsafe {
                        self.end -= self.stride;
                        let elt = mem::transmute(self.begin.offset(self.end));
                        Some(elt)
                    }
                }
            }
        }

        impl<'a, A> ExactSizeIterator<$elem> for $name<'a, A> { }

        impl<'a, A> Index<uint, A> for $name<'a, A>
        {
            fn index<'b>(&'b self, i: &uint) -> &'b A
            {
                assert!(*i < self.len());
                unsafe {
                    let ptr = self.begin.offset(self.offset + self.stride * (*i as int));
                    mem::transmute(ptr)
                }
            }
        }

        impl<'a, A: fmt::Show> fmt::Show for $name<'a, A>
        {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
            {
                try!(write!(f, "["));
                for i in range(0, self.len()) {
                    if i != 0 {
                        try!(write!(f, ", "));
                    }
                    try!(write!(f, "{}", (*self)[i]));
                }
                write!(f, "]")
            }
        }
    }
}

stride_impl!{struct Stride -> &'a [A], as_ptr, *const A, &'a A}
stride_impl!{struct StrideMut -> &'a mut [A], as_mut_ptr, *mut A, &'a mut A}

impl<'a, A> Clone for Stride<'a, A>
{
    fn clone(&self) -> Stride<'a, A>
    {
        *self
    }
}

impl<'a, A> IndexMut<uint, A> for StrideMut<'a, A>
{
    fn index_mut<'b>(&'b mut self, i: &uint) -> &'b mut A
    {
        assert!(*i < self.len());
        unsafe {
            let ptr = self.begin.offset(self.offset + self.stride * (*i as int));
            mem::transmute(ptr)
        }
    }
}
<commit_msg>stride: Clean up docs<commit_after>//! Licensed under the Apache License, Version 2.0
//! http://www.apache.org/licenses/LICENSE-2.0 or the MIT license
//! http://opensource.org/licenses/MIT, at your
//! option. This file may not be copied, modified, or distributed
//! except according to those terms.

use std::fmt;
use std::kinds;
use std::mem;
use std::num;

/// Stride is similar to the slice iterator, but with a certain number of steps
/// (the stride) skipped per iteration.
///
/// Stride does not support zero-sized types for `A`.
///
/// Iterator element type is `&'a A`.
pub struct Stride<'a, A> {
    /// base pointer -- does not change during iteration
    begin: *const A,
    /// current offset from begin
    offset: int,
    /// offset where we end (exclusive end).
    end: int,
    stride: int,
    life: kinds::marker::ContravariantLifetime<'a>,
}

/// StrideMut is like Stride, but with mutable elements.
///
/// Iterator element type is `&'a mut A`.
pub struct StrideMut<'a, A> {
    begin: *mut A,
    offset: int,
    end: int,
    stride: int,
    life: kinds::marker::ContravariantLifetime<'a>,
    nocopy: kinds::marker::NoCopy
}

impl<'a, A> Stride<'a, A>
{
    /// Create a Stride iterator from a raw pointer.
    pub unsafe fn from_ptr_len(begin: *const A, nelem: uint, stride: int) -> Stride<'a, A>
    {
        Stride {
            begin: begin,
            offset: 0,
            end: stride * nelem as int,
            stride: stride,
            life: kinds::marker::ContravariantLifetime,
        }
    }
}

impl<'a, A> StrideMut<'a, A>
{
    /// Create a StrideMut iterator from a raw pointer.
    pub unsafe fn from_ptr_len(begin: *mut A, nelem: uint, stride: int) -> StrideMut<'a, A>
    {
        StrideMut {
            begin: begin,
            offset: 0,
            end: stride * nelem as int,
            stride: stride,
            life: kinds::marker::ContravariantLifetime,
            nocopy: kinds::marker::NoCopy,
        }
    }
}

macro_rules! stride_impl {
    (struct $name:ident -> $slice:ty, $getptr:ident, $ptr:ty, $elem:ty) => {
        impl<'a, A> $name<'a, A>
        {
            /// Create Stride iterator from a slice and the element step count.
            ///
            /// If `step` is negative, start from the back.
            ///
            /// ## Example
            ///
            /// ```
            /// use itertools::Stride;
            ///
            /// let xs = [0i, 1, 2, 3, 4, 5];
            ///
            /// let front = Stride::from_slice(xs.as_slice(), 2);
            /// assert_eq!(front[0], 0);
            /// assert_eq!(front[1], 2);
            ///
            /// let back = Stride::from_slice(xs.as_slice(), -2);
            /// assert_eq!(back[0], 5);
            /// assert_eq!(back[1], 3);
            /// ```
            ///
            /// **Panics** if values of type `A` are zero-sized. <br>
            /// **Panics** if `step` is 0.
            #[inline]
            pub fn from_slice(xs: $slice, step: int) -> $name<'a, A>
            {
                assert!(mem::size_of::<A>() != 0);
                let ustep = if step < 0 { -step } else { step } as uint;
                let nelem = if ustep <= 1 {
                    xs.len()
                } else {
                    let (d, r) = num::div_rem(xs.len(), ustep);
                    d + if r > 0 { 1 } else { 0 }
                };
                let mut begin = xs. $getptr ();
                unsafe {
                    if step > 0 {
                        $name::from_ptr_len(begin, nelem, step)
                    } else {
                        if nelem != 0 {
                            begin = begin.offset(xs.len() as int - 1)
                        }
                        $name::from_ptr_len(begin, nelem, step)
                    }
                }
            }

            /// Create Stride iterator from an existing Stride iterator
            ///
            /// **Panics** if `step` is 0.
            #[inline]
            pub fn from_stride(mut it: $name<'a, A>, mut step: int) -> $name<'a, A>
            {
                assert!(step != 0);
                if step < 0 {
                    it.swap_ends();
                    step = -step;
                }
                let len = (it.end - it.offset) / it.stride;
                let newstride = it.stride * step;
                let (d, r) = num::div_rem(len as uint, step as uint);
                let len = d as uint + if r > 0 { 1 } else { 0 };
                unsafe {
                    $name::from_ptr_len(it.begin, len, newstride)
                }
            }

            /// Swap the begin and end and reverse the stride,
            /// in effect reversing the iterator.
            #[inline]
            pub fn swap_ends(&mut self) {
                let len = (self.end - self.offset) / self.stride;
                if len > 0 {
                    unsafe {
                        let endptr = self.begin.offset((len - 1) * self.stride);
                        *self = $name::from_ptr_len(endptr, len as uint, -self.stride);
                    }
                }
            }

            /// Return the number of elements in the iterator.
            #[inline]
            pub fn len(&self) -> uint {
                ((self.end - self.offset) / self.stride) as uint
            }
        }

        impl<'a, A> Iterator<$elem> for $name<'a, A>
        {
            #[inline]
            fn next(&mut self) -> Option<$elem>
            {
                if self.offset == self.end {
                    None
                } else {
                    unsafe {
                        let elt: $elem =
                            mem::transmute(self.begin.offset(self.offset));
                        self.offset += self.stride;
                        Some(elt)
                    }
                }
            }

            #[inline]
            fn size_hint(&self) -> (uint, Option<uint>) {
                let len = self.len();
                (len, Some(len))
            }
        }

        impl<'a, A> DoubleEndedIterator<$elem> for $name<'a, A>
        {
            #[inline]
            fn next_back(&mut self) -> Option<$elem>
            {
                if self.offset == self.end {
                    None
                } else {
                    unsafe {
                        self.end -= self.stride;
                        let elt = mem::transmute(self.begin.offset(self.end));
                        Some(elt)
                    }
                }
            }
        }

        impl<'a, A> ExactSizeIterator<$elem> for $name<'a, A> { }

        impl<'a, A> Index<uint, A> for $name<'a, A>
        {
            /// Return a reference to the element at a given index.
            ///
            /// **Panics** if the index is out of bounds.
            fn index<'b>(&'b self, i: &uint) -> &'b A
            {
                assert!(*i < self.len());
                unsafe {
                    let ptr = self.begin.offset(self.offset + self.stride * (*i as int));
                    mem::transmute(ptr)
                }
            }
        }

        impl<'a, A: fmt::Show> fmt::Show for $name<'a, A>
        {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
            {
                try!(write!(f, "["));
                for i in range(0, self.len()) {
                    if i != 0 {
                        try!(write!(f, ", "));
                    }
                    try!(write!(f, "{}", (*self)[i]));
                }
                write!(f, "]")
            }
        }
    }
}

stride_impl!{struct Stride -> &'a [A], as_ptr, *const A, &'a A}
stride_impl!{struct StrideMut -> &'a mut [A], as_mut_ptr, *mut A, &'a mut A}

impl<'a, A> Clone for Stride<'a, A>
{
    fn clone(&self) -> Stride<'a, A>
    {
        *self
    }
}

impl<'a, A> IndexMut<uint, A> for StrideMut<'a, A>
{
    /// Return a mutable reference to the element at a given index.
    ///
    /// **Panics** if the index is out of bounds.
    fn index_mut<'b>(&'b mut self, i: &uint) -> &'b mut A
    {
        assert!(*i < self.len());
        unsafe {
            let ptr = self.begin.offset(self.offset + self.stride * (*i as int));
            mem::transmute(ptr)
        }
    }
}
<|endoftext|>


<commit_before>//! Various useful traits

use std::ops::*;

/// Convenience trait for floats.
pub trait Float:
    Copy + Radians + One + Zero + Sqrt
    + FromPrimitive
    + Min + Max + Signum
    + Trig
    + PartialEq
    + Add<Self, Output = Self>
    + Mul<Self, Output = Self>
    + Sub<Self, Output = Self>
    + Div<Self, Output = Self>
    + Rem<Self, Output = Self>
    + Neg<Output = Self>
    + Trig {}

impl<T> Float for T where
    T: Copy + Radians + One + Zero + Sqrt
    + FromPrimitive
    + Min + Max + Signum
    + Trig
    + PartialEq
    + Add<T, Output = T>
    + Mul<T, Output = T>
    + Sub<T, Output = T>
    + Div<T, Output = T>
    + Rem<T, Output = T>
    + Neg<Output = T>
    + Trig {}

/// Minimum value.
pub trait Min {
    /// Returns the minimum value of self or other.
    fn min(self, other: Self) -> Self;
}

impl Min for f32 {
    #[inline(always)]
    fn min(self, other: Self) -> Self { self.min(other) }
}

impl Min for f64 {
    #[inline(always)]
    fn min(self, other: Self) -> Self { self.min(other) }
}

/// Maximum value.
pub trait Max {
    /// Returns the maximum value of self or other.
    fn max(self, other: Self) -> Self;
}

impl Max for f32 {
    #[inline(always)]
    fn max(self, other: Self) -> Self { self.max(other) }
}

impl Max for f64 {
    #[inline(always)]
    fn max(self, other: Self) -> Self { self.max(other) }
}

/// The sign of the number.
pub trait Signum {
    /// Returns number representing the sign of self
    fn signum(self) -> Self;
}

impl Signum for f32 {
    #[inline(always)]
    fn signum(self) -> Self { self.signum() }
}

impl Signum for f64 {
    #[inline(always)]
    fn signum(self) -> Self { self.signum() }
}

/// Useful constants for radians.
pub trait Radians {
    /// Returns radians corresponding to 90 degrees.
    fn _90() -> Self;

    /// Returns radians corresponding to 180 degrees.
    fn _180() -> Self;

    /// Returns radians corresponding to 360 degrees.
    fn _360() -> Self;

    /// Convert a value to radians from degrees.
    /// Equivalent to ```value * (π / 180)```.
    fn deg_to_rad(self) -> Self;

    /// Convert a value to degrees from radians.
    /// Equivalent to ```value * (180 / π)```.
    fn rad_to_deg(self) -> Self;
}

impl Radians for f32 {
    #[inline(always)]
    fn _90() -> f32 {
        ::std::f32::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f32 {
        ::std::f32::consts::PI
    }

    #[inline(always)]
    fn _360() -> f32 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(self) -> Self {
        self * (::std::f32::consts::PI / 180.0f32)
    }

    #[inline(always)]
    fn rad_to_deg(self) -> Self {
        self * (180.0f32 / ::std::f32::consts::PI)
    }
}

impl Radians for f64 {
    #[inline(always)]
    fn _90() -> f64 {
        ::std::f64::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f64 {
        ::std::f64::consts::PI
    }

    #[inline(always)]
    fn _360() -> f64 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(self) -> Self {
        self * (::std::f64::consts::PI / 180.0f64)
    }

    #[inline(always)]
    fn rad_to_deg(self) -> Self {
        self * (180.0f64 / ::std::f64::consts::PI)
    }
}

/// Number 1.
pub trait One {
    /// Returns 1.
    fn one() -> Self;
}

/// Number 0.
pub trait Zero {
    /// Returns 0.
    fn zero() -> Self;
}

impl One for f32 {
    #[inline(always)]
    fn one() -> f32 { 1.0 }
}

impl One for f64 {
    #[inline(always)]
    fn one() -> f64 { 1.0 }
}

impl Zero for f32 {
    #[inline(always)]
    fn zero() -> f32 { 0.0 }
}

impl Zero for f64 {
    #[inline(always)]
    fn zero() -> f64 { 0.0 }
}

/// Square root.
pub trait Sqrt {
    /// Returns square root.
    fn sqrt(self) -> Self;
}

impl Sqrt for f32 {
    #[inline(always)]
    fn sqrt(self) -> f32 { self.sqrt() }
}

impl Sqrt for f64 {
    #[inline(always)]
    fn sqrt(self) -> f64 { self.sqrt() }
}

/// Basic trigonometry functions
pub trait Trig {
    /// Returns sine of self
    fn sin(self) -> Self;
    /// Returns cosine of self
    fn cos(self) -> Self;
    /// Returns tangent of self
    fn tan(self) -> Self;
}

impl Trig for f32 {
    #[inline(always)]
    fn sin(self) -> f32 { self.sin() }

    #[inline(always)]
    fn cos(self) -> f32 { self.cos() }

    #[inline(always)]
    fn tan(self) -> f32 { self.tan() }
}

impl Trig for f64 {
    #[inline(always)]
    fn sin(self) -> f64 { self.sin() }

    #[inline(always)]
    fn cos(self) -> f64 { self.cos() }

    #[inline(always)]
    fn tan(self) -> f64 { self.tan() }
}

/// Casts into another type.
pub trait Cast<T> {
    /// Casts into other type.
    fn cast(self) -> T;
}

impl Cast<f32> for f64 {
    #[inline(always)]
    fn cast(self) -> f32 { self as f32 }
}

impl Cast<f64> for f32 {
    #[inline(always)]
    fn cast(self) -> f64 { self as f64 }
}

impl Cast<f32> for f32 {
    #[inline(always)]
    fn cast(self) -> f32 { self }
}

impl Cast<f64> for f64 {
    #[inline(always)]
    fn cast(self) -> f64 { self }
}

/// Trait for converting from different numeric types
pub trait FromPrimitive {
    /// from a f64
    fn from_f64(t: f64) -> Self;
    /// from a f32
    fn from_f32(t: f32) -> Self;
    /// from a isze
    fn from_isize(t: isize) -> Self;
    // Add more as needed..
}

impl FromPrimitive for f64 {
    fn from_f64(t: f64) -> Self { t }
    fn from_f32(t: f32) -> Self { t as f64 }
    fn from_isize(t: isize) -> Self { t as f64 }
}

impl FromPrimitive for f32 {
    fn from_f64(t: f64) -> Self { t as f32 }
    fn from_f32(t: f32) -> Self { t }
    fn from_isize(t: isize) -> Self { t as f32 }
}

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

    #[test]
    fn test_f32_sqrt() {
        let a = 4.0f32;
        let b = <f32 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f32);
    }

    #[test]
    fn test_f64_sqrt() {
        let a = 4.0f64;
        let b = <f64 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f64);
    }

    #[test]
    fn test_f32_deg_to_rad() {
        let degrees = 23.0f32;
        let radians = degrees.deg_to_rad();
        assert!(f32::abs_sub(radians, 0.401425) > ::std::f32::EPSILON);
    }

    #[test]
    fn test_f64_deg_to_rad() {
        let degrees = 60.0f64;
        let radians = degrees.deg_to_rad();
        assert!(f64::abs_sub(radians, 1.047197)  > ::std::f64::EPSILON);
    }
}
<commit_msg>Added PartialOrd and inverse trig functions to Float trait<commit_after>//! Various useful traits

use std::ops::*;

/// Convenience trait for floats.
pub trait Float:
    Copy + Radians + One + Zero + Sqrt
    + FromPrimitive
    + Min + Max + Signum
    + Trig
    + PartialEq
    + PartialOrd
    + Add<Self, Output = Self>
    + Mul<Self, Output = Self>
    + Sub<Self, Output = Self>
    + Div<Self, Output = Self>
    + Rem<Self, Output = Self>
    + Neg<Output = Self>
    + Trig {}

impl<T> Float for T where
    T: Copy + Radians + One + Zero + Sqrt
    + FromPrimitive
    + Min + Max + Signum
    + Trig
    + PartialEq
    + PartialOrd
    + Add<T, Output = T>
    + Mul<T, Output = T>
    + Sub<T, Output = T>
    + Div<T, Output = T>
    + Rem<T, Output = T>
    + Neg<Output = T>
    + Trig {}

/// Minimum value.
pub trait Min {
    /// Returns the minimum value of self or other.
    fn min(self, other: Self) -> Self;
}

impl Min for f32 {
    #[inline(always)]
    fn min(self, other: Self) -> Self { self.min(other) }
}

impl Min for f64 {
    #[inline(always)]
    fn min(self, other: Self) -> Self { self.min(other) }
}

/// Maximum value.
pub trait Max {
    /// Returns the maximum value of self or other.
    fn max(self, other: Self) -> Self;
}

impl Max for f32 {
    #[inline(always)]
    fn max(self, other: Self) -> Self { self.max(other) }
}

impl Max for f64 {
    #[inline(always)]
    fn max(self, other: Self) -> Self { self.max(other) }
}

/// The sign of the number.
pub trait Signum {
    /// Returns number representing the sign of self
    fn signum(self) -> Self;
}

impl Signum for f32 {
    #[inline(always)]
    fn signum(self) -> Self { self.signum() }
}

impl Signum for f64 {
    #[inline(always)]
    fn signum(self) -> Self { self.signum() }
}

/// Useful constants for radians.
pub trait Radians {
    /// Returns radians corresponding to 90 degrees.
    fn _90() -> Self;

    /// Returns radians corresponding to 180 degrees.
    fn _180() -> Self;

    /// Returns radians corresponding to 360 degrees.
    fn _360() -> Self;

    /// Convert a value to radians from degrees.
    /// Equivalent to ```value * (π / 180)```.
    fn deg_to_rad(self) -> Self;

    /// Convert a value to degrees from radians.
    /// Equivalent to ```value * (180 / π)```.
    fn rad_to_deg(self) -> Self;
}

impl Radians for f32 {
    #[inline(always)]
    fn _90() -> f32 {
        ::std::f32::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f32 {
        ::std::f32::consts::PI
    }

    #[inline(always)]
    fn _360() -> f32 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(self) -> Self {
        self * (::std::f32::consts::PI / 180.0f32)
    }

    #[inline(always)]
    fn rad_to_deg(self) -> Self {
        self * (180.0f32 / ::std::f32::consts::PI)
    }
}

impl Radians for f64 {
    #[inline(always)]
    fn _90() -> f64 {
        ::std::f64::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f64 {
        ::std::f64::consts::PI
    }

    #[inline(always)]
    fn _360() -> f64 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(self) -> Self {
        self * (::std::f64::consts::PI / 180.0f64)
    }

    #[inline(always)]
    fn rad_to_deg(self) -> Self {
        self * (180.0f64 / ::std::f64::consts::PI)
    }
}

/// Number 1.
pub trait One {
    /// Returns 1.
    fn one() -> Self;
}

/// Number 0.
pub trait Zero {
    /// Returns 0.
    fn zero() -> Self;
}

impl One for f32 {
    #[inline(always)]
    fn one() -> f32 { 1.0 }
}

impl One for f64 {
    #[inline(always)]
    fn one() -> f64 { 1.0 }
}

impl Zero for f32 {
    #[inline(always)]
    fn zero() -> f32 { 0.0 }
}

impl Zero for f64 {
    #[inline(always)]
    fn zero() -> f64 { 0.0 }
}

/// Square root.
pub trait Sqrt {
    /// Returns square root.
    fn sqrt(self) -> Self;
}

impl Sqrt for f32 {
    #[inline(always)]
    fn sqrt(self) -> f32 { self.sqrt() }
}

impl Sqrt for f64 {
    #[inline(always)]
    fn sqrt(self) -> f64 { self.sqrt() }
}

/// Basic trigonometry functions
pub trait Trig {
    /// Returns sine of self
    fn sin(self) -> Self;
    /// Returns cosine of self
    fn cos(self) -> Self;
    /// Returns tangent of self
    fn tan(self) -> Self;
    /// Returns inverse sine of self
    fn asin(self) -> Self;
    /// Returns inverse cosine of self
    fn acos(self) -> Self;
    /// Returns inverse tangent of self
    fn atan(self) -> Self;
}

impl Trig for f32 {
    #[inline(always)]
    fn sin(self) -> f32 { self.sin() }

    #[inline(always)]
    fn cos(self) -> f32 { self.cos() }

    #[inline(always)]
    fn tan(self) -> f32 { self.tan() }

    #[inline(always)]
    fn asin(self) -> f32 { self.asin() }

    #[inline(always)]
    fn acos(self) -> f32 { self.acos() }

    #[inline(always)]
    fn atan(self) -> f32 { self.atan() }
}

impl Trig for f64 {
    #[inline(always)]
    fn sin(self) -> f64 { self.sin() }

    #[inline(always)]
    fn cos(self) -> f64 { self.cos() }

    #[inline(always)]
    fn tan(self) -> f64 { self.tan() }

    #[inline(always)]
    fn asin(self) -> f64 { self.asin() }

    #[inline(always)]
    fn acos(self) -> f64 { self.acos() }

    #[inline(always)]
    fn atan(self) -> f64 { self.atan() }
}

/// Casts into another type.
pub trait Cast<T> {
    /// Casts into other type.
    fn cast(self) -> T;
}

impl Cast<f32> for f64 {
    #[inline(always)]
    fn cast(self) -> f32 { self as f32 }
}

impl Cast<f64> for f32 {
    #[inline(always)]
    fn cast(self) -> f64 { self as f64 }
}

impl Cast<f32> for f32 {
    #[inline(always)]
    fn cast(self) -> f32 { self }
}

impl Cast<f64> for f64 {
    #[inline(always)]
    fn cast(self) -> f64 { self }
}

/// Trait for converting from different numeric types
pub trait FromPrimitive {
    /// from a f64
    fn from_f64(t: f64) -> Self;
    /// from a f32
    fn from_f32(t: f32) -> Self;
    /// from a isze
    fn from_isize(t: isize) -> Self;
    // Add more as needed..
}

impl FromPrimitive for f64 {
    fn from_f64(t: f64) -> Self { t }
    fn from_f32(t: f32) -> Self { t as f64 }
    fn from_isize(t: isize) -> Self { t as f64 }
}

impl FromPrimitive for f32 {
    fn from_f64(t: f64) -> Self { t as f32 }
    fn from_f32(t: f32) -> Self { t }
    fn from_isize(t: isize) -> Self { t as f32 }
}

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

    #[test]
    fn test_f32_sqrt() {
        let a = 4.0f32;
        let b = <f32 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f32);
    }

    #[test]
    fn test_f64_sqrt() {
        let a = 4.0f64;
        let b = <f64 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f64);
    }

    #[test]
    fn test_f32_deg_to_rad() {
        let degrees = 23.0f32;
        let radians = degrees.deg_to_rad();
        assert!(f32::abs_sub(radians, 0.401425) > ::std::f32::EPSILON);
    }

    #[test]
    fn test_f64_deg_to_rad() {
        let degrees = 60.0f64;
        let radians = degrees.deg_to_rad();
        assert!(f64::abs_sub(radians, 1.047197)  > ::std::f64::EPSILON);
    }
}
<|endoftext|>