<commit_before>//! HTTP/HTTPS URL type for Iron.

use url::{self, Host};
use std::fmt;

/// HTTP/HTTPS URL type for Iron.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Url {
    /// The generic rust-url that corresponds to this Url
    generic_url: url::Url,
}

impl Url {
    /// Create a URL from a string.
    ///
    /// The input must be a valid URL with a special scheme for this to succeed.
    ///
    /// HTTP and HTTPS are special schemes.
    ///
    /// See: http://url.spec.whatwg.org/#special-scheme
    pub fn parse(input: &str) -> Result<Url, String> {
        // Parse the string using rust-url, then convert.
        match url::Url::parse(input) {
            Ok(raw_url) => Url::from_generic_url(raw_url),
            Err(e) => Err(format!("{}", e))
        }
    }

    /// Create a `Url` from a `rust-url` `Url`.
    pub fn from_generic_url(raw_url: url::Url) -> Result<Url, String> {
        // Create an Iron URL by verifying the `rust-url` `Url` is a special
        // scheme that Iron supports.
        if raw_url.cannot_be_a_base() {
            Err(format!("Not a special scheme: `{}`", raw_url.scheme()))
        } else if raw_url.port_or_known_default().is_none() {
            Err(format!("Invalid special scheme: `{}`", raw_url.scheme()))
        } else {
            Ok(Url {
                generic_url: raw_url,
            })
        }
    }

    /// Create a `rust-url` `Url` from a `Url`.
    pub fn into_generic_url(self) -> url::Url {
        self.generic_url
    }

    /// The lower-cased scheme of the URL, typically "http" or "https".
    pub fn scheme(&self) -> String {
        self.generic_url.scheme().to_string()
    }

    /// The host field of the URL, probably a domain.
    pub fn host(&self) -> Host {
        // `unwrap` is safe here because urls that cannot be a base don't have a host
        self.generic_url.host().unwrap().to_owned()
    }

    /// The connection port.
    pub fn port(&self) -> u16 {
        // `unwrap` is safe here because we checked `port_or_known_default`
        // in `from_generic_url`.
        self.generic_url.port_or_known_default().unwrap()
    }

    /// The URL path, the resource to be accessed.
    ///
    /// A *non-empty* vector encoding the parts of the URL path.
    /// Empty entries of `""` correspond to trailing slashes.
    pub fn path(&self) -> Vec<String> {
        // `unwrap` is safe here because urls that can be a base will have `Some`.
        self.generic_url.path_segments().unwrap().map(str::to_string).collect()
    }

    /// The URL username field, from the userinfo section of the URL.
    ///
    /// `None` if the `@` character was not part of the input OR
    /// if a blank username was provided.
    /// Otherwise, a non-empty string.
    pub fn username(&self) -> Option<String> {
        // Map empty usernames to None.
        match self.generic_url.username() {
            "" => None,
            username => Some(username.to_string())
        }
    }

    /// The URL password field, from the userinfo section of the URL.
    ///
    /// `None` if the `@` character was not part of the input OR
    /// if a blank password was provided.
    /// Otherwise, a non-empty string.
    pub fn password(&self) -> Option<String> {
        // Map empty passwords to None.
        match self.generic_url.password() {
            None => None,
            Some(ref x) if x.is_empty() => None,
            Some(password) => Some(password.to_string())
        }
    }

    /// The URL query string.
    ///
    /// `None` if the `?` character was not part of the input.
    /// Otherwise, a possibly empty, percent encoded string.
    pub fn query(&self) -> Option<String> {
        self.generic_url.query().map(str::to_string)
    }

    /// The URL fragment.
    ///
    /// `None` if the `#` character was not part of the input.
    /// Otherwise, a possibly empty, percent encoded string.
    pub fn fragment(&self) -> Option<String> {
        self.generic_url.fragment().map(str::to_string)
    }
}

impl fmt::Display for Url {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        try!(self.generic_url.fmt(formatter));
        Ok(())
    }
}

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

    #[test]
    fn test_default_port() {
        assert_eq!(Url::parse("http://example.com/wow").unwrap().port(), 80u16);
        assert_eq!(Url::parse("https://example.com/wow").unwrap().port(), 443u16);
    }

    #[test]
    fn test_explicit_port() {
        assert_eq!(Url::parse("http://localhost:3097").unwrap().port(), 3097u16);
    }

    #[test]
    fn test_empty_username() {
        assert!(Url::parse("http://@example.com").unwrap().username().is_none());
        assert!(Url::parse("http://:password@example.com").unwrap().username().is_none());
    }

    #[test]
    fn test_not_empty_username() {
        let user = Url::parse("http://john:pass@example.com").unwrap().username();
        assert_eq!(user.unwrap(), "john");

        let user = Url::parse("http://john:@example.com").unwrap().username();
        assert_eq!(user.unwrap(), "john");
    }

    #[test]
    fn test_empty_password() {
        assert!(Url::parse("http://michael@example.com").unwrap().password().is_none());
        assert!(Url::parse("http://:@example.com").unwrap().password().is_none());
    }

    #[test]
    fn test_not_empty_password() {
        let pass = Url::parse("http://michael:pass@example.com").unwrap().password();
        assert_eq!(pass.unwrap(), "pass");

        let pass = Url::parse("http://:pass@example.com").unwrap().password();
        assert_eq!(pass.unwrap(), "pass");
    }

    #[test]
    fn test_formatting() {
        assert_eq!(Url::parse("http://michael@example.com/path/?q=wow").unwrap().to_string(),
                    "http://michael@example.com/path/?q=wow".to_string());
    }

    #[test]
    fn test_conversion() {
        let url_str = "https://user:password@iron.com:8080/path?q=wow#fragment";
        let url = Url::parse(url_str).unwrap();

        // Convert to a generic URL and check fidelity.
        let raw_url = url.clone().into_generic_url();
        assert_eq!(::url::Url::parse(url_str).unwrap(), raw_url);

        // Convert back to an Iron URL and check fidelity.
        let new_url = Url::from_generic_url(raw_url).unwrap();
        assert_eq!(url, new_url);
    }

    #[test]
    fn test_https_non_default_port() {
        let parsed = Url::parse("https://example.com:8080").unwrap().to_string();
        assert_eq!(parsed, "https://example.com:8080/");
    }

    #[test]
    fn test_https_default_port() {
        let parsed = Url::parse("https://example.com:443").unwrap().to_string();
        assert_eq!(parsed, "https://example.com/");
    }
}
<commit_msg>Hand out borrowed types to Url pieces<commit_after>//! HTTP/HTTPS URL type for Iron.

use url::{self, Host};
use std::fmt;

/// HTTP/HTTPS URL type for Iron.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Url {
    /// The generic rust-url that corresponds to this Url
    generic_url: url::Url,
}

impl Url {
    /// Create a URL from a string.
    ///
    /// The input must be a valid URL with a special scheme for this to succeed.
    ///
    /// HTTP and HTTPS are special schemes.
    ///
    /// See: http://url.spec.whatwg.org/#special-scheme
    pub fn parse(input: &str) -> Result<Url, String> {
        // Parse the string using rust-url, then convert.
        match url::Url::parse(input) {
            Ok(raw_url) => Url::from_generic_url(raw_url),
            Err(e) => Err(format!("{}", e))
        }
    }

    /// Create a `Url` from a `rust-url` `Url`.
    pub fn from_generic_url(raw_url: url::Url) -> Result<Url, String> {
        // Create an Iron URL by verifying the `rust-url` `Url` is a special
        // scheme that Iron supports.
        if raw_url.cannot_be_a_base() {
            Err(format!("Not a special scheme: `{}`", raw_url.scheme()))
        } else if raw_url.port_or_known_default().is_none() {
            Err(format!("Invalid special scheme: `{}`", raw_url.scheme()))
        } else {
            Ok(Url {
                generic_url: raw_url,
            })
        }
    }

    /// Create a `rust-url` `Url` from a `Url`.
    pub fn into_generic_url(self) -> url::Url {
        self.generic_url
    }

    /// The lower-cased scheme of the URL, typically "http" or "https".
    pub fn scheme(&self) -> &str {
        self.generic_url.scheme()
    }

    /// The host field of the URL, probably a domain.
    pub fn host(&self) -> Host<&str> {
        // `unwrap` is safe here because urls that cannot be a base don't have a host
        self.generic_url.host().unwrap()
    }

    /// The connection port.
    pub fn port(&self) -> u16 {
        // `unwrap` is safe here because we checked `port_or_known_default`
        // in `from_generic_url`.
        self.generic_url.port_or_known_default().unwrap()
    }

    /// The URL path, the resource to be accessed.
    ///
    /// A *non-empty* vector encoding the parts of the URL path.
    /// Empty entries of `""` correspond to trailing slashes.
    pub fn path(&self) -> Vec<&str> {
        // `unwrap` is safe here because urls that can be a base will have `Some`.
        self.generic_url.path_segments().unwrap().collect()
    }

    /// The URL username field, from the userinfo section of the URL.
    ///
    /// `None` if the `@` character was not part of the input OR
    /// if a blank username was provided.
    /// Otherwise, a non-empty string.
    pub fn username(&self) -> Option<&str> {
        // Map empty usernames to None.
        match self.generic_url.username() {
            "" => None,
            username => Some(username)
        }
    }

    /// The URL password field, from the userinfo section of the URL.
    ///
    /// `None` if the `@` character was not part of the input OR
    /// if a blank password was provided.
    /// Otherwise, a non-empty string.
    pub fn password(&self) -> Option<&str> {
        // Map empty passwords to None.
        match self.generic_url.password() {
            None => None,
            Some(ref x) if x.is_empty() => None,
            Some(password) => Some(password)
        }
    }

    /// The URL query string.
    ///
    /// `None` if the `?` character was not part of the input.
    /// Otherwise, a possibly empty, percent encoded string.
    pub fn query(&self) -> Option<&str> {
        self.generic_url.query()
    }

    /// The URL fragment.
    ///
    /// `None` if the `#` character was not part of the input.
    /// Otherwise, a possibly empty, percent encoded string.
    pub fn fragment(&self) -> Option<&str> {
        self.generic_url.fragment()
    }
}

impl fmt::Display for Url {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        try!(self.generic_url.fmt(formatter));
        Ok(())
    }
}

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

    #[test]
    fn test_default_port() {
        assert_eq!(Url::parse("http://example.com/wow").unwrap().port(), 80u16);
        assert_eq!(Url::parse("https://example.com/wow").unwrap().port(), 443u16);
    }

    #[test]
    fn test_explicit_port() {
        assert_eq!(Url::parse("http://localhost:3097").unwrap().port(), 3097u16);
    }

    #[test]
    fn test_empty_username() {
        assert!(Url::parse("http://@example.com").unwrap().username().is_none());
        assert!(Url::parse("http://:password@example.com").unwrap().username().is_none());
    }

    #[test]
    fn test_not_empty_username() {
        let url = Url::parse("http://john:pass@example.com").unwrap();
        assert_eq!(url.username().unwrap(), "john");

        let url = Url::parse("http://john:@example.com").unwrap();
        assert_eq!(url.username().unwrap(), "john");
    }

    #[test]
    fn test_empty_password() {
        assert!(Url::parse("http://michael@example.com").unwrap().password().is_none());
        assert!(Url::parse("http://:@example.com").unwrap().password().is_none());
    }

    #[test]
    fn test_not_empty_password() {
        let url = Url::parse("http://michael:pass@example.com").unwrap();
        assert_eq!(url.password().unwrap(), "pass");

        let url = Url::parse("http://:pass@example.com").unwrap();
        assert_eq!(url.password().unwrap(), "pass");
    }

    #[test]
    fn test_formatting() {
        assert_eq!(Url::parse("http://michael@example.com/path/?q=wow").unwrap().to_string(),
                    "http://michael@example.com/path/?q=wow".to_string());
    }

    #[test]
    fn test_conversion() {
        let url_str = "https://user:password@iron.com:8080/path?q=wow#fragment";
        let url = Url::parse(url_str).unwrap();

        // Convert to a generic URL and check fidelity.
        let raw_url = url.clone().into_generic_url();
        assert_eq!(::url::Url::parse(url_str).unwrap(), raw_url);

        // Convert back to an Iron URL and check fidelity.
        let new_url = Url::from_generic_url(raw_url).unwrap();
        assert_eq!(url, new_url);
    }

    #[test]
    fn test_https_non_default_port() {
        let parsed = Url::parse("https://example.com:8080").unwrap().to_string();
        assert_eq!(parsed, "https://example.com:8080/");
    }

    #[test]
    fn test_https_default_port() {
        let parsed = Url::parse("https://example.com:443").unwrap().to_string();
        assert_eq!(parsed, "https://example.com/");
    }
}
<|endoftext|>


<commit_before>/*!
Library for reading/writing Labeled Tab-Separated Values

# Example

~~~~~~~~~~~~~~~~~~~~~~
extern mod ltsv;
use ltsv::LTSVWriter;
use ltsv::LTSVReader;

fn main() {
    let infile = io::file_reader(&Path("path/fo/file.tlsv")).get();
    for infile.read_ltsv().each |record| {
        for record.each |&(label, value)| {
            io::println(fmt!("label: %s, value: %s", *label, *value));
        }
    }
}
~~~~~~~~~~~~~~~~~~~~~~
*/
#[link(name = "ltsv",
       vers = "0.1",
       uuid = "E0EA0251-E165-4612-919F-38E89ACECBE9",
       url  = "https://github.com/tychosci/rust-ltsv/")];

#[comment = "Library for reading/writing Labeled Tab-Separated Values"];
#[license = "MIT license"];
#[crate_type = "lib"];

use core::container::Map;
use core::hashmap::linear::LinearMap;
use io::WriterUtil;

pub type Record = LinearMap<~str, ~str>;

enum Trailing { EOF, NL, TAB }

enum ParseType {
    Record,
    Field,
    FieldLabel,
    FieldValue(Trailing)
}

enum ParseResult<T> {
    ParseError(~str),
    ParseOk(ParseType, T)
}

pub trait LTSVWriter {
    fn write_ltsv(&self, ltsv: &[Record]);
    fn write_ltsv_record(&self, record: &Record);
}

pub trait LTSVReader {
    fn read_ltsv(&self) -> ~[Record];
    fn read_ltsv_record(&self) -> Record;
}

pub impl<T: io::Writer> LTSVWriter for T {
    fn write_ltsv(&self, ltsv: &[Record]) {
        for ltsv.each |record| {
            self.write_ltsv_record(record);
            self.write_char('\n');
        }
    }
    fn write_ltsv_record(&self, record: &Record) {
        let mut is_first = true;
        for record.each |&(k, v)| {
            if !is_first { self.write_char('\t'); }
            self.write_str(fmt!("%s:%s", *k, *v));
            if is_first { is_first = false; }
        }
    }
}

pub impl<T: io::Reader> LTSVReader for T {
    fn read_ltsv(&self) -> ~[Record] {
        let mut parser = LTSVParser::new(self);
        match parser.parse_records() {
            ParseOk(_, records) => records,
            ParseError(reason) => die!(reason)
        }
    }
    fn read_ltsv_record(&self) -> Record {
        let mut parser = LTSVParser::new(self);
        match parser.parse_fields() {
            ParseOk(_, record) => record,
            ParseError(reason) => die!(reason)
        }
    }
}

struct LTSVParser<T> {
    priv rd: &T,
    priv cur: int
}

impl<T: io::Reader> LTSVParser<T> {
    static fn new(rd: &r/T) -> LTSVParser/&r<T> {
        let cur = rd.read_byte();
        LTSVParser { rd: rd, cur: cur }
    }

    fn bump(&mut self) {
        if self.cur != -1 {
            self.cur = self.rd.read_byte();
        }
    }

    fn parse_records(&mut self) -> ParseResult<~[Record]> {
        let mut records = ~[];
        loop {
            match self.parse_fields() {
                ParseOk(_, record) => {
                    records.push(record);
                    if self.cur == -1 { break; }
                }
                ParseError(reason) => {
                    return ParseError(reason);
                }
            }
        }
        ParseOk(Record, records)
    }

    fn parse_fields(&mut self) -> ParseResult<Record> {
        let mut record = LinearMap::new();
        self.skip_whitespaces();
        loop {
            let label = match self.parse_field_label() {
                ParseOk(_, label)  => { self.bump(); label },
                ParseError(reason) => return ParseError(reason)
            };
            match self.parse_field_value() {
                ParseOk(FieldValue(TAB), value) => {
                    self.bump();
                    self.skip_whitespaces();
                    record.insert(label, value);
                }
                ParseOk(_, value) => {
                    self.bump();
                    self.skip_whitespaces();
                    record.insert(label, value);
                    return ParseOk(Field, record);
                }
                ParseError(reason) => {
                    return ParseError(reason);
                }
            }
        }
    }

    fn parse_field_label(&mut self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match self.cur {
                0x30..0x39 | 0x41..0x5a | 0x61..0x7a | 0x5f |
                0x2e | 0x2d => bytes.push(self.cur as u8),
                0x3a if bytes.len() == 0 => return ParseError(~"label is empty"),
                0x3a => return ParseOk(FieldLabel, str::from_bytes(bytes)),
                -1   => return ParseError(~"EOF while parsing field label"),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    fn parse_field_value(&mut self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match self.cur {
                0x01..0x08 | 0x0b | 0x0c |
                0x0e..0xff => bytes.push(self.cur as u8),
                0x0d => return self.consume_foward_LF(str::from_bytes(bytes)),
                0x0a => return ParseOk(FieldValue(NL), str::from_bytes(bytes)),
                0x09 => return ParseOk(FieldValue(TAB), str::from_bytes(bytes)),
                -1   => return ParseOk(FieldValue(EOF), str::from_bytes(bytes)),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    fn consume_forward_LF(&mut self, rv: ~str) -> ParseResult<~str> {
        self.bump();
        if self.cur != 0x0a {
            ParseError(~"CR detected, but not provided with LF")
        } else {
            ParseOk(FieldValue(NL), rv)
        }
    }

    fn skip_whitespaces(&mut self) {
        while char::is_whitespace(self.cur as char) {
            self.bump();
        }
    }
}

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

    #[test]
    fn test_parse_simple() {
        let records = io::with_str_reader(~"a:1\tb:2", |rd| rd.read_ltsv());
        assert records.len() == 1;
    }

    #[test]
    fn test_parse_full() {
        let s = io::with_str_writer(|wr| {
            // genzairyou
            wr.write_str(fmt!("%s:%s\t", "tofu", "豆"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "魚"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "海藻"));
            // konomi
            wr.write_str(fmt!("%s:%s\t", "tofu", "好き"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "普通"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "苦手"));
        });
        let records = io::with_str_reader(s, |rd| rd.read_ltsv());
        assert records.len() == 2;
    }

    #[test]
    fn test_parse_ltsv_trailing_nl_and_write() {
        let s = io::with_str_writer(|wr| {
            wr.write_str(fmt!("%s:%s\t", "neko", "yes"));
            wr.write_str(fmt!("%s:%s\t", "inu", "yes"));
            wr.write_str(fmt!("%s:%s\n", "tori", "yes"));
        });
        let records_1 = io::with_str_reader(s, |rd| rd.read_ltsv());
        let s2 = io::with_str_writer(|wr| wr.write_ltsv(records_1));
        let records_2 = io::with_str_reader(s2, |rd| rd.read_ltsv());
        assert records_1 == records_2;
    }
}
<commit_msg>Fix typo<commit_after>/*!
Library for reading/writing Labeled Tab-Separated Values

# Example

~~~~~~~~~~~~~~~~~~~~~~
extern mod ltsv;
use ltsv::LTSVWriter;
use ltsv::LTSVReader;

fn main() {
    let infile = io::file_reader(&Path("path/fo/file.tlsv")).get();
    for infile.read_ltsv().each |record| {
        for record.each |&(label, value)| {
            io::println(fmt!("label: %s, value: %s", *label, *value));
        }
    }
}
~~~~~~~~~~~~~~~~~~~~~~
*/
#[link(name = "ltsv",
       vers = "0.1",
       uuid = "E0EA0251-E165-4612-919F-38E89ACECBE9",
       url  = "https://github.com/tychosci/rust-ltsv/")];

#[comment = "Library for reading/writing Labeled Tab-Separated Values"];
#[license = "MIT license"];
#[crate_type = "lib"];

use core::container::Map;
use core::hashmap::linear::LinearMap;
use io::WriterUtil;

pub type Record = LinearMap<~str, ~str>;

enum Trailing { EOF, NL, TAB }

enum ParseType {
    Record,
    Field,
    FieldLabel,
    FieldValue(Trailing)
}

enum ParseResult<T> {
    ParseError(~str),
    ParseOk(ParseType, T)
}

pub trait LTSVWriter {
    fn write_ltsv(&self, ltsv: &[Record]);
    fn write_ltsv_record(&self, record: &Record);
}

pub trait LTSVReader {
    fn read_ltsv(&self) -> ~[Record];
    fn read_ltsv_record(&self) -> Record;
}

pub impl<T: io::Writer> LTSVWriter for T {
    fn write_ltsv(&self, ltsv: &[Record]) {
        for ltsv.each |record| {
            self.write_ltsv_record(record);
            self.write_char('\n');
        }
    }
    fn write_ltsv_record(&self, record: &Record) {
        let mut is_first = true;
        for record.each |&(k, v)| {
            if !is_first { self.write_char('\t'); }
            self.write_str(fmt!("%s:%s", *k, *v));
            if is_first { is_first = false; }
        }
    }
}

pub impl<T: io::Reader> LTSVReader for T {
    fn read_ltsv(&self) -> ~[Record] {
        let mut parser = LTSVParser::new(self);
        match parser.parse_records() {
            ParseOk(_, records) => records,
            ParseError(reason) => die!(reason)
        }
    }
    fn read_ltsv_record(&self) -> Record {
        let mut parser = LTSVParser::new(self);
        match parser.parse_fields() {
            ParseOk(_, record) => record,
            ParseError(reason) => die!(reason)
        }
    }
}

struct LTSVParser<T> {
    priv rd: &T,
    priv cur: int
}

impl<T: io::Reader> LTSVParser<T> {
    static fn new(rd: &r/T) -> LTSVParser/&r<T> {
        let cur = rd.read_byte();
        LTSVParser { rd: rd, cur: cur }
    }

    fn bump(&mut self) {
        if self.cur != -1 {
            self.cur = self.rd.read_byte();
        }
    }

    fn parse_records(&mut self) -> ParseResult<~[Record]> {
        let mut records = ~[];
        loop {
            match self.parse_fields() {
                ParseOk(_, record) => {
                    records.push(record);
                    if self.cur == -1 { break; }
                }
                ParseError(reason) => {
                    return ParseError(reason);
                }
            }
        }
        ParseOk(Record, records)
    }

    fn parse_fields(&mut self) -> ParseResult<Record> {
        let mut record = LinearMap::new();
        self.skip_whitespaces();
        loop {
            let label = match self.parse_field_label() {
                ParseOk(_, label)  => { self.bump(); label },
                ParseError(reason) => return ParseError(reason)
            };
            match self.parse_field_value() {
                ParseOk(FieldValue(TAB), value) => {
                    self.bump();
                    self.skip_whitespaces();
                    record.insert(label, value);
                }
                ParseOk(_, value) => {
                    self.bump();
                    self.skip_whitespaces();
                    record.insert(label, value);
                    return ParseOk(Field, record);
                }
                ParseError(reason) => {
                    return ParseError(reason);
                }
            }
        }
    }

    fn parse_field_label(&mut self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match self.cur {
                0x30..0x39 | 0x41..0x5a | 0x61..0x7a | 0x5f |
                0x2e | 0x2d => bytes.push(self.cur as u8),
                0x3a if bytes.len() == 0 => return ParseError(~"label is empty"),
                0x3a => return ParseOk(FieldLabel, str::from_bytes(bytes)),
                -1   => return ParseError(~"EOF while parsing field label"),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    fn parse_field_value(&mut self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match self.cur {
                0x01..0x08 | 0x0b | 0x0c |
                0x0e..0xff => bytes.push(self.cur as u8),
                0x0d => return self.consume_forward_LF(str::from_bytes(bytes)),
                0x0a => return ParseOk(FieldValue(NL), str::from_bytes(bytes)),
                0x09 => return ParseOk(FieldValue(TAB), str::from_bytes(bytes)),
                -1   => return ParseOk(FieldValue(EOF), str::from_bytes(bytes)),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    fn consume_forward_LF(&mut self, rv: ~str) -> ParseResult<~str> {
        self.bump();
        if self.cur != 0x0a {
            ParseError(~"CR detected, but not provided with LF")
        } else {
            ParseOk(FieldValue(NL), rv)
        }
    }

    fn skip_whitespaces(&mut self) {
        while char::is_whitespace(self.cur as char) {
            self.bump();
        }
    }
}

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

    #[test]
    fn test_parse_simple() {
        let records = io::with_str_reader(~"a:1\tb:2", |rd| rd.read_ltsv());
        assert records.len() == 1;
    }

    #[test]
    fn test_parse_full() {
        let s = io::with_str_writer(|wr| {
            // genzairyou
            wr.write_str(fmt!("%s:%s\t", "tofu", "豆"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "魚"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "海藻"));
            // konomi
            wr.write_str(fmt!("%s:%s\t", "tofu", "好き"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "普通"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "苦手"));
        });
        let records = io::with_str_reader(s, |rd| rd.read_ltsv());
        assert records.len() == 2;
    }

    #[test]
    fn test_parse_ltsv_trailing_nl_and_write() {
        let s = io::with_str_writer(|wr| {
            wr.write_str(fmt!("%s:%s\t", "neko", "yes"));
            wr.write_str(fmt!("%s:%s\t", "inu", "yes"));
            wr.write_str(fmt!("%s:%s\n", "tori", "yes"));
        });
        let records_1 = io::with_str_reader(s, |rd| rd.read_ltsv());
        let s2 = io::with_str_writer(|wr| wr.write_ltsv(records_1));
        let records_2 = io::with_str_reader(s2, |rd| rd.read_ltsv());
        assert records_1 == records_2;
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests;
pub mod response;

pub use message::response::*;
use notification::Notification;
use std::collections::HashMap;
use std::collections::BTreeMap;
use std::str;
use curl::http;
use rustc_serialize::json::{self, Json, ToJson};

#[derive(PartialEq, Debug, Clone)]
pub enum Priority {
  Normal, High
}

/// Represents a GCM message. Construct the GCM message
/// using various utility methods and finally send it.
/// # Examples:
/// ```rust
/// use gcm::Message;
///
/// let message = Message::new("<registration id>").dry_run(true);
/// ```
pub struct Message<'a> {
  to: &'a str,
  registration_ids: Option<Vec<String>>,
  collapse_key: Option<&'a str>,
  priority: Option<Priority>,
  content_available: Option<bool>,
  delay_while_idle: Option<bool>,
  time_to_live: Option<i32>,
  restricted_package_name: Option<&'a str>,
  dry_run: Option<bool>,
  data: Option<HashMap<String, String>>,
  notification: Option<Notification<'a>>,
}

impl <'a> ToJson for Message<'a> {
  fn to_json(&self) -> Json {
    let mut root = BTreeMap::new();

    root.insert("to".to_string(), self.to.to_json());

    if self.registration_ids.is_some() {
      root.insert("registration_ids".to_string(),
          self.registration_ids.clone().unwrap().to_json());
    }

    if self.collapse_key.is_some() {
      root.insert("collapse_key".to_string(), self.collapse_key.clone().unwrap().to_json());
    }

    if self.priority.is_some() {
      root.insert("priority".to_string(), match self.priority.clone().unwrap() {
        Priority::Normal => Json::String("normal".to_string()),
        Priority::High => Json::String("high".to_string()),
      });
    }

    if self.content_available.is_some() {
      root.insert("content_available".to_string(), self.content_available.unwrap().to_json());
    }

    if self.delay_while_idle.is_some() {
      root.insert("delay_while_idle".to_string(), self.delay_while_idle.unwrap().to_json());
    }

    if self.time_to_live.is_some() {
      root.insert("time_to_live".to_string(), self.time_to_live.unwrap().to_json());
    }

    if self.restricted_package_name.is_some() {
      root.insert("restricted_package_name".to_string(), self.restricted_package_name.clone().unwrap().to_json());
    }

    if self.dry_run.is_some() {
      root.insert("dry_run".to_string(), self.dry_run.unwrap().to_json());
    }

    if self.data.is_some() {
      root.insert("data".to_string(), self.data.clone().unwrap().to_json());
    }

    if self.notification.is_some() {
      root.insert("notification".to_string(), self.notification.clone().unwrap().to_json());
    }

    Json::Object(root)
  }
}

impl <'a> Message<'a> {
  /// Get a new instance of Message. You need to supply either
  /// a registration id, or a topic (/topic/...).
  pub fn new(to: &'a str) -> Message {
    Message {
      to: to,
      registration_ids: None,
      collapse_key: None,
      priority: None,
      content_available: None,
      delay_while_idle: None,
      time_to_live: None,
      restricted_package_name: None,
      dry_run: None,
      data: None,
      notification: None,
    }
  }

  /// Set various registration ids to which the message ought to be sent.
  pub fn registration_ids(mut self, ids: Vec<&'a str>) -> Message<'a> {
    self.registration_ids = Some(ids.iter().map(|s| s.to_string()).collect());
    self
  }

  /// Set this parameter to identify groups of messages that can be collapsed.
  pub fn collapse_key(mut self, collapse_key: &'a str) -> Message<'a> {
    self.collapse_key = Some(collapse_key);
    self
  }

  /// Set the priority of the message. You can set Normal or High priorities.
  /// # Examples:
  /// ```rust
  /// use gcm::{Message, Priority};
  ///
  /// let message = Message::new("<registration id>")
  ///     .priority(Priority::High);
  /// ```
  pub fn priority(mut self, priority: Priority) -> Message<'a> {
    self.priority = Some(priority);
    self
  }

  /// To set the `content-available` field on iOS
  pub fn content_available(mut self, content_available: bool) -> Message<'a> {
    self.content_available = Some(content_available);
    self
  }

  /// When set to `true`, sends the message only when the device is active.
  pub fn delay_while_idle(mut self, delay_while_idle: bool) -> Message<'a> {
    self.delay_while_idle = Some(delay_while_idle);
    self
  }

  /// How long (in seconds) to keep the message on GCM servers in case the device
  /// is offline. The maximum and default is 4 weeks.
  pub fn time_to_live(mut self, time_to_live: i32) -> Message<'a> {
    self.time_to_live = Some(time_to_live);
    self
  }

  /// Package name of the application where the registration tokens must match.
  pub fn restricted_package_name(mut self, restricted_package_name: &'a str) -> Message<'a> {
    self.restricted_package_name = Some(restricted_package_name);
    self
  }

  /// When set to `true`, allows you to test GCM without actually sending the message.
  pub fn dry_run(mut self, dry_run: bool) -> Message<'a> {
    self.dry_run = Some(dry_run);
    self
  }

  /// Use this to add custom key-value pairs to the message. This data
  /// must be handled appropriately on the client end.
  /// # Examples:
  /// ```rust
  /// use gcm::Message;
  /// use std::collections::HashMap;
  ///
  /// let mut map = HashMap::new();
  /// map.insert("message", "Howdy!");
  ///
  /// let message = Message::new("<registration id>").data(map);
  /// ```
  pub fn data(mut self, data: HashMap<&'a str, &'a str>) -> Message<'a> {
    let mut datamap: HashMap<String, String> = HashMap::new();
    for (key, val) in data.iter() {
      datamap.insert(key.to_string(), val.to_string());
    }

    self.data = Some(datamap);
    self
  }

  /// Use this to set a `Notification` for the message.
  /// # Examples:
  /// ```rust
  /// use gcm::{Message, NotificationBuilder};
  ///
  /// let notification = NotificationBuilder::new("Hey!")
  ///     .body("Do you want to catch up later?")
  ///     .finalize();
  ///
  /// let message = Message::new("<registration id>")
  ///     .notification(notification);
  /// ```
  pub fn notification(mut self, notification: Notification<'a>) -> Message<'a> {
    self.notification = Some(notification);
    self
  }

  /// Send the message using your GCM API Key.
  /// # Examples:
  /// ```no_run
  /// use gcm::Message;
  /// use std::collections::HashMap;
  ///
  /// let mut map = HashMap::new();
  /// map.insert("message", "Howdy!");
  ///
  /// let result = Message::new("<registration id>")
  ///     .data(map)
  ///     .send("<GCM API Key>");
  /// ```
  pub fn send(self, api_key: &'a str) -> Result<response::GcmResponse, response::GcmError> {
    let payload = self.to_json().to_string();
    let auth_header = "key=".to_string() + api_key;
    let res;
    let body;
    let code;

    let result = http::handle()
        .post("https://gcm-http.googleapis.com/gcm/send", &payload)
        .header("Authorization", &auth_header)
        .header("Content-Type", "application/json")
        .exec();

    match result {
      Ok(unwrapped) => {
        res = unwrapped;
        body = str::from_utf8(res.get_body()).unwrap();
        code = res.get_code();

        Message::parse_response(code, body)
      },
      Err(_) => {
        Message::parse_response(500, "Server Error")
      }
    }
  }

  fn parse_response(status: u32, body: &str) -> Result<response::GcmResponse, response::GcmError> {
    match status {
      200 => {
        Ok(json::decode(body).unwrap())
      },
      401 => Err(response::GcmError::Unauthorized),
      400 => Err(response::GcmError::InvalidMessage(body.to_string())),
      500...599 => Err(response::GcmError::ServerError),
      _ => Err(response::GcmError::InvalidMessage("Unknown Error".to_string())),
    }
  }
}
<commit_msg>Update http api endpoint<commit_after>#[cfg(test)]
mod tests;
pub mod response;

pub use message::response::*;
use notification::Notification;
use std::collections::HashMap;
use std::collections::BTreeMap;
use std::str;
use curl::http;
use rustc_serialize::json::{self, Json, ToJson};

#[derive(PartialEq, Debug, Clone)]
pub enum Priority {
  Normal, High
}

/// Represents a GCM message. Construct the GCM message
/// using various utility methods and finally send it.
/// # Examples:
/// ```rust
/// use gcm::Message;
///
/// let message = Message::new("<registration id>").dry_run(true);
/// ```
pub struct Message<'a> {
  to: &'a str,
  registration_ids: Option<Vec<String>>,
  collapse_key: Option<&'a str>,
  priority: Option<Priority>,
  content_available: Option<bool>,
  delay_while_idle: Option<bool>,
  time_to_live: Option<i32>,
  restricted_package_name: Option<&'a str>,
  dry_run: Option<bool>,
  data: Option<HashMap<String, String>>,
  notification: Option<Notification<'a>>,
}

impl <'a> ToJson for Message<'a> {
  fn to_json(&self) -> Json {
    let mut root = BTreeMap::new();

    root.insert("to".to_string(), self.to.to_json());

    if self.registration_ids.is_some() {
      root.insert("registration_ids".to_string(),
          self.registration_ids.clone().unwrap().to_json());
    }

    if self.collapse_key.is_some() {
      root.insert("collapse_key".to_string(), self.collapse_key.clone().unwrap().to_json());
    }

    if self.priority.is_some() {
      root.insert("priority".to_string(), match self.priority.clone().unwrap() {
        Priority::Normal => Json::String("normal".to_string()),
        Priority::High => Json::String("high".to_string()),
      });
    }

    if self.content_available.is_some() {
      root.insert("content_available".to_string(), self.content_available.unwrap().to_json());
    }

    if self.delay_while_idle.is_some() {
      root.insert("delay_while_idle".to_string(), self.delay_while_idle.unwrap().to_json());
    }

    if self.time_to_live.is_some() {
      root.insert("time_to_live".to_string(), self.time_to_live.unwrap().to_json());
    }

    if self.restricted_package_name.is_some() {
      root.insert("restricted_package_name".to_string(), self.restricted_package_name.clone().unwrap().to_json());
    }

    if self.dry_run.is_some() {
      root.insert("dry_run".to_string(), self.dry_run.unwrap().to_json());
    }

    if self.data.is_some() {
      root.insert("data".to_string(), self.data.clone().unwrap().to_json());
    }

    if self.notification.is_some() {
      root.insert("notification".to_string(), self.notification.clone().unwrap().to_json());
    }

    Json::Object(root)
  }
}

impl <'a> Message<'a> {
  /// Get a new instance of Message. You need to supply either
  /// a registration id, or a topic (/topic/...).
  pub fn new(to: &'a str) -> Message {
    Message {
      to: to,
      registration_ids: None,
      collapse_key: None,
      priority: None,
      content_available: None,
      delay_while_idle: None,
      time_to_live: None,
      restricted_package_name: None,
      dry_run: None,
      data: None,
      notification: None,
    }
  }

  /// Set various registration ids to which the message ought to be sent.
  pub fn registration_ids(mut self, ids: Vec<&'a str>) -> Message<'a> {
    self.registration_ids = Some(ids.iter().map(|s| s.to_string()).collect());
    self
  }

  /// Set this parameter to identify groups of messages that can be collapsed.
  pub fn collapse_key(mut self, collapse_key: &'a str) -> Message<'a> {
    self.collapse_key = Some(collapse_key);
    self
  }

  /// Set the priority of the message. You can set Normal or High priorities.
  /// # Examples:
  /// ```rust
  /// use gcm::{Message, Priority};
  ///
  /// let message = Message::new("<registration id>")
  ///     .priority(Priority::High);
  /// ```
  pub fn priority(mut self, priority: Priority) -> Message<'a> {
    self.priority = Some(priority);
    self
  }

  /// To set the `content-available` field on iOS
  pub fn content_available(mut self, content_available: bool) -> Message<'a> {
    self.content_available = Some(content_available);
    self
  }

  /// When set to `true`, sends the message only when the device is active.
  pub fn delay_while_idle(mut self, delay_while_idle: bool) -> Message<'a> {
    self.delay_while_idle = Some(delay_while_idle);
    self
  }

  /// How long (in seconds) to keep the message on GCM servers in case the device
  /// is offline. The maximum and default is 4 weeks.
  pub fn time_to_live(mut self, time_to_live: i32) -> Message<'a> {
    self.time_to_live = Some(time_to_live);
    self
  }

  /// Package name of the application where the registration tokens must match.
  pub fn restricted_package_name(mut self, restricted_package_name: &'a str) -> Message<'a> {
    self.restricted_package_name = Some(restricted_package_name);
    self
  }

  /// When set to `true`, allows you to test GCM without actually sending the message.
  pub fn dry_run(mut self, dry_run: bool) -> Message<'a> {
    self.dry_run = Some(dry_run);
    self
  }

  /// Use this to add custom key-value pairs to the message. This data
  /// must be handled appropriately on the client end.
  /// # Examples:
  /// ```rust
  /// use gcm::Message;
  /// use std::collections::HashMap;
  ///
  /// let mut map = HashMap::new();
  /// map.insert("message", "Howdy!");
  ///
  /// let message = Message::new("<registration id>").data(map);
  /// ```
  pub fn data(mut self, data: HashMap<&'a str, &'a str>) -> Message<'a> {
    let mut datamap: HashMap<String, String> = HashMap::new();
    for (key, val) in data.iter() {
      datamap.insert(key.to_string(), val.to_string());
    }

    self.data = Some(datamap);
    self
  }

  /// Use this to set a `Notification` for the message.
  /// # Examples:
  /// ```rust
  /// use gcm::{Message, NotificationBuilder};
  ///
  /// let notification = NotificationBuilder::new("Hey!")
  ///     .body("Do you want to catch up later?")
  ///     .finalize();
  ///
  /// let message = Message::new("<registration id>")
  ///     .notification(notification);
  /// ```
  pub fn notification(mut self, notification: Notification<'a>) -> Message<'a> {
    self.notification = Some(notification);
    self
  }

  /// Send the message using your GCM API Key.
  /// # Examples:
  /// ```no_run
  /// use gcm::Message;
  /// use std::collections::HashMap;
  ///
  /// let mut map = HashMap::new();
  /// map.insert("message", "Howdy!");
  ///
  /// let result = Message::new("<registration id>")
  ///     .data(map)
  ///     .send("<GCM API Key>");
  /// ```
  pub fn send(self, api_key: &'a str) -> Result<response::GcmResponse, response::GcmError> {
    let payload = self.to_json().to_string();
    let auth_header = "key=".to_string() + api_key;
    let res;
    let body;
    let code;

    let result = http::handle()
        .post("https://fcm.googleapis.com/fcm/send", &payload)
        .header("Authorization", &auth_header)
        .header("Content-Type", "application/json")
        .exec();

    match result {
      Ok(unwrapped) => {
        res = unwrapped;
        body = str::from_utf8(res.get_body()).unwrap();
        code = res.get_code();

        Message::parse_response(code, body)
      },
      Err(_) => {
        Message::parse_response(500, "Server Error")
      }
    }
  }

  fn parse_response(status: u32, body: &str) -> Result<response::GcmResponse, response::GcmError> {
    match status {
      200 => {
        Ok(json::decode(body).unwrap())
      },
      401 => Err(response::GcmError::Unauthorized),
      400 => Err(response::GcmError::InvalidMessage(body.to_string())),
      500...599 => Err(response::GcmError::ServerError),
      _ => Err(response::GcmError::InvalidMessage("Unknown Error".to_string())),
    }
  }
}
<|endoftext|>


<commit_before>use super::utils::types::{ Sha256Digest, Bitfield, Blake2sDigest };
use super::utils::bls::{ Signature, AggregateSignature, Keypair, PublicKey };
use super::aggregate_vote::AggregateVote;
use super::rlp::{ RlpStream, Encodable } ;

pub struct Block {
    pub parent_hash: Sha256Digest,
    pub skip_count: u64,
    pub randao_reveal: Sha256Digest,
    pub attestation_bitfield: Bitfield,
    pub attestation_aggregate_sig: AggregateSignature,
    pub shard_aggregate_votes: Vec<AggregateVote>,
    pub main_chain_ref: Sha256Digest,
    pub state_hash: Blake2sDigest,
    pub sig: Option<Signature>
}
impl Block {
    pub fn new(parent_hash: Sha256Digest,
               randao_reveal: Sha256Digest,
               main_chain_ref: Sha256Digest,
               state_hash: Blake2sDigest) -> Block {
        Block {
            parent_hash: parent_hash,
            skip_count: 0,
            randao_reveal: randao_reveal,
            attestation_bitfield: Vec::new(),
            attestation_aggregate_sig: AggregateSignature::new(),
            shard_aggregate_votes: Vec::new(),
            main_chain_ref: main_chain_ref,
            state_hash: state_hash,
            sig: None
        }
    }

    /*
     * Take a Block and covert it into an array of u8 for BLS signing
     * or verfication. The `sig` field is purposefully omitted.
     */
    pub fn encode_to_signable_message(&self) -> [u8; 9140] {
        // Using biggest avg. block size from v2 spec
        let mut message: [u8; 9140] = [0; 9140];

        // Create the RLP vector
        let mut s = RlpStream::new();
        s.append(&self.parent_hash);
        s.append(&self.skip_count);
        s.append(&self.randao_reveal);
        s.append(&self.attestation_bitfield);
        // TODO: represent attestation_aggregate_sig
        // TODO: represent shard_aggregate_votes
        s.append(&self.main_chain_ref);
        s.append(&self.state_hash);
        let rlp_vec = s.out();

        // Parse the RLP vector into an array compatible with the BLS signer
        let len = rlp_vec.len();
        message[..len].copy_from_slice(&rlp_vec[..len]);
        message
    }

    /*
     * Sign the block with the given keypair.
     */
    pub fn sig_sign(&mut self, keypair: &Keypair) {
        let message = self.encode_to_signable_message();
        self.sig = Some(keypair.sign(&message));
    }

    /*
     * Verify a block signature given some keypair.
     */
    pub fn sig_verify(&self, pub_key: &PublicKey) -> bool {
        let message = self.encode_to_signable_message();
        match &self.sig {
            None => false,
            Some(sig) => {
                pub_key.verify(&message, &sig)
            },
        }
    }
}

impl Encodable for Block {
    fn rlp_append(&self, s: &mut RlpStream) {
        s.append(&self.parent_hash);
        s.append(&self.skip_count);
        s.append(&self.randao_reveal);
        s.append(&self.attestation_bitfield);
        // s.append(&self.attestation_aggregate_sig);   // TODO: RLP this
        s.append_list(&self.shard_aggregate_votes);
        s.append(&self.main_chain_ref);
        s.append(&self.state_hash);
        // s.append(&self.sig);    // TODO: RLP this
    }
}

#[cfg(test)]
mod tests {
    use super::super::rlp;
    extern crate rand;

    use super::*;
    use self::rand::{ SeedableRng, XorShiftRng };

    #[test]
    fn test_new_for_parent_hash() {
        let parent_hash = Sha256Digest::random();
        let randao_reveal = Sha256Digest::random();
        let main_chain_ref = Sha256Digest::random();
        let state_hash = Sha256Digest::random();
        let b = Block::new(parent_hash,
                           randao_reveal,
                           main_chain_ref,
                           state_hash);
        assert_eq!(b.parent_hash, parent_hash);
        assert_eq!(b.randao_reveal, randao_reveal);
        assert_eq!(b.main_chain_ref, main_chain_ref);
        assert_eq!(b.state_hash, state_hash);
    }

    #[test]
    fn test_signable_message_encoding() {
        let parent_hash = Sha256Digest::from([0; 32]);
        let randao_reveal = Sha256Digest::from([1; 32]);
        let main_chain_ref = Sha256Digest::from([2; 32]);
        let state_hash = Sha256Digest::from([3; 32]);
        let mut b = Block::new(parent_hash,
                           randao_reveal,
                           main_chain_ref,
                           state_hash);
        b.skip_count = 2;
        let output = b.encode_to_signable_message();
        // TODO: test this better
        assert_eq!(output[0], 160);
        assert_eq!(output[1..21], [0; 20]);
    }

    #[test]
    fn test_sign_and_verify() {
        let mut rng = XorShiftRng::from_seed([0xbc4f6d44, 0xd62f276c, 0xb963afd0, 0x5455863d]);
        let alice_keypair = Keypair::generate(&mut rng);
        let bob_keypair = Keypair::generate(&mut rng);
        let mut b = Block::new(Sha256Digest::random(),
                           Sha256Digest::random(),
                           Sha256Digest::random(),
                           Sha256Digest::random());

        // Both signatures fail before signing
        assert_eq!(b.sig_verify(&alice_keypair.public), false);
        assert_eq!(b.sig_verify(&bob_keypair.public), false);

        // Sign as Alice
        b.sig_sign(&alice_keypair);

        // Alice signature passes, bobs fails
        assert_eq!(b.sig_verify(&alice_keypair.public), true);
        assert_eq!(b.sig_verify(&bob_keypair.public), false);
    }

    #[test]
    fn test_serialization() {
        let b = Block {
            parent_hash: Sha256Digest::zero(),
            skip_count: 100,
            randao_reveal: Sha256Digest::zero(),
            attestation_bitfield: Vec::new(),
            attestation_aggregate_sig: AggregateSignature::new(),
            shard_aggregate_votes: Vec::new(),
            main_chain_ref: Sha256Digest::zero(),
            state_hash: Blake2sDigest::zero(),
            sig: None
        };
        let e = rlp::encode(&b);
        println!("{:?}", e);
        assert_eq!(e.len(), 135);
        assert_eq!(e[0], 160);
        assert_eq!(e[1..33], [0; 32]);
        assert_eq!(e[33], 100);
        assert_eq!(e[34], 160);
        assert_eq!(e[35..67], [0; 32]);
        assert_eq!(e[67], 128);
        assert_eq!(e[68], 192);
        assert_eq!(e[69], 160);
        assert_eq!(e[70..102], [0; 32]);
        assert_eq!(e[102], 160);
        assert_eq!(e[103..135], [0; 32]);
    }
}
<commit_msg>Improve RLP encoding of Block<commit_after>use super::utils::types::{ Sha256Digest, Bitfield, Blake2sDigest };
use super::utils::bls::{ Signature, AggregateSignature, Keypair, PublicKey };
use super::aggregate_vote::AggregateVote;
use super::rlp::{ RlpStream, Encodable } ;

pub struct Block {
    pub parent_hash: Sha256Digest,
    pub skip_count: u64,
    pub randao_reveal: Sha256Digest,
    pub attestation_bitfield: Bitfield,
    pub attestation_aggregate_sig: AggregateSignature,
    pub shard_aggregate_votes: Vec<AggregateVote>,
    pub main_chain_ref: Sha256Digest,
    pub state_hash: Blake2sDigest,
    pub sig: Option<Signature>
}
impl Block {
    pub fn new(parent_hash: Sha256Digest,
               randao_reveal: Sha256Digest,
               main_chain_ref: Sha256Digest,
               state_hash: Blake2sDigest) -> Block {
        Block {
            parent_hash: parent_hash,
            skip_count: 0,
            randao_reveal: randao_reveal,
            attestation_bitfield: Vec::new(),
            attestation_aggregate_sig: AggregateSignature::new(),
            shard_aggregate_votes: Vec::new(),
            main_chain_ref: main_chain_ref,
            state_hash: state_hash,
            sig: None
        }
    }

    /*
     * Take a Block and covert it into an array of u8 for BLS signing
     * or verfication. The `sig` field is purposefully omitted.
     */
    pub fn encode_to_signable_message(&self) -> [u8; 9140] {
        // Using biggest avg. block size from v2 spec
        let mut message: [u8; 9140] = [0; 9140];

        // Create the RLP vector
        let mut s = RlpStream::new();
        s.append(&self.parent_hash);
        s.append(&self.skip_count);
        s.append(&self.randao_reveal);
        s.append(&self.attestation_bitfield);
        // s.append(&self.attestation_aggregate_sig);   // TODO: RLP this
        s.append_list(&self.shard_aggregate_votes);
        s.append(&self.main_chain_ref);
        s.append(&self.state_hash);
        let rlp_vec = s.out();

        // Parse the RLP vector into an array compatible with the BLS signer
        let len = rlp_vec.len();
        message[..len].copy_from_slice(&rlp_vec[..len]);
        message
    }

    /*
     * Sign the block with the given keypair.
     */
    pub fn sig_sign(&mut self, keypair: &Keypair) {
        let message = self.encode_to_signable_message();
        self.sig = Some(keypair.sign(&message));
    }

    /*
     * Verify a block signature given some keypair.
     */
    pub fn sig_verify(&self, pub_key: &PublicKey) -> bool {
        let message = self.encode_to_signable_message();
        match &self.sig {
            None => false,
            Some(sig) => {
                pub_key.verify(&message, &sig)
            },
        }
    }
}

impl Encodable for Block {
    fn rlp_append(&self, s: &mut RlpStream) {
        s.append(&self.parent_hash);
        s.append(&self.skip_count);
        s.append(&self.randao_reveal);
        s.append(&self.attestation_bitfield);
        // s.append(&self.attestation_aggregate_sig);   // TODO: RLP this
        s.append_list(&self.shard_aggregate_votes);
        s.append(&self.main_chain_ref);
        s.append(&self.state_hash);
        // s.append(&self.sig);    // TODO: RLP this
    }
}

#[cfg(test)]
mod tests {
    use super::super::rlp;
    extern crate rand;

    use super::*;
    use self::rand::{ SeedableRng, XorShiftRng };

    #[test]
    fn test_new_for_parent_hash() {
        let parent_hash = Sha256Digest::random();
        let randao_reveal = Sha256Digest::random();
        let main_chain_ref = Sha256Digest::random();
        let state_hash = Sha256Digest::random();
        let b = Block::new(parent_hash,
                           randao_reveal,
                           main_chain_ref,
                           state_hash);
        assert_eq!(b.parent_hash, parent_hash);
        assert_eq!(b.randao_reveal, randao_reveal);
        assert_eq!(b.main_chain_ref, main_chain_ref);
        assert_eq!(b.state_hash, state_hash);
    }

    #[test]
    fn test_signable_message_encoding() {
        let parent_hash = Sha256Digest::from([0; 32]);
        let randao_reveal = Sha256Digest::from([1; 32]);
        let main_chain_ref = Sha256Digest::from([2; 32]);
        let state_hash = Sha256Digest::from([3; 32]);
        let mut b = Block::new(parent_hash,
                           randao_reveal,
                           main_chain_ref,
                           state_hash);
        b.skip_count = 2;
        let output = b.encode_to_signable_message();
        // TODO: test this better
        assert_eq!(output[0], 160);
        assert_eq!(output[1..21], [0; 20]);
    }

    #[test]
    fn test_sign_and_verify() {
        let mut rng = XorShiftRng::from_seed([0xbc4f6d44, 0xd62f276c, 0xb963afd0, 0x5455863d]);
        let alice_keypair = Keypair::generate(&mut rng);
        let bob_keypair = Keypair::generate(&mut rng);
        let mut b = Block::new(Sha256Digest::random(),
                           Sha256Digest::random(),
                           Sha256Digest::random(),
                           Sha256Digest::random());

        // Both signatures fail before signing
        assert_eq!(b.sig_verify(&alice_keypair.public), false);
        assert_eq!(b.sig_verify(&bob_keypair.public), false);

        // Sign as Alice
        b.sig_sign(&alice_keypair);

        // Alice signature passes, bobs fails
        assert_eq!(b.sig_verify(&alice_keypair.public), true);
        assert_eq!(b.sig_verify(&bob_keypair.public), false);
    }

    #[test]
    fn test_serialization() {
        let b = Block {
            parent_hash: Sha256Digest::zero(),
            skip_count: 100,
            randao_reveal: Sha256Digest::zero(),
            attestation_bitfield: Vec::new(),
            attestation_aggregate_sig: AggregateSignature::new(),
            shard_aggregate_votes: Vec::new(),
            main_chain_ref: Sha256Digest::zero(),
            state_hash: Blake2sDigest::zero(),
            sig: None
        };
        let e = rlp::encode(&b);
        println!("{:?}", e);
        assert_eq!(e.len(), 135);
        assert_eq!(e[0], 160);
        assert_eq!(e[1..33], [0; 32]);
        assert_eq!(e[33], 100);
        assert_eq!(e[34], 160);
        assert_eq!(e[35..67], [0; 32]);
        assert_eq!(e[67], 128);
        assert_eq!(e[68], 192);
        assert_eq!(e[69], 160);
        assert_eq!(e[70..102], [0; 32]);
        assert_eq!(e[102], 160);
        assert_eq!(e[103..135], [0; 32]);
    }
}
<|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/.

// Code to handle initial setup steps for a pool.
// Initial setup steps are steps that do not alter the environment.

use std::collections::{HashMap, HashSet};
use std::io::ErrorKind;
use std::fs::{OpenOptions, read_dir};
use std::os::linux::fs::MetadataExt;
use std::path::PathBuf;
use std::str::FromStr;

use nix::Errno;
use nix::sys::stat::{S_IFBLK, S_IFMT};
use serde_json;

use devicemapper::Device;

use super::super::errors::{EngineResult, EngineError, ErrorEnum};
use super::super::types::PoolUuid;

use super::blockdev::BlockDev;
use super::device::blkdev_size;
use super::engine::DevOwnership;
use super::metadata::{BDA, StaticHeader};
use super::range_alloc::RangeAllocator;
use super::serde_structs::PoolSave;

/// Find all Stratis devices.
///
/// Returns a map of pool uuids to a vector of devices for each pool.
pub fn find_all() -> EngineResult<HashMap<PoolUuid, Vec<PathBuf>>> {

    let mut pool_map = HashMap::new();
    for dir_e in try!(read_dir("/dev")) {
        let dir_e = try!(dir_e);
        let mode = try!(dir_e.metadata()).st_mode();

        // Device node can't belong to Stratis if it is not a block device
        if mode & S_IFMT.bits() != S_IFBLK.bits() {
            continue;
        }

        let devnode = dir_e.path();

        let f = OpenOptions::new().read(true).open(&devnode);

        // There are some reasons for OpenOptions::open() to return an error
        // which are not reasons for this method to return an error.
        // Try to distinguish. Non-error conditions are:
        //
        // 1. ENXIO: The device does not exist anymore. This means that the device
        // was volatile for some reason; in that case it can not belong to
        // Stratis so it is safe to ignore it.
        //
        // 2. ENOMEDIUM: The device has no medium. An example of this case is an
        // empty optical drive.
        //
        // Note that it is better to be conservative and return with an
        // error in any case where failure to read the device could result
        // in bad data for Stratis. Additional exceptions may be added,
        // but only with a complete justification.
        if f.is_err() {
            let err = f.unwrap_err();
            match err.kind() {
                ErrorKind::NotFound => {
                    continue;
                }
                _ => {
                    if let Some(errno) = err.raw_os_error() {
                        match Errno::from_i32(errno) {
                            Errno::ENXIO | Errno::ENOMEDIUM => continue,
                            _ => return Err(EngineError::Io(err)),
                        };
                    } else {
                        return Err(EngineError::Io(err));
                    }
                }
            }
        }

        let mut f = f.expect("unreachable if f is err");
        if let DevOwnership::Ours(uuid) = try!(StaticHeader::determine_ownership(&mut f)) {
            pool_map
                .entry(uuid)
                .or_insert_with(Vec::new)
                .push(devnode)
        };
    }

    Ok(pool_map)
}

/// Get the most recent metadata from a set of Devices for a given pool UUID.
/// Returns None if no metadata found for this pool.
pub fn get_metadata(pool_uuid: PoolUuid, devnodes: &[PathBuf]) -> EngineResult<Option<PoolSave>> {

    // No device nodes means no metadata
    if devnodes.is_empty() {
        return Ok(None);
    }

    // Get pairs of device nodes and matching BDAs
    // If no BDA, or BDA UUID does not match pool UUID, skip.
    // If there is an error reading the BDA, error. There could have been
    // vital information on that BDA, for example, it may have contained
    // the newest metadata.
    let mut bdas = Vec::new();
    for devnode in devnodes {
        let bda = try!(BDA::load(&mut try!(OpenOptions::new().read(true).open(devnode))));
        if bda.is_none() {
            continue;
        }
        let bda = bda.expect("unreachable if bda is None");

        if *bda.pool_uuid() != pool_uuid {
            continue;
        }
        bdas.push((devnode, bda));
    }

    // We may have had no devices with BDAs for this pool, so return if no BDAs.
    if bdas.is_empty() {
        return Ok(None);
    }

    // Get a most recent BDA
    let &(_, ref most_recent_bda) = bdas.iter()
        .max_by_key(|p| p.1.last_update_time())
        .expect("bdas is not empty, must have a max");

    // Most recent time should never be None if this was a properly
    // created pool; this allows for the method to be called in other
    // circumstances.
    let most_recent_time = most_recent_bda.last_update_time();
    if most_recent_time.is_none() {
        return Ok(None);
    }

    // Try to read from all available devnodes that could contain most
    // recent metadata. In the event of errors, continue to try until all are
    // exhausted.
    for &(devnode, ref bda) in
        bdas.iter()
            .filter(|&&(_, ref bda)| bda.last_update_time() == most_recent_time) {

        let poolsave = OpenOptions::new()
            .read(true)
            .open(devnode)
            .ok()
            .and_then(|mut f| bda.load_state(&mut f).ok())
            .and_then(|opt| opt)
            .and_then(|data| serde_json::from_slice(&data).ok());

        if poolsave.is_some() {
            return Ok(poolsave);
        }
    }

    // If no data has yet returned, we have an error. That is, we should have
    // some metadata, because we have a most recent time, but we failed to
    // get any.
    let err_str = "timestamp indicates data was written, but no data succesfully read";
    Err(EngineError::Engine(ErrorEnum::NotFound, err_str.into()))
}

/// Get the blockdevs corresponding to this pool.
pub fn get_blockdevs(pool_save: &PoolSave, devnodes: &[PathBuf]) -> EngineResult<Vec<BlockDev>> {
    let segments = pool_save
        .flex_devs
        .meta_dev
        .iter()
        .chain(pool_save.flex_devs.thin_meta_dev.iter())
        .chain(pool_save.flex_devs.thin_data_dev.iter());

    let mut segment_table = HashMap::new();
    for seg in segments {
        segment_table
            .entry(seg.0.clone())
            .or_insert(vec![])
            .push((seg.1, seg.2))
    }

    let mut blockdevs = vec![];
    let mut devices = HashSet::new();
    for dev in devnodes {
        let device = try!(Device::from_str(&dev.to_string_lossy()));

        // If we've seen this device already, skip it.
        if !devices.insert(device) {
            continue;
        }

        let bda = try!(BDA::load(&mut try!(OpenOptions::new().read(true).open(dev))));
        let bda = try!(bda.ok_or(EngineError::Engine(ErrorEnum::NotFound,
                                                     "no BDA found for Stratis device".into())));

        let actual_size = try!(blkdev_size(&try!(OpenOptions::new().read(true).open(dev))))
            .sectors();

        // If size of device has changed and is less, then it is possible
        // that the segments previously allocated for this blockdev no
        // longer exist. If that is the case, RangeAllocator::new() will
        // return an error.
        let allocator =
            try!(RangeAllocator::new(actual_size,
                                     segment_table.get(bda.dev_uuid()).unwrap_or(&vec![])));

        blockdevs.push(BlockDev::new(device, dev.clone(), bda, allocator));
    }

    // Verify that blockdevs found match blockdevs recorded.
    let current_uuids: HashSet<_> = blockdevs.iter().map(|b| *b.uuid()).collect();
    let recorded_uuids: HashSet<_> = pool_save.block_devs.keys().map(|u| *u).collect();

    if current_uuids != recorded_uuids {
        let err_msg = "Recorded block dev UUIDs != discovered blockdev UUIDs";
        return Err(EngineError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    if blockdevs.len() != current_uuids.len() {
        let err_msg = "Duplicate block devices found in environment";
        return Err(EngineError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    Ok(blockdevs)
}
<commit_msg>Reverse some logic to eliminate continues and an expect<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/.

// Code to handle initial setup steps for a pool.
// Initial setup steps are steps that do not alter the environment.

use std::collections::{HashMap, HashSet};
use std::io::ErrorKind;
use std::fs::{OpenOptions, read_dir};
use std::os::linux::fs::MetadataExt;
use std::path::PathBuf;
use std::str::FromStr;

use nix::Errno;
use nix::sys::stat::{S_IFBLK, S_IFMT};
use serde_json;

use devicemapper::Device;

use super::super::errors::{EngineResult, EngineError, ErrorEnum};
use super::super::types::PoolUuid;

use super::blockdev::BlockDev;
use super::device::blkdev_size;
use super::engine::DevOwnership;
use super::metadata::{BDA, StaticHeader};
use super::range_alloc::RangeAllocator;
use super::serde_structs::PoolSave;

/// Find all Stratis devices.
///
/// Returns a map of pool uuids to a vector of devices for each pool.
pub fn find_all() -> EngineResult<HashMap<PoolUuid, Vec<PathBuf>>> {

    let mut pool_map = HashMap::new();
    for dir_e in try!(read_dir("/dev")) {
        let dir_e = try!(dir_e);
        let mode = try!(dir_e.metadata()).st_mode();

        // Device node can't belong to Stratis if it is not a block device
        if mode & S_IFMT.bits() != S_IFBLK.bits() {
            continue;
        }

        let devnode = dir_e.path();

        let f = OpenOptions::new().read(true).open(&devnode);

        // There are some reasons for OpenOptions::open() to return an error
        // which are not reasons for this method to return an error.
        // Try to distinguish. Non-error conditions are:
        //
        // 1. ENXIO: The device does not exist anymore. This means that the device
        // was volatile for some reason; in that case it can not belong to
        // Stratis so it is safe to ignore it.
        //
        // 2. ENOMEDIUM: The device has no medium. An example of this case is an
        // empty optical drive.
        //
        // Note that it is better to be conservative and return with an
        // error in any case where failure to read the device could result
        // in bad data for Stratis. Additional exceptions may be added,
        // but only with a complete justification.
        if f.is_err() {
            let err = f.unwrap_err();
            match err.kind() {
                ErrorKind::NotFound => {
                    continue;
                }
                _ => {
                    if let Some(errno) = err.raw_os_error() {
                        match Errno::from_i32(errno) {
                            Errno::ENXIO | Errno::ENOMEDIUM => continue,
                            _ => return Err(EngineError::Io(err)),
                        };
                    } else {
                        return Err(EngineError::Io(err));
                    }
                }
            }
        }

        let mut f = f.expect("unreachable if f is err");
        if let DevOwnership::Ours(uuid) = try!(StaticHeader::determine_ownership(&mut f)) {
            pool_map
                .entry(uuid)
                .or_insert_with(Vec::new)
                .push(devnode)
        };
    }

    Ok(pool_map)
}

/// Get the most recent metadata from a set of Devices for a given pool UUID.
/// Returns None if no metadata found for this pool.
pub fn get_metadata(pool_uuid: PoolUuid, devnodes: &[PathBuf]) -> EngineResult<Option<PoolSave>> {

    // No device nodes means no metadata
    if devnodes.is_empty() {
        return Ok(None);
    }

    // Get pairs of device nodes and matching BDAs
    // If no BDA, or BDA UUID does not match pool UUID, skip.
    // If there is an error reading the BDA, error. There could have been
    // vital information on that BDA, for example, it may have contained
    // the newest metadata.
    let mut bdas = Vec::new();
    for devnode in devnodes {
        let bda = try!(BDA::load(&mut try!(OpenOptions::new().read(true).open(devnode))));
        if let Some(bda) = bda {
            if *bda.pool_uuid() == pool_uuid {
                bdas.push((devnode, bda));
            }
        }
    }

    // We may have had no devices with BDAs for this pool, so return if no BDAs.
    if bdas.is_empty() {
        return Ok(None);
    }

    // Get a most recent BDA
    let &(_, ref most_recent_bda) = bdas.iter()
        .max_by_key(|p| p.1.last_update_time())
        .expect("bdas is not empty, must have a max");

    // Most recent time should never be None if this was a properly
    // created pool; this allows for the method to be called in other
    // circumstances.
    let most_recent_time = most_recent_bda.last_update_time();
    if most_recent_time.is_none() {
        return Ok(None);
    }

    // Try to read from all available devnodes that could contain most
    // recent metadata. In the event of errors, continue to try until all are
    // exhausted.
    for &(devnode, ref bda) in
        bdas.iter()
            .filter(|&&(_, ref bda)| bda.last_update_time() == most_recent_time) {

        let poolsave = OpenOptions::new()
            .read(true)
            .open(devnode)
            .ok()
            .and_then(|mut f| bda.load_state(&mut f).ok())
            .and_then(|opt| opt)
            .and_then(|data| serde_json::from_slice(&data).ok());

        if poolsave.is_some() {
            return Ok(poolsave);
        }
    }

    // If no data has yet returned, we have an error. That is, we should have
    // some metadata, because we have a most recent time, but we failed to
    // get any.
    let err_str = "timestamp indicates data was written, but no data succesfully read";
    Err(EngineError::Engine(ErrorEnum::NotFound, err_str.into()))
}

/// Get the blockdevs corresponding to this pool.
pub fn get_blockdevs(pool_save: &PoolSave, devnodes: &[PathBuf]) -> EngineResult<Vec<BlockDev>> {
    let segments = pool_save
        .flex_devs
        .meta_dev
        .iter()
        .chain(pool_save.flex_devs.thin_meta_dev.iter())
        .chain(pool_save.flex_devs.thin_data_dev.iter());

    let mut segment_table = HashMap::new();
    for seg in segments {
        segment_table
            .entry(seg.0.clone())
            .or_insert(vec![])
            .push((seg.1, seg.2))
    }

    let mut blockdevs = vec![];
    let mut devices = HashSet::new();
    for dev in devnodes {
        let device = try!(Device::from_str(&dev.to_string_lossy()));

        // If we've seen this device already, skip it.
        if !devices.insert(device) {
            continue;
        }

        let bda = try!(BDA::load(&mut try!(OpenOptions::new().read(true).open(dev))));
        let bda = try!(bda.ok_or(EngineError::Engine(ErrorEnum::NotFound,
                                                     "no BDA found for Stratis device".into())));

        let actual_size = try!(blkdev_size(&try!(OpenOptions::new().read(true).open(dev))))
            .sectors();

        // If size of device has changed and is less, then it is possible
        // that the segments previously allocated for this blockdev no
        // longer exist. If that is the case, RangeAllocator::new() will
        // return an error.
        let allocator =
            try!(RangeAllocator::new(actual_size,
                                     segment_table.get(bda.dev_uuid()).unwrap_or(&vec![])));

        blockdevs.push(BlockDev::new(device, dev.clone(), bda, allocator));
    }

    // Verify that blockdevs found match blockdevs recorded.
    let current_uuids: HashSet<_> = blockdevs.iter().map(|b| *b.uuid()).collect();
    let recorded_uuids: HashSet<_> = pool_save.block_devs.keys().map(|u| *u).collect();

    if current_uuids != recorded_uuids {
        let err_msg = "Recorded block dev UUIDs != discovered blockdev UUIDs";
        return Err(EngineError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    if blockdevs.len() != current_uuids.len() {
        let err_msg = "Duplicate block devices found in environment";
        return Err(EngineError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    Ok(blockdevs)
}
<|endoftext|>


<commit_before>//! Endpoints that cannot change with new versions of the Matrix specification.

/// [GET /_matrix/client/versions](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-versions)
pub mod get_supported_versions {
    use ruma_api_macros::ruma_api;

    ruma_api! {
        metadata {
            description: "Get the versions of the client-server API supported by this homeserver.",
            method: GET,
            name: "api_versions",
            path: "/_matrix/client/versions",
            rate_limited: false,
            requires_authentication: true,
        }

        request {}

        response {
            /// A list of Matrix client API protocol versions supported by the homeserver.
            pub versions: Vec<String>,
        }
    }
}
<commit_msg>get_supported_versions does not require authentication<commit_after>//! Endpoints that cannot change with new versions of the Matrix specification.

/// [GET /_matrix/client/versions](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-versions)
pub mod get_supported_versions {
    use ruma_api_macros::ruma_api;

    ruma_api! {
        metadata {
            description: "Get the versions of the client-server API supported by this homeserver.",
            method: GET,
            name: "api_versions",
            path: "/_matrix/client/versions",
            rate_limited: false,
            requires_authentication: false,
        }

        request {}

        response {
            /// A list of Matrix client API protocol versions supported by the homeserver.
            pub versions: Vec<String>,
        }
    }
}
<|endoftext|>


<commit_before>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T>;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(10));

  if *state == ParserState::Header {
    let (i, _) = try_parse!(slice, tag!("fLaC"));

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> bool
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state    = ParserState::Header;
  let mut is_error = false;

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(_)                   => {
        is_error = true;

        break;
      }
    }
  }

  is_error
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }
}
<commit_msg>Add faster version for `2_u32.pow(x)`<commit_after>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T>;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(10));

  if *state == ParserState::Header {
    let (i, _) = try_parse!(slice, tag!("fLaC"));

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> bool
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state    = ParserState::Header;
  let mut is_error = false;

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(_)                   => {
        is_error = true;

        break;
      }
    }
  }

  is_error
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }
}
<|endoftext|>


<commit_before>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T>;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(10));

  if *state == ParserState::Header {
    let (i, _) = try_parse!(slice, tag!("fLaC"));

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> bool
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state    = ParserState::Header;
  let mut is_error = false;

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(_)                   => {
        is_error = true;

        break;
      }
    }
  }

  is_error
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<commit_msg>Add parser functions that return `ErrorKind`<commit_after>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T>;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

#[inline]
fn header_parser(input: &[u8]) -> IResult<&[u8], &[u8], ErrorKind> {
  tag!(input, "fLaC").map_err(to_custom_error!(HeaderParser))
}

#[inline]
fn metadata_parser_(input: &[u8]) -> IResult<&[u8], Metadata, ErrorKind> {
  metadata_parser(input).map_err(to_custom_error!(Unknown))
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(10));

  if *state == ParserState::Header {
    let (i, _) = try_parse!(slice, tag!("fLaC"));

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> bool
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state    = ParserState::Header;
  let mut is_error = false;

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(_)                   => {
        is_error = true;

        break;
      }
    }
  }

  is_error
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<|endoftext|>


<commit_before>use std::io::{Result, Write};

use env::Env;
use file_saver::save_to_file;
use regex::Regex;

pub fn generate(env: &Env) {
    println!(
        "generating sys build script for {}",
        env.config.library_name
    );

    let path = env.config.target_path.join("build.rs");

    println!("Generating file {:?}", path);
    save_to_file(
        &path,
        env.config.make_backup,
        |w| generate_build_script(w, env),
    );
}

fn generate_build_script(w: &mut Write, env: &Env) -> Result<()> {
    try!(write!(
        w,
        "{}",
        r##"extern crate pkg_config;

use pkg_config::{Config, Error};
use std::env;
use std::io::prelude::*;
use std::io;
use std::process;

fn main() {
    if let Err(s) = find() {
        let _ = writeln!(io::stderr(), "{}", s);
        process::exit(1);
    }
}

fn find() -> Result<(), Error> {
"##
    ));

    let ns = env.namespaces.main();
    let regex = Regex::new(r"^lib(.+)\.so.*$").expect("Regex failed");
    let shared_libs: Vec<_> = ns.shared_libs
        .iter()
        .map(|s| regex.replace(s, "\"$1\""))
        .collect();

    try!(writeln!(
        w,
        "\tlet package_name = \"{}\";",
        ns.package_name
            .as_ref()
            .expect("Package name doesn't exist")
    ));
    try!(writeln!(
        w,
        "\tlet shared_libs = [{}];",
        shared_libs.join(", ")
    ));
    try!(write!(w, "\tlet version = "));
    let versions = ns.versions
        .iter()
        .filter(|v| **v >= env.config.min_cfg_version)
        .skip(1)
        .collect::<Vec<_>>();
    for v in versions.iter().rev() {
        try!(write!(
            w,
            "if cfg!({}) {{\n\t\t\"{}\"\n\t}} else ",
            v.to_cfg(),
            v
        ));
    }
    try!(writeln!(
        w,
        "{{\n\t\t\"{}\"\n\t}};",
        env.config.min_cfg_version
    ));

    writeln!(
        w,
        "{}",
        r##"
    if let Ok(lib_dir) = env::var("GTK_LIB_DIR") {
        for lib_ in shared_libs.iter() {
            println!("cargo:rustc-link-lib=dylib={}", lib_);
        }
        println!("cargo:rustc-link-search=native={}", lib_dir);
        return Ok(())
    }

    let target = env::var("TARGET").expect("TARGET environment variable doesn't exist");
    let hardcode_shared_libs = target.contains("windows");

    let mut config = Config::new();
    config.atleast_version(version);
    if hardcode_shared_libs {
        config.cargo_metadata(false);
    }
    match config.probe(package_name) {
        Ok(library) => {
            if hardcode_shared_libs {
                for lib_ in shared_libs.iter() {
                    println!("cargo:rustc-link-lib=dylib={}", lib_);
                }
                for path in library.link_paths.iter() {
                    println!("cargo:rustc-link-search=native={}",
                             path.to_str().expect("library path doesn't exist"));
                }
            }
            Ok(())
        }
        Err(Error::EnvNoPkgConfig(_)) | Err(Error::Command { .. }) => {
            for lib_ in shared_libs.iter() {
                println!("cargo:rustc-link-lib=dylib={}", lib_);
            }
            Ok(())
        }
        Err(err) => Err(err),
    }
}
"##
    )
}
<commit_msg>Add panic when `shared-library` has an invalid form<commit_after>use std::io::{Result, Write};

use env::Env;
use file_saver::save_to_file;
use regex::Regex;

pub fn generate(env: &Env) {
    println!(
        "generating sys build script for {}",
        env.config.library_name
    );

    let path = env.config.target_path.join("build.rs");

    println!("Generating file {:?}", path);
    save_to_file(
        &path,
        env.config.make_backup,
        |w| generate_build_script(w, env),
    );
}

fn generate_build_script(w: &mut Write, env: &Env) -> Result<()> {
    try!(write!(
        w,
        "{}",
        r##"extern crate pkg_config;

use pkg_config::{Config, Error};
use std::env;
use std::io::prelude::*;
use std::io;
use std::process;

fn main() {
    if let Err(s) = find() {
        let _ = writeln!(io::stderr(), "{}", s);
        process::exit(1);
    }
}

fn find() -> Result<(), Error> {
"##
    ));

    let ns = env.namespaces.main();
    let regex = Regex::new(r"^lib(.+)\.so.*$").expect("Regex failed");
    let shared_libs: Vec<_> = ns.shared_libs
        .iter()
        .map(|s| {
            if !regex.is_match(s) {
                panic!("A 'shared-library' in the GIR file doesn't match the following form: '^lib(.+)\\.so.*$'");
            }
            regex.replace(s, "\"$1\"")
        })
        .collect();

    try!(writeln!(
        w,
        "\tlet package_name = \"{}\";",
        ns.package_name
            .as_ref()
            .expect("Package name doesn't exist")
    ));
    try!(writeln!(
        w,
        "\tlet shared_libs = [{}];",
        shared_libs.join(", ")
    ));
    try!(write!(w, "\tlet version = "));
    let versions = ns.versions
        .iter()
        .filter(|v| **v >= env.config.min_cfg_version)
        .skip(1)
        .collect::<Vec<_>>();
    for v in versions.iter().rev() {
        try!(write!(
            w,
            "if cfg!({}) {{\n\t\t\"{}\"\n\t}} else ",
            v.to_cfg(),
            v
        ));
    }
    try!(writeln!(
        w,
        "{{\n\t\t\"{}\"\n\t}};",
        env.config.min_cfg_version
    ));

    writeln!(
        w,
        "{}",
        r##"
    if let Ok(lib_dir) = env::var("GTK_LIB_DIR") {
        for lib_ in shared_libs.iter() {
            println!("cargo:rustc-link-lib=dylib={}", lib_);
        }
        println!("cargo:rustc-link-search=native={}", lib_dir);
        return Ok(())
    }

    let target = env::var("TARGET").expect("TARGET environment variable doesn't exist");
    let hardcode_shared_libs = target.contains("windows");

    let mut config = Config::new();
    config.atleast_version(version);
    if hardcode_shared_libs {
        config.cargo_metadata(false);
    }
    match config.probe(package_name) {
        Ok(library) => {
            if hardcode_shared_libs {
                for lib_ in shared_libs.iter() {
                    println!("cargo:rustc-link-lib=dylib={}", lib_);
                }
                for path in library.link_paths.iter() {
                    println!("cargo:rustc-link-search=native={}",
                             path.to_str().expect("library path doesn't exist"));
                }
            }
            Ok(())
        }
        Err(Error::EnvNoPkgConfig(_)) | Err(Error::Command { .. }) => {
            for lib_ in shared_libs.iter() {
                println!("cargo:rustc-link-lib=dylib={}", lib_);
            }
            Ok(())
        }
        Err(err) => Err(err),
    }
}
"##
    )
}
<|endoftext|>