<commit_before>/// The Toml Insert extensions

use toml::Value;

use tokenizer::tokenize_with_seperator;
use error::*;

pub trait TomlValueInsertExt<'doc> {

    /// Extension function for inserting a value in the current toml::Value document
    /// using a custom seperator.
    ///
    /// For difference to TomlSetExt::set() and friends, read [#semantics].
    ///
    /// # Semantics
    ///
    /// The function automatically creates intermediate data structures based on the query string.
    /// That means, if the query string is `"a.b.c.[0]"`, but only a table `"a"` exists in the
    /// document, the function automatically creates a table `"b"` inside `"a"` and `"c"` inside
    /// `"b"`, and an array in `"c"`. The array index is ignored if the array is created.
    ///
    /// If an Array exists, but the specified index is larger than the last index, the array will
    /// be expanded by one element: If the array has a length of 3, but the query string specifies
    /// that the element should be put at 1000, the function ignores the large index and simply
    /// appends the value to the index.
    ///
    /// # Return value
    ///
    /// If the insert operation worked correctly, `Ok(None)` is returned.
    /// If the insert operation replaced an existing value `Ok(Some(old_value))` is returned
    /// On failure, `Err(e)` is returned
    ///
    fn insert_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>>;

    /// Extension function for inserting a value from the current toml::Value document
    ///
    /// See documentation of `TomlValueinsertExt::insert_with_seperator`
    fn insert(&mut self, query: &String, value: Value) -> Result<Option<Value>> {
        self.insert_with_seperator(query, '.', value)
    }

}

impl<'doc> TomlValueInsertExt<'doc> for Value {

    fn insert_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>> {
        use resolver::mut_resolver::resolve;

        unimplemented!()
    }

}

#[cfg(test)]
mod test {
    use super::*;
    use error::*;
    use toml::Value;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_insert_with_seperator_into_table() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let table = t.get("table");
                assert!(table.is_some());

                let table = table.unwrap();
                assert!(is_match!(table, &Value::Table(_)));
                match table {
                    &Value::Table(ref t) => {
                        assert!(!t.is_empty());

                        let a = t.get("a");
                        assert!(a.is_some());

                        let a = a.unwrap();
                        assert!(is_match!(a, &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_insert_with_seperator_into_array() {
        use std::ops::Index;

        let mut toml : Value = toml_from_str(r#"
        array = []
        "#).unwrap();

        let res = toml.insert_with_seperator(&String::from("array.[0]"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let array = t.get("array");
                assert!(array.is_some());

                let array = array.unwrap();
                assert!(is_match!(array, &Value::Array(_)));
                match array {
                    &Value::Array(ref a) => {
                        assert!(!a.is_empty());
                        assert!(is_match!(a.index(0), &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

}

<commit_msg>Add test of nested tables<commit_after>/// The Toml Insert extensions

use toml::Value;

use tokenizer::tokenize_with_seperator;
use error::*;

pub trait TomlValueInsertExt<'doc> {

    /// Extension function for inserting a value in the current toml::Value document
    /// using a custom seperator.
    ///
    /// For difference to TomlSetExt::set() and friends, read [#semantics].
    ///
    /// # Semantics
    ///
    /// The function automatically creates intermediate data structures based on the query string.
    /// That means, if the query string is `"a.b.c.[0]"`, but only a table `"a"` exists in the
    /// document, the function automatically creates a table `"b"` inside `"a"` and `"c"` inside
    /// `"b"`, and an array in `"c"`. The array index is ignored if the array is created.
    ///
    /// If an Array exists, but the specified index is larger than the last index, the array will
    /// be expanded by one element: If the array has a length of 3, but the query string specifies
    /// that the element should be put at 1000, the function ignores the large index and simply
    /// appends the value to the index.
    ///
    /// # Return value
    ///
    /// If the insert operation worked correctly, `Ok(None)` is returned.
    /// If the insert operation replaced an existing value `Ok(Some(old_value))` is returned
    /// On failure, `Err(e)` is returned
    ///
    fn insert_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>>;

    /// Extension function for inserting a value from the current toml::Value document
    ///
    /// See documentation of `TomlValueinsertExt::insert_with_seperator`
    fn insert(&mut self, query: &String, value: Value) -> Result<Option<Value>> {
        self.insert_with_seperator(query, '.', value)
    }

}

impl<'doc> TomlValueInsertExt<'doc> for Value {

    fn insert_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>> {
        use resolver::mut_resolver::resolve;

        unimplemented!()
    }

}

#[cfg(test)]
mod test {
    use super::*;
    use error::*;
    use toml::Value;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_insert_with_seperator_into_table() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let table = t.get("table");
                assert!(table.is_some());

                let table = table.unwrap();
                assert!(is_match!(table, &Value::Table(_)));
                match table {
                    &Value::Table(ref t) => {
                        assert!(!t.is_empty());

                        let a = t.get("a");
                        assert!(a.is_some());

                        let a = a.unwrap();
                        assert!(is_match!(a, &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_insert_with_seperator_into_array() {
        use std::ops::Index;

        let mut toml : Value = toml_from_str(r#"
        array = []
        "#).unwrap();

        let res = toml.insert_with_seperator(&String::from("array.[0]"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let array = t.get("array");
                assert!(array.is_some());

                let array = array.unwrap();
                assert!(is_match!(array, &Value::Array(_)));
                match array {
                    &Value::Array(ref a) => {
                        assert!(!a.is_empty());
                        assert!(is_match!(a.index(0), &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_insert_with_seperator_into_nested_table() {
        let mut toml : Value = toml_from_str(r#"
        [a.b.c]
        "#).unwrap();

        let res = toml.insert_with_seperator(&String::from("a.b.c.d"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref outer) => {
                assert!(!outer.is_empty());
                let a_tab = outer.get("a");
                assert!(a_tab.is_some());

                let a_tab = a_tab.unwrap();
                assert!(is_match!(a_tab, &Value::Table(_)));
                match a_tab {
                    &Value::Table(ref a) => {
                        assert!(!a.is_empty());

                        let b_tab = a.get("b");
                        assert!(b_tab.is_some());

                        let b_tab = b_tab.unwrap();
                        assert!(is_match!(b_tab, &Value::Table(_)));
                        match b_tab {
                            &Value::Table(ref b) => {
                                assert!(!b.is_empty());

                                let c_tab = b.get("c");
                                assert!(c_tab.is_some());

                                let c_tab = c_tab.unwrap();
                                assert!(is_match!(c_tab, &Value::Table(_)));
                                match c_tab {
                                    &Value::Table(ref c) => {
                                        assert!(!c.is_empty());

                                        let d = c.get("d");
                                        assert!(d.is_some());

                                        let d = d.unwrap();
                                        assert!(is_match!(d, &Value::Integer(1)));
                                    },
                                    _ => panic!("What just happenend?"),
                                }
                            },
                            _ => panic!("What just happenend?"),
                        }
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happened?"),
        }
    }

}

<|endoftext|>


<commit_before>// Copyright 2016 Pierre Marijon.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! GFF format reading and writing.
//!
//! # Example
//!
//! ```
//! use std::io;
//! use bio::io::gff;
//! let reader = gff::Reader::new(io::stdin());
//! ```

use std::io;
use std::fs;
use std::fmt;
use std::path::Path;
use std::convert::AsRef;

use csv;

/// A GFF reader.
pub struct Reader<R: io::Read> {
    inner: csv::Reader<R>,
}

impl Reader<fs::File> {
    /// Read FASTA from given file path.
    pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::open(path).map(Reader::new)
    }
}

impl<R: io::Read> Reader<R> {
    /// Create a new Fasta reader given an instance of `io::Read`.
    pub fn new(reader: R) -> Self {
        Reader {
            inner: csv::Reader::from_reader(reader).delimiter(b'\t').has_headers(false)
        }
    }

    /// Iterate over all records.
    pub fn records(&mut self) -> Records<R> {
        Records { inner: self.inner.decode() }
    }
}

/// A GFF record.
pub struct Records<'a, R: 'a + io::Read> {
    inner: csv::DecodedRecords<'a, R, (String, String, String, u64, u64, String, String, String, String)>,
}

impl<'a, R: io::Read> Iterator for Records<'a, R> {
    type Item = csv::Result<Record>;

    fn next(&mut self) -> Option<csv::Result<Record>> {
        self.inner.next().map(|res| {
            res.map(|(sequence, source, type_name, start, end, score, strand, frame, attributes)| {
                Record {
                    sequence: sequence,
                    source: source,
                    type_name: type_name,
                    start: start,
                    end: end,
                    score: score,
                    strand: strand,
                    frame: frame,
                    attributes: attributes,
                }
            })
        })
    }
}

/// A GFF writer.
pub struct Writer<W: io::Write> {
    inner: csv::Writer<W>,
}

impl Writer<fs::File> {
    /// Write to a given file path.
    pub fn to_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::create(path).map(Writer::new)
    }
}

impl<W: io::Write> Writer<W> {
    /// Write to a given writer.
    pub fn new(writer: W) -> Self {
        Writer { inner: csv::Writer::from_writer(writer).delimiter(b'\t').flexible(true) }
    }

    /// Write a given GFF record.
    pub fn write(&mut self, record: Record) -> csv::Result<()> {
        self.inner.encode(record)
    }
}

/// A GFF record
#[derive(RustcEncodable)]
pub struct Record {
    sequence: String,
    source: String,
    type_name: String,
    start: u64,
    end: u64,
    score: String,
    strand: String,
    frame: String,
    attributes: String,
}

impl Record {
    /// Create a new GFF record.
    pub fn new() -> Self {
        Record {
            sequence: "".to_owned(),
            source: "".to_owned(),
            type_name: "".to_owned(),
            start: 0,
            end: 0,
            score: ".".to_owned(),
            strand: ".".to_owned(),
            frame: "".to_owned(),
            attributes: "".to_owned(),
        }
    }

    /// Sequence of the feature.
    pub fn sequence(&self) -> &str {
        &self.sequence
    }

    /// Source of the feature.
    pub fn source(&self) -> &str {
        &self.source
    }

    /// Type name of the feature.
    pub fn type_name(&self) -> &str {
        &self.type_name
    }

    /// Start position of feature (1-based).
    pub fn start(&self) -> u64 {
        self.start
    }

    /// End position of feature (1-based, not included).
    pub fn end(&self) -> u64 {
        self.end
    }

    /// Score of feature
    pub fn score(&self) -> Option<u64> {
        match self.score.as_ref() {
            "." => None,
            _ => self.score.parse::<u64>().ok(),
        }
    }

    /// Strand of the feature.
    pub fn strand(&self) -> Option<Strand> {
        match self.strand.as_ref() {
            "+" => Some(Strand::Forward),
            "-" => Some(Strand::Reverse),
            _ => None,
        }
    }

    /// Frame of the feature.
    pub fn frame(&self) -> &str {
        &self.frame
    }

    /// Attribute of feature
    pub fn attributes(&self) -> &str {
        &self.attributes
    }

    /// Set sequence of feature.
    pub fn set_sequence(&mut self, sequence: &str) {
        self.sequence = sequence.to_owned();
    }

    /// Set source of feature.
    pub fn set_source(&mut self, source: &str) {
        self.source = source.to_owned();
    }

    /// Set type_name of feature.
    pub fn set_type_name(&mut self, type_name: &str) {
        self.type_name = type_name.to_owned();
    }

    /// Set start of feature.
    pub fn set_start(&mut self, start: u64) {
        self.start = start;
    }

    /// Set end of feature.
    pub fn set_end(&mut self, end: u64) {
        self.end = end;
    }

    /// Set score of feature.
    pub fn set_score(&mut self, score: &str) {
        self.score = score.to_owned();
    }

    /// Set strand of feature.
    pub fn set_strand(&mut self, strand: &str) {
        self.strand = strand.to_owned();
    }
}

/// Strand information.
#[derive(Debug, PartialEq)]
pub enum Strand {
    Forward,
    Reverse,
}

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

    const GFF_FILE: &'static [u8] = b"P0A7B8\tUniProtKB\tInitiator methionine\t1\t1\t.\t.\t.\tNote=Removed
P0A7B8\tUniProtKB\tChain\t2\t176\t50\t+\t.\tID=PRO_0000148105;Note=ATP-dependent protease subunit HslV
";

    #[test]
    fn test_reader() {
        let sequence = ["P0A7B8", "P0A7B8"];
        let source = ["UniProtKB", "UniProtKB"];
        let type_name = ["Initiator methionine", "Chain"];
        let starts = [1, 2];
        let ends = [1, 176];
        let scores = [None, Some(50)];
        let strand = [None, Some(Strand::Forward)];
        let frame = [".", "."];
        let attributes = ["Note=Removed", "ID=PRO_0000148105;Note=ATP-dependent protease subunit HslV"];

        let mut reader = Reader::new(GFF_FILE);
        for (i, r) in reader.records().enumerate() {
            let record = r.ok().expect("Error reading record");
            assert_eq!(record.sequence(), sequence[i]);
            assert_eq!(record.source(), source[i]);
            assert_eq!(record.type_name(), type_name[i]);
            assert_eq!(record.start(), starts[i]);
            assert_eq!(record.end(), ends[i]);
            assert_eq!(record.score(), scores[i]);
            assert_eq!(record.strand(), strand[i]);
            assert_eq!(record.frame(), frame[i]);
            assert_eq!(record.attributes(), attributes[i]);
        }
    }

    #[test]
    fn test_writer() {
        let mut reader = Reader::new(GFF_FILE);
        let mut writer = Writer::new(vec![]);
        for r in reader.records() {
            writer.write(r.ok().expect("Error reading record")).ok().expect("Error writing record");
        }
        assert_eq!(writer.inner.as_bytes(), GFF_FILE);
    }
}
<commit_msg>Improve attributes name and correct some copy mistake in comment<commit_after>// Copyright 2016 Pierre Marijon.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! GFF format reading and writing.
//!
//! # Example
//!
//! ```
//! use std::io;
//! use bio::io::gff;
//! let reader = gff::Reader::new(io::stdin());
//! ```

use std::io;
use std::fs;
use std::path::Path;
use std::convert::AsRef;

use csv;

/// A GFF reader.
pub struct Reader<R: io::Read> {
    inner: csv::Reader<R>,
}

impl Reader<fs::File> {
    /// Read GFF from given file path.
    pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::open(path).map(Reader::new)
    }
}

impl<R: io::Read> Reader<R> {
    /// Create a new GFF reader given an instance of `io::Read`.
    pub fn new(reader: R) -> Self {
        Reader {
            inner: csv::Reader::from_reader(reader).delimiter(b'\t').has_headers(false)
        }
    }

    /// Iterate over all records.
    pub fn records(&mut self) -> Records<R> {
        Records { inner: self.inner.decode() }
    }
}

/// A GFF record.
pub struct Records<'a, R: 'a + io::Read> {
    inner: csv::DecodedRecords<'a, R, (String, String, String, u64, u64, String, String, String, String)>,
}

impl<'a, R: io::Read> Iterator for Records<'a, R> {
    type Item = csv::Result<Record>;

    fn next(&mut self) -> Option<csv::Result<Record>> {
        self.inner.next().map(|res| {
            res.map(|(seqname, source, feature_type, start, end, score, strand, frame, attributes)| {
                Record {
                    seqname: seqname,
                    source: source,
                    feature_type: feature_type,
                    start: start,
                    end: end,
                    score: score,
                    strand: strand,
                    frame: frame,
                    attributes: attributes,
                }
            })
        })
    }
}

/// A GFF writer.
pub struct Writer<W: io::Write> {
    inner: csv::Writer<W>,
}

impl Writer<fs::File> {
    /// Write to a given file path.
    pub fn to_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::create(path).map(Writer::new)
    }
}

impl<W: io::Write> Writer<W> {
    /// Write to a given writer.
    pub fn new(writer: W) -> Self {
        Writer { inner: csv::Writer::from_writer(writer).delimiter(b'\t').flexible(true) }
    }

    /// Write a given GFF record.
    pub fn write(&mut self, record: Record) -> csv::Result<()> {
        self.inner.encode(record)
    }
}

/// A GFF record
#[derive(RustcEncodable)]
pub struct Record {
    seqname: String,
    source: String,
    feature_type: String,
    start: u64,
    end: u64,
    score: String,
    strand: String,
    frame: String,
    attributes: String,
}

impl Record {
    /// Create a new GFF record.
    pub fn new() -> Self {
        Record {
            seqname: "".to_owned(),
            source: "".to_owned(),
            feature_type: "".to_owned(),
            start: 0,
            end: 0,
            score: ".".to_owned(),
            strand: ".".to_owned(),
            frame: "".to_owned(),
            attributes: "".to_owned(),
        }
    }

    /// Sequence name of the feature.
    pub fn seqname(&self) -> &str {
        &self.seqname
    }

    /// Source of the feature.
    pub fn source(&self) -> &str {
        &self.source
    }

    /// Type of the feature.
    pub fn feature_type(&self) -> &str {
        &self.feature_type
    }

    /// Start position of feature (1-based).
    pub fn start(&self) -> u64 {
        self.start
    }

    /// End position of feature (1-based, not included).
    pub fn end(&self) -> u64 {
        self.end
    }

    /// Score of feature
    pub fn score(&self) -> Option<u64> {
        match self.score.as_ref() {
            "." => None,
            _ => self.score.parse::<u64>().ok(),
        }
    }

    /// Strand of the feature.
    pub fn strand(&self) -> Option<Strand> {
        match self.strand.as_ref() {
            "+" => Some(Strand::Forward),
            "-" => Some(Strand::Reverse),
            _ => None,
        }
    }

    /// Frame of the feature.
    pub fn frame(&self) -> &str {
        &self.frame
    }

    /// Attribute of feature
    pub fn attributes(&self) -> &str {
        &self.attributes
    }

    /// Set seqname of feature.
    pub fn set_seqname(&mut self, seqname: &str) {
        self.seqname = seqname.to_owned();
    }

    /// Set source of feature.
    pub fn set_source(&mut self, source: &str) {
        self.source = source.to_owned();
    }

    /// Set type of feature.
    pub fn set_feature_type(&mut self, feature_type: &str) {
        self.feature_type = feature_type.to_owned();
    }

    /// Set start of feature.
    pub fn set_start(&mut self, start: u64) {
        self.start = start;
    }

    /// Set end of feature.
    pub fn set_end(&mut self, end: u64) {
        self.end = end;
    }

    /// Set score of feature.
    pub fn set_score(&mut self, score: &str) {
        self.score = score.to_owned();
    }

    /// Set strand of feature.
    pub fn set_strand(&mut self, strand: &str) {
        self.strand = strand.to_owned();
    }
}

/// Strand information.
#[derive(Debug, PartialEq)]
pub enum Strand {
    Forward,
    Reverse,
}

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

    const GFF_FILE: &'static [u8] = b"P0A7B8\tUniProtKB\tInitiator methionine\t1\t1\t.\t.\t.\tNote=Removed
P0A7B8\tUniProtKB\tChain\t2\t176\t50\t+\t.\tID=PRO_0000148105;Note=ATP-dependent protease subunit HslV
";

    #[test]
    fn test_reader() {
        let seqname = ["P0A7B8", "P0A7B8"];
        let source = ["UniProtKB", "UniProtKB"];
        let feature_type = ["Initiator methionine", "Chain"];
        let starts = [1, 2];
        let ends = [1, 176];
        let scores = [None, Some(50)];
        let strand = [None, Some(Strand::Forward)];
        let frame = [".", "."];
        let attributes = ["Note=Removed", "ID=PRO_0000148105;Note=ATP-dependent protease subunit HslV"];

        let mut reader = Reader::new(GFF_FILE);
        for (i, r) in reader.records().enumerate() {
            let record = r.ok().expect("Error reading record");
            assert_eq!(record.seqname(), seqname[i]);
            assert_eq!(record.source(), source[i]);
            assert_eq!(record.feature_type(), feature_type[i]);
            assert_eq!(record.start(), starts[i]);
            assert_eq!(record.end(), ends[i]);
            assert_eq!(record.score(), scores[i]);
            assert_eq!(record.strand(), strand[i]);
            assert_eq!(record.frame(), frame[i]);
            assert_eq!(record.attributes(), attributes[i]);
        }
    }

    #[test]
    fn test_writer() {
        let mut reader = Reader::new(GFF_FILE);
        let mut writer = Writer::new(vec![]);
        for r in reader.records() {
            writer.write(r.ok().expect("Error reading record")).ok().expect("Error writing record");
        }
        assert_eq!(writer.inner.as_bytes(), GFF_FILE);
    }
}
<|endoftext|>


<commit_before>use nom::multispace;
use nom::{IResult, Err, ErrorKind, Needed};
use std::str;

use common::{field_list, statement_terminator, table_reference, value_list};

#[derive(Clone, Debug, Default, PartialEq)]
pub struct InsertStatement {
    pub table: String,
    pub fields: Vec<String>,
}

/// Parse rule for a SQL insert query.
/// TODO(malte): support REPLACE, multiple parens expr, nested selection, DEFAULT VALUES
named!(pub insertion<&[u8], InsertStatement>,
    dbg_dmp!(chain!(
        caseless_tag!("insert") ~
        multispace ~
        caseless_tag!("into") ~
        multispace ~
        table: table_reference ~
        multispace ~
        caseless_tag!("values") ~
        multispace ~
        tag!("(") ~
        values: value_list ~
        tag!(")") ~
        statement_terminator,
        || {
            InsertStatement {
                table: String::from(table),
                fields: fields.iter().map(|s| String::from(*s)).collect(),
            }
        }
    ))
);

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

    #[test]
    fn simple_insert() {
        let qstring = "INSERT INTO users VALUES (42, test);";

        let res = insertion(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   InsertStatement {
                       table: String::from("users"),
                       fields: vec!["42".into(), "test".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn placeholder_insert() {
        let qstring = "INSERT INTO users VALUES (?, ?);";

        let res = insertion(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   InsertStatement {
                       table: String::from("users"),
                       fields: vec!["?".into(), "?".into()],
                       ..Default::default()
                   });
    }
}
<commit_msg>Support field names in INSERT query<commit_after>use nom::multispace;
use nom::{IResult, Err, ErrorKind, Needed};
use std::str;

use common::{field_list, statement_terminator, table_reference, value_list};

#[derive(Clone, Debug, Default, PartialEq)]
pub struct InsertStatement {
    pub table: String,
    pub fields: Vec<(String, String)>,
}

/// Parse rule for a SQL insert query.
/// TODO(malte): support REPLACE, multiple parens expr, nested selection, DEFAULT VALUES
named!(pub insertion<&[u8], InsertStatement>,
    chain!(
        caseless_tag!("insert") ~
        multispace ~
        caseless_tag!("into") ~
        multispace ~
        table: table_reference ~
        multispace ~
        fields: opt!(chain!(
                tag!("(") ~
                fields: field_list ~
                tag!(")") ~
                multispace,
                || { fields }
                )
            ) ~
        caseless_tag!("values") ~
        multispace ~
        tag!("(") ~
        values: value_list ~
        tag!(")") ~
        statement_terminator,
        || {
            InsertStatement {
                table: String::from(table),
                fields: match fields {
                    Some(ref f) =>
                        f.iter()
                         .map(|s| String::from(*s))
                         .zip(values.into_iter()
                                    .map(|s| String::from(s))
                                    )
                         .collect(),
                    None =>
                        values.into_iter()
                              .enumerate()
                              .map(|(i, v)| (format!("{}", i), String::from(v)))
                              .collect(),
                },
            }
        }
    )
);

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

    #[test]
    fn simple_insert() {
        let qstring = "INSERT INTO users VALUES (42, test);";

        let res = insertion(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   InsertStatement {
                       table: String::from("users"),
                       fields: vec![("0".into(), "42".into()), ("1".into(), "test".into())],
                       ..Default::default()
                   });
    }

    #[test]
    fn placeholder_insert() {
        let qstring = "INSERT INTO users VALUES (?, ?);";

        let res = insertion(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   InsertStatement {
                       table: String::from("users"),
                       fields: vec![("0".into(), "?".into()), ("1".into(), "?".into())],
                       ..Default::default()
                   });
    }

    #[test]
    fn insert_with_field_names() {
        let qstring = "INSERT INTO users (id, name) VALUES (42, test);";

        let res = insertion(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   InsertStatement {
                       table: String::from("users"),
                       fields: vec![("id".into(), "42".into()), ("name".into(), "test".into())],
                       ..Default::default()
                   });
    }
}
<|endoftext|>


<commit_before>//! Saving and loading data to and from disk.
//!
//! # HDF5
//!
//! The recommended way to save/load data in Numeric is using HDF5.
//!
//! **Note:** The HDF5 library will by default not be thread-safe (it depends on how you compiled
//! it), so do not call either of these functions concurrently.
//!
//! ##Saving to an HDF5 file:
//!
//! ```no_run
//! use std::path::Path;
//! use numeric::Tensor;
//!
//! let path = Path::new("output.h5");
//! let t: Tensor<i32> = Tensor::range(100);
//! let ret = t.save_hdf5(&path);
//! ```
//! The data will be saved to the group `/data`. Now, we can load this using:
//!
//! ## Loading from HDF5 file
//!
//! Now, we can load this file:
//!
//! ```no_run
//! use std::path::Path;
//! use numeric::Tensor;
//!
//! let path = Path::new("output.h5");
//! let t = match numeric::io::load_hdf5_as_f64(&path, "/data") {
//!     Ok(v) => v,
//!     Err(e) => panic!("Failed: {}", e),
//! };
//! ```
//!
//! Note that since we need to know the type of `t` at compile time, it doesn't matter that we
//! saved the file as `i32`, we have to specify how to load it. The way this is done is that it
//! will load the `i32` natively and then convert it to `f64`. If your data converted, you simply
//! have to load it as the same type as you know is in the file.

extern crate std;

use libc::{c_char, c_void, c_ulonglong, c_int};
use std::path::Path;
use hdf5_sys as ffi;

use tensor::Tensor;

#[allow(non_camel_case_types)]
type hsize_t = c_ulonglong;
#[allow(non_camel_case_types)]
type hid_t = c_int;

extern fn error_handler(_: hid_t, _: *const c_void) {
    // Suppress errors. We will rely on return statuses alone.
}

macro_rules! add_save {
    ($t:ty, $h5type:expr) => (
        impl Tensor<$t> {
            /// Saves tensor to an HDF5 file.
            ///
            /// **Warning**: This function is not thread-safe (unless you compiled HDF5 to be
            /// thread-safe). Do no call this function concurrently from multiple threads.
            pub fn save_hdf5(&self, path: &Path) -> std::io::Result<()> {
                let filename = match path.to_str() {
                    Some(v) => v,
                    None => {
                        let err = std::io::Error::new(std::io::ErrorKind::InvalidInput, format!("Path could not be converted to string: {:?}", path));
                        return Err(err);
                    },
                };
                // This could be made an option
                let group = "data";

                unsafe {
                    let filename_cstr = try!(::std::ffi::CString::new(filename));
                    let group_cstr = try!(::std::ffi::CString::new(group));

                    //ffi::H5Eset_auto2(0, error_handler, 0 as *const c_void);

                    let file = ffi::H5Fcreate(filename_cstr.as_ptr() as *const c_char,
                                   ffi::H5F_ACC_TRUNC, ffi::H5P_DEFAULT, ffi::H5P_DEFAULT);

                    let mut shape: Vec<u64> = Vec::new();
                    for s in self.shape().iter() {
                        shape.push(*s as u64);
                    }

                    let space = ffi::H5Screate_simple(shape.len() as i32, shape.as_ptr(), std::ptr::null());

                    let dset = ffi::H5Dcreate2(file, group_cstr.as_ptr() as *const c_char,
                                               $h5type, space,
                                               ffi::H5P_DEFAULT,
                                               ffi::H5P_DEFAULT,
                                               ffi::H5P_DEFAULT);

                    let status = ffi::H5Dwrite(dset, $h5type, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                               self.as_ptr() as * const c_void);

                    if status < 0 {
                        let err = std::io::Error::new(std::io::ErrorKind::Other,
                                                      format!("Failed to write '{}': {:?}", group, path));
                        return Err(err);
                    }

                    ffi::H5Dclose(dset);
                    ffi::H5Fclose(file);
                }
                Ok(())
            }
        }
    )
}

add_save!(u8, ffi::H5T_NATIVE_UINT8);
add_save!(u16, ffi::H5T_NATIVE_UINT16);
add_save!(u32, ffi::H5T_NATIVE_UINT32);
add_save!(u64, ffi::H5T_NATIVE_UINT64);
add_save!(i8, ffi::H5T_NATIVE_INT8);
add_save!(i16, ffi::H5T_NATIVE_INT16);
add_save!(i32, ffi::H5T_NATIVE_INT32);
add_save!(i64, ffi::H5T_NATIVE_INT64);
add_save!(f32, ffi::H5T_NATIVE_FLOAT);
add_save!(f64, ffi::H5T_NATIVE_DOUBLE);

macro_rules! add_load {
    ($name:ident, $t:ty) => (
        /// Load HDF5 file and convert to specified type.
        pub fn $name(path: &Path, group: &str) -> std::io::Result<Tensor<$t>> {
            let filename = match path.to_str() {
                Some(v) => v,
                None => {
                    let err = std::io::Error::new(std::io::ErrorKind::InvalidInput, format!("Path could not be converted to string: {:?}", path));
                    return Err(err);
                },
            };
            unsafe {
                let filename_cstr = try!(::std::ffi::CString::new(filename));
                let group_cstr = try!(::std::ffi::CString::new(group));

                ffi::H5Eset_auto2(0, error_handler, 0 as *const c_void);

                let file = ffi::H5Fopen(filename_cstr.as_ptr() as *const c_char,
                               ffi::H5F_ACC_RDONLY, ffi::H5P_DEFAULT);

                if file < 0 {
                    let err = std::io::Error::new(std::io::ErrorKind::NotFound, format!("File not found: {:?}", path));
                    return Err(err);
                }

                let dset = ffi::H5Dopen2(file, group_cstr.as_ptr() as *const c_char,
                                        ffi::H5P_DEFAULT);

                if dset < 0 {
                    let err = std::io::Error::new(std::io::ErrorKind::NotFound, format!("Group '{}' not found: {}", group, filename));
                    return Err(err);
                }

                let datatype = ffi::H5Dget_type(dset);

                let space = ffi::H5Dget_space(dset);
                let ndims = ffi::H5Sget_simple_extent_ndims(space);

                let mut shape: Tensor<hsize_t> = Tensor::zeros(&[ndims as usize]);

                if ffi::H5Sget_simple_extent_dims(space, shape.as_mut_ptr(), 0 as *mut hsize_t) != ndims {
                    let err = std::io::Error::new(std::io::ErrorKind::InvalidData, format!("Could not read shape of tesor: {}", filename));
                    return Err(err);
                }

                //let unsigned_shape: Vec<usize> = shape.iter().map(|x| x as usize).collect();
                let unsigned_tensor = shape.convert::<usize>();
                let unsigned_shape = &unsigned_tensor.data();

                let data: Tensor<$t> = {
                    if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_UINT8) == 1 {
                        let mut native_data: Tensor<u8> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_UINT8, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_INT8) == 1 {
                        let mut native_data: Tensor<i8> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_INT8, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_UINT16) == 1 {
                        let mut native_data: Tensor<u16> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_UINT16, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_INT16) == 1 {
                        let mut native_data: Tensor<i16> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_INT16, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_UINT32) == 1 {
                        let mut native_data: Tensor<u32> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_UINT32, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_INT32) == 1 {
                        let mut native_data: Tensor<i32> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_INT32, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_UINT64) == 1 {
                        let mut native_data: Tensor<u64> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_UINT64, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_INT64) == 1 {
                        let mut native_data: Tensor<i64> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_INT64, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_FLOAT) == 1 {
                        let mut native_data: Tensor<f32> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_FLOAT, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_DOUBLE) == 1 {
                        let mut native_data: Tensor<f64> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_DOUBLE, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else {
                        let err = std::io::Error::new(std::io::ErrorKind::InvalidData, format!("Unable to convert '{}' to {}: {}", group, "f64", filename));
                        return Err(err);
                    }
                };

                ffi::H5Tclose(datatype);
                ffi::H5Dclose(dset);
                ffi::H5Fclose(file);

                Ok(data)
            }
        }
    )
}

add_load!(load_hdf5_as_u8, u8);
add_load!(load_hdf5_as_u16, u16);
add_load!(load_hdf5_as_u32, u32);
add_load!(load_hdf5_as_u64, u64);
add_load!(load_hdf5_as_i8, i8);
add_load!(load_hdf5_as_i16, i16);
add_load!(load_hdf5_as_i32, i32);
add_load!(load_hdf5_as_i64, i64);
add_load!(load_hdf5_as_f32, f32);
add_load!(load_hdf5_as_f64, f64);
add_load!(load_hdf5_as_isize, isize);
add_load!(load_hdf5_as_usize, usize);
<commit_msg>DOC: Minor tweak<commit_after>//! Saving and loading data to and from disk.
//!
//! # HDF5
//!
//! The recommended way to save/load data in Numeric is using HDF5.
//!
//! **Note:** The HDF5 library will by default not be thread-safe (it depends on how you compiled
//! it), so do not call either of these functions concurrently.
//!
//! ##Saving to HDF5 file:
//!
//! ```no_run
//! use std::path::Path;
//! use numeric::Tensor;
//!
//! let path = Path::new("output.h5");
//! let t: Tensor<i32> = Tensor::range(100);
//! let ret = t.save_hdf5(&path);
//! ```
//! The data will be saved to the group `/data`.
//!
//! ## Loading from HDF5 file
//!
//! Now, we can load this file:
//!
//! ```no_run
//! use std::path::Path;
//! use numeric::Tensor;
//!
//! let path = Path::new("output.h5");
//! let t = match numeric::io::load_hdf5_as_f64(&path, "/data") {
//!     Ok(v) => v,
//!     Err(e) => panic!("Failed: {}", e),
//! };
//! ```
//!
//! Note that since we need to know the type of `t` at compile time, it doesn't matter that we
//! saved the file as `i32`, we have to specify how to load it. The way this is done is that it
//! will load the `i32` natively and then convert it to `f64`. If your data converted, you simply
//! have to load it as the same type as you know is in the file.

extern crate std;

use libc::{c_char, c_void, c_ulonglong, c_int};
use std::path::Path;
use hdf5_sys as ffi;

use tensor::Tensor;

#[allow(non_camel_case_types)]
type hsize_t = c_ulonglong;
#[allow(non_camel_case_types)]
type hid_t = c_int;

extern fn error_handler(_: hid_t, _: *const c_void) {
    // Suppress errors. We will rely on return statuses alone.
}

macro_rules! add_save {
    ($t:ty, $h5type:expr) => (
        impl Tensor<$t> {
            /// Saves tensor to an HDF5 file.
            ///
            /// **Warning**: This function is not thread-safe (unless you compiled HDF5 to be
            /// thread-safe). Do no call this function concurrently from multiple threads.
            pub fn save_hdf5(&self, path: &Path) -> std::io::Result<()> {
                let filename = match path.to_str() {
                    Some(v) => v,
                    None => {
                        let err = std::io::Error::new(std::io::ErrorKind::InvalidInput, format!("Path could not be converted to string: {:?}", path));
                        return Err(err);
                    },
                };
                // This could be made an option
                let group = "data";

                unsafe {
                    let filename_cstr = try!(::std::ffi::CString::new(filename));
                    let group_cstr = try!(::std::ffi::CString::new(group));

                    //ffi::H5Eset_auto2(0, error_handler, 0 as *const c_void);

                    let file = ffi::H5Fcreate(filename_cstr.as_ptr() as *const c_char,
                                   ffi::H5F_ACC_TRUNC, ffi::H5P_DEFAULT, ffi::H5P_DEFAULT);

                    let mut shape: Vec<u64> = Vec::new();
                    for s in self.shape().iter() {
                        shape.push(*s as u64);
                    }

                    let space = ffi::H5Screate_simple(shape.len() as i32, shape.as_ptr(), std::ptr::null());

                    let dset = ffi::H5Dcreate2(file, group_cstr.as_ptr() as *const c_char,
                                               $h5type, space,
                                               ffi::H5P_DEFAULT,
                                               ffi::H5P_DEFAULT,
                                               ffi::H5P_DEFAULT);

                    let status = ffi::H5Dwrite(dset, $h5type, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                               self.as_ptr() as * const c_void);

                    if status < 0 {
                        let err = std::io::Error::new(std::io::ErrorKind::Other,
                                                      format!("Failed to write '{}': {:?}", group, path));
                        return Err(err);
                    }

                    ffi::H5Dclose(dset);
                    ffi::H5Fclose(file);
                }
                Ok(())
            }
        }
    )
}

add_save!(u8, ffi::H5T_NATIVE_UINT8);
add_save!(u16, ffi::H5T_NATIVE_UINT16);
add_save!(u32, ffi::H5T_NATIVE_UINT32);
add_save!(u64, ffi::H5T_NATIVE_UINT64);
add_save!(i8, ffi::H5T_NATIVE_INT8);
add_save!(i16, ffi::H5T_NATIVE_INT16);
add_save!(i32, ffi::H5T_NATIVE_INT32);
add_save!(i64, ffi::H5T_NATIVE_INT64);
add_save!(f32, ffi::H5T_NATIVE_FLOAT);
add_save!(f64, ffi::H5T_NATIVE_DOUBLE);

macro_rules! add_load {
    ($name:ident, $t:ty) => (
        /// Load HDF5 file and convert to specified type.
        pub fn $name(path: &Path, group: &str) -> std::io::Result<Tensor<$t>> {
            let filename = match path.to_str() {
                Some(v) => v,
                None => {
                    let err = std::io::Error::new(std::io::ErrorKind::InvalidInput, format!("Path could not be converted to string: {:?}", path));
                    return Err(err);
                },
            };
            unsafe {
                let filename_cstr = try!(::std::ffi::CString::new(filename));
                let group_cstr = try!(::std::ffi::CString::new(group));

                ffi::H5Eset_auto2(0, error_handler, 0 as *const c_void);

                let file = ffi::H5Fopen(filename_cstr.as_ptr() as *const c_char,
                               ffi::H5F_ACC_RDONLY, ffi::H5P_DEFAULT);

                if file < 0 {
                    let err = std::io::Error::new(std::io::ErrorKind::NotFound, format!("File not found: {:?}", path));
                    return Err(err);
                }

                let dset = ffi::H5Dopen2(file, group_cstr.as_ptr() as *const c_char,
                                        ffi::H5P_DEFAULT);

                if dset < 0 {
                    let err = std::io::Error::new(std::io::ErrorKind::NotFound, format!("Group '{}' not found: {}", group, filename));
                    return Err(err);
                }

                let datatype = ffi::H5Dget_type(dset);

                let space = ffi::H5Dget_space(dset);
                let ndims = ffi::H5Sget_simple_extent_ndims(space);

                let mut shape: Tensor<hsize_t> = Tensor::zeros(&[ndims as usize]);

                if ffi::H5Sget_simple_extent_dims(space, shape.as_mut_ptr(), 0 as *mut hsize_t) != ndims {
                    let err = std::io::Error::new(std::io::ErrorKind::InvalidData, format!("Could not read shape of tesor: {}", filename));
                    return Err(err);
                }

                //let unsigned_shape: Vec<usize> = shape.iter().map(|x| x as usize).collect();
                let unsigned_tensor = shape.convert::<usize>();
                let unsigned_shape = &unsigned_tensor.data();

                let data: Tensor<$t> = {
                    if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_UINT8) == 1 {
                        let mut native_data: Tensor<u8> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_UINT8, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_INT8) == 1 {
                        let mut native_data: Tensor<i8> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_INT8, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_UINT16) == 1 {
                        let mut native_data: Tensor<u16> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_UINT16, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_INT16) == 1 {
                        let mut native_data: Tensor<i16> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_INT16, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_UINT32) == 1 {
                        let mut native_data: Tensor<u32> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_UINT32, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_INT32) == 1 {
                        let mut native_data: Tensor<i32> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_INT32, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_UINT64) == 1 {
                        let mut native_data: Tensor<u64> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_UINT64, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_INT64) == 1 {
                        let mut native_data: Tensor<i64> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_INT64, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_FLOAT) == 1 {
                        let mut native_data: Tensor<f32> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_FLOAT, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else if ffi::H5Tequal(datatype, ffi::H5T_NATIVE_DOUBLE) == 1 {
                        let mut native_data: Tensor<f64> = Tensor::empty(&unsigned_shape[..]);
                        // Finally load the actual data
                        ffi::H5Dread(dset, ffi::H5T_NATIVE_DOUBLE, ffi::H5S_ALL, ffi::H5S_ALL, ffi::H5P_DEFAULT,
                                     native_data.as_mut_ptr() as *mut c_void);
                        native_data.convert::<$t>()
                    } else {
                        let err = std::io::Error::new(std::io::ErrorKind::InvalidData, format!("Unable to convert '{}' to {}: {}", group, "f64", filename));
                        return Err(err);
                    }
                };

                ffi::H5Tclose(datatype);
                ffi::H5Dclose(dset);
                ffi::H5Fclose(file);

                Ok(data)
            }
        }
    )
}

add_load!(load_hdf5_as_u8, u8);
add_load!(load_hdf5_as_u16, u16);
add_load!(load_hdf5_as_u32, u32);
add_load!(load_hdf5_as_u64, u64);
add_load!(load_hdf5_as_i8, i8);
add_load!(load_hdf5_as_i16, i16);
add_load!(load_hdf5_as_i32, i32);
add_load!(load_hdf5_as_i64, i64);
add_load!(load_hdf5_as_f32, f32);
add_load!(load_hdf5_as_f64, f64);
add_load!(load_hdf5_as_isize, isize);
add_load!(load_hdf5_as_usize, usize);
<|endoftext|>


<commit_before>//! Traits, helpers, and type definitions for Tokio I/O & non-blocking IO
//! functionality.
//!
//! # Readiness
//!
//! A source is **ready** when performing an operation has a high likelihood
//! (but not a guarantee) of successfully making progress.
//!
//! For example, a TCP socket is ready to perform a read operation when the
//! internal buffer has pending bytes. The same socket is ready to perform a
//! write when its write buffer is not full.
//!
//! The `Readiness` trait represents this concept. The `Readiness` trait also
//! acts as a marker trait to denotate types which are *Tokio aware*. A Tokio
//! aware type is able to observe usage and signal interest to the `Reactor`.
//!
//! In the case of `TcpStream`, the Tokio aware TCP socket, when
//! `TcpStream::try_read` is called and `Ok(None)` is returned, read interest
//! is automatically registered with the reactor an associated with the
//! currently running task. The logic being that, by trying to read from the
//! socket, the current task has indicated that read readiness is required for
//! the task to make progress. Once the TCP socket becomes read ready, the
//! task's `tick` function is called again, and this time a call to
//! `TcpStream::try_read` will (most likely) read some bytes OR result in an
//! error.
//!
//! # Transport
//!
//! A typed stream that may be read from and written to without blocking.
//!
//! A `Transport` does protocol specific serialization / deserialization. It
//! usually is composed of some lower level source, for example a TCP Stream
//! and reads / writes protocol frames.
//!
//! For example, imagine a protocol that is UTF-8 string based and framed with
//! new lines, aka each message is terminated by "\n". The transport would look
//! something like:
//!
//! ```rust,no_run
//! use tokio::io::{TryRead, TryWrite, Readiness, Transport};
//! use std::io;
//!
//! struct LineTransport<T> {
//!     source: T,
//!     rd: Vec<u8>,
//!     wr: Vec<u8>,
//! }
//!
//! impl<T: TryRead + TryWrite + Readiness> Transport for LineTransport<T> {
//!     type In = String;
//!     type Out = String;
//!
//!     fn read(&mut self) -> io::Result<Option<String>> {
//!         loop {
//!             // First, try to parse a new line from what was buffered
//!             if let Some(line) = parse_new_line(&mut self.rd) {
//!                 return Ok(Some(line));
//!             }
//!         }
//!     }
//!
//!     fn write(&mut self, req: String) -> io::Result<Option<()>> {
//!         // Append the message to the buffer
//!         self.wr.append(&mut req.into_bytes());
//!         self.flush()
//!     }
//!
//!     fn flush(&mut self) -> io::Result<Option<()>> {
//!         while !self.wr.is_empty() {
//!             match try!(self.source.try_write(&mut self.wr)) {
//!                 Some(n) => shift(&mut self.wr, n),
//!                 None => return Ok(None),
//!             }
//!         }
//!
//!         Ok(Some(()))
//!     }
//! }
//!
//! impl<T: Readiness> Readiness for LineTransport<T> {
//!     fn is_readable(&self) -> bool {
//!         self.rd.contains(&b'\n') || self.source.is_readable()
//!     }
//!
//!     fn is_writable(&self) -> bool {
//!         // The source is always writable since we don't cap the write
//!         // buffer size. Not an ideal production behavior...
//!         true
//!     }
//! }
//!
//! fn parse_new_line(buf: &mut Vec<u8>) -> Option<String> {
//!     // Search for "\n", if found, read everything from the start of the
//!     // buffer to the newline as a string then shift all bytes after the
//!     // newline to the beginning of the buffer.
//!     unimplemented!();
//! }
//!
//! fn shift(buf: &mut Vec<u8>, n: usize) {
//!     // Drop the first `n` bytes in the buffer and move all bytes after that
//!     // point to the front of the buffer.
//! }
//! ```

mod framing;
mod ready;
mod stream;
mod transport;

pub use self::framing::{Framed, Parse, Serialize};
pub use self::ready::{Readiness, Ready};
pub use self::stream::Stream;
pub use self::transport::Transport;

use bytes::{Buf, MutBuf, ReadExt, WriteExt};
use std::io;

/// A refinement of `std::io::Read` for reading from non-blocking sources.
///
/// When reading from a non-blocking source, receiving a
/// `ErrorKind::WouldBlock` is expected and not an error. A such, it is useful
/// to split out the would-block case from the other error cases.
pub trait TryRead: io::Read {

    /// Pull some bytes from this source into the specified buffer, returning
    /// how many bytes were read.
    ///
    /// If the source is not able to perform the operation due to not having
    /// any bytes to read, `Ok(None)` is returned.
    ///
    /// Aside from the signature, behavior is identical to `std::io::Read`. For
    /// more details, read the `std::io::Read` documentation.
    fn try_read(&mut self, buf: &mut [u8]) -> io::Result<Option<usize>>;

    /// Pull some bytes from this source into the specified `Buf`, returning
    /// how many bytes were read.
    fn try_read_buf<B: MutBuf>(&mut self, buf: &mut B) -> io::Result<Option<usize>>;
}

impl<T: io::Read> TryRead for T {
    fn try_read(&mut self, buf: &mut [u8]) -> io::Result<Option<usize>> {
        match self.read(buf) {
            Ok(n) => Ok(Some(n)),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
            Err(e) => Err(e),
        }
    }

    fn try_read_buf<B: MutBuf>(&mut self, buf: &mut B) -> io::Result<Option<usize>> {
        match self.read_buf(buf) {
            Ok(n) => Ok(Some(n)),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
            Err(e) => Err(e),
        }
    }
}

/// A refinement of `std::io::Write` for reading from non-blocking sources.
///
/// When reading from a non-blocking source, receiving a
/// `ErrorKind::WouldBlock` is expected and not an error. A such, it is useful
/// to split out the would-block case from the other error cases.
pub trait TryWrite: io::Write {

    /// Write a buffer into this object, returning how many bytes were written.
    ///
    /// If the source is not able to perform the operation due to not being
    /// ready, `Ok(None)` is returned.
    ///
    /// Aside from the signature, behavior is identical to `std::io::Write`.
    /// For more details, read the `std::io::Write` documentation.
    fn try_write(&mut self, buf: &[u8]) -> io::Result<Option<usize>>;

    /// Write a `Buf` into this object, returning how many bytes were written.
    fn try_write_buf<B: Buf>(&mut self, buf: &mut B) -> io::Result<Option<usize>>;

    /// Try flushing the underlying IO
    fn try_flush(&mut self) -> io::Result<Option<()>>;
}

impl<T: io::Write> TryWrite for T {
    fn try_write(&mut self, buf: &[u8]) -> io::Result<Option<usize>> {
        match self.write(buf) {
            Ok(n) => Ok(Some(n)),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
            Err(e) => Err(e),
        }
    }

    fn try_write_buf<B: Buf>(&mut self, buf: &mut B) -> io::Result<Option<usize>> {
        match self.write_buf(buf) {
            Ok(n) => Ok(Some(n)),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
            Err(e) => Err(e),
        }
    }

    fn try_flush(&mut self) -> io::Result<Option<()>> {
        match self.flush() {
            Ok(()) => Ok(Some(())),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
            Err(e) => Err(e),
        }
    }
}
<commit_msg>Fix documentation typo<commit_after>//! Traits, helpers, and type definitions for Tokio I/O & non-blocking IO
//! functionality.
//!
//! # Readiness
//!
//! A source is **ready** when performing an operation has a high likelihood
//! (but not a guarantee) of successfully making progress.
//!
//! For example, a TCP socket is ready to perform a read operation when the
//! internal buffer has pending bytes. The same socket is ready to perform a
//! write when its write buffer is not full.
//!
//! The `Readiness` trait represents this concept. The `Readiness` trait also
//! acts as a marker trait to denotate types which are *Tokio aware*. A Tokio
//! aware type is able to observe usage and signal interest to the `Reactor`.
//!
//! In the case of `TcpStream`, the Tokio aware TCP socket, when
//! `TcpStream::try_read` is called and `Ok(None)` is returned, read interest
//! is automatically registered with the reactor and associated with the
//! currently running task. The logic being that, by trying to read from the
//! socket, the current task has indicated that read readiness is required for
//! the task to make progress. Once the TCP socket becomes read ready, the
//! task's `tick` function is called again, and this time a call to
//! `TcpStream::try_read` will (most likely) read some bytes OR result in an
//! error.
//!
//! # Transport
//!
//! A typed stream that may be read from and written to without blocking.
//!
//! A `Transport` does protocol specific serialization / deserialization. It
//! usually is composed of some lower level source, for example a TCP Stream
//! and reads / writes protocol frames.
//!
//! For example, imagine a protocol that is UTF-8 string based and framed with
//! new lines, aka each message is terminated by "\n". The transport would look
//! something like:
//!
//! ```rust,no_run
//! use tokio::io::{TryRead, TryWrite, Readiness, Transport};
//! use std::io;
//!
//! struct LineTransport<T> {
//!     source: T,
//!     rd: Vec<u8>,
//!     wr: Vec<u8>,
//! }
//!
//! impl<T: TryRead + TryWrite + Readiness> Transport for LineTransport<T> {
//!     type In = String;
//!     type Out = String;
//!
//!     fn read(&mut self) -> io::Result<Option<String>> {
//!         loop {
//!             // First, try to parse a new line from what was buffered
//!             if let Some(line) = parse_new_line(&mut self.rd) {
//!                 return Ok(Some(line));
//!             }
//!         }
//!     }
//!
//!     fn write(&mut self, req: String) -> io::Result<Option<()>> {
//!         // Append the message to the buffer
//!         self.wr.append(&mut req.into_bytes());
//!         self.flush()
//!     }
//!
//!     fn flush(&mut self) -> io::Result<Option<()>> {
//!         while !self.wr.is_empty() {
//!             match try!(self.source.try_write(&mut self.wr)) {
//!                 Some(n) => shift(&mut self.wr, n),
//!                 None => return Ok(None),
//!             }
//!         }
//!
//!         Ok(Some(()))
//!     }
//! }
//!
//! impl<T: Readiness> Readiness for LineTransport<T> {
//!     fn is_readable(&self) -> bool {
//!         self.rd.contains(&b'\n') || self.source.is_readable()
//!     }
//!
//!     fn is_writable(&self) -> bool {
//!         // The source is always writable since we don't cap the write
//!         // buffer size. Not an ideal production behavior...
//!         true
//!     }
//! }
//!
//! fn parse_new_line(buf: &mut Vec<u8>) -> Option<String> {
//!     // Search for "\n", if found, read everything from the start of the
//!     // buffer to the newline as a string then shift all bytes after the
//!     // newline to the beginning of the buffer.
//!     unimplemented!();
//! }
//!
//! fn shift(buf: &mut Vec<u8>, n: usize) {
//!     // Drop the first `n` bytes in the buffer and move all bytes after that
//!     // point to the front of the buffer.
//! }
//! ```

mod framing;
mod ready;
mod stream;
mod transport;

pub use self::framing::{Framed, Parse, Serialize};
pub use self::ready::{Readiness, Ready};
pub use self::stream::Stream;
pub use self::transport::Transport;

use bytes::{Buf, MutBuf, ReadExt, WriteExt};
use std::io;

/// A refinement of `std::io::Read` for reading from non-blocking sources.
///
/// When reading from a non-blocking source, receiving a
/// `ErrorKind::WouldBlock` is expected and not an error. A such, it is useful
/// to split out the would-block case from the other error cases.
pub trait TryRead: io::Read {

    /// Pull some bytes from this source into the specified buffer, returning
    /// how many bytes were read.
    ///
    /// If the source is not able to perform the operation due to not having
    /// any bytes to read, `Ok(None)` is returned.
    ///
    /// Aside from the signature, behavior is identical to `std::io::Read`. For
    /// more details, read the `std::io::Read` documentation.
    fn try_read(&mut self, buf: &mut [u8]) -> io::Result<Option<usize>>;

    /// Pull some bytes from this source into the specified `Buf`, returning
    /// how many bytes were read.
    fn try_read_buf<B: MutBuf>(&mut self, buf: &mut B) -> io::Result<Option<usize>>;
}

impl<T: io::Read> TryRead for T {
    fn try_read(&mut self, buf: &mut [u8]) -> io::Result<Option<usize>> {
        match self.read(buf) {
            Ok(n) => Ok(Some(n)),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
            Err(e) => Err(e),
        }
    }

    fn try_read_buf<B: MutBuf>(&mut self, buf: &mut B) -> io::Result<Option<usize>> {
        match self.read_buf(buf) {
            Ok(n) => Ok(Some(n)),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
            Err(e) => Err(e),
        }
    }
}

/// A refinement of `std::io::Write` for reading from non-blocking sources.
///
/// When reading from a non-blocking source, receiving a
/// `ErrorKind::WouldBlock` is expected and not an error. A such, it is useful
/// to split out the would-block case from the other error cases.
pub trait TryWrite: io::Write {

    /// Write a buffer into this object, returning how many bytes were written.
    ///
    /// If the source is not able to perform the operation due to not being
    /// ready, `Ok(None)` is returned.
    ///
    /// Aside from the signature, behavior is identical to `std::io::Write`.
    /// For more details, read the `std::io::Write` documentation.
    fn try_write(&mut self, buf: &[u8]) -> io::Result<Option<usize>>;

    /// Write a `Buf` into this object, returning how many bytes were written.
    fn try_write_buf<B: Buf>(&mut self, buf: &mut B) -> io::Result<Option<usize>>;

    /// Try flushing the underlying IO
    fn try_flush(&mut self) -> io::Result<Option<()>>;
}

impl<T: io::Write> TryWrite for T {
    fn try_write(&mut self, buf: &[u8]) -> io::Result<Option<usize>> {
        match self.write(buf) {
            Ok(n) => Ok(Some(n)),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
            Err(e) => Err(e),
        }
    }

    fn try_write_buf<B: Buf>(&mut self, buf: &mut B) -> io::Result<Option<usize>> {
        match self.write_buf(buf) {
            Ok(n) => Ok(Some(n)),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
            Err(e) => Err(e),
        }
    }

    fn try_flush(&mut self) -> io::Result<Option<()>> {
        match self.flush() {
            Ok(()) => Ok(Some(())),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
            Err(e) => Err(e),
        }
    }
}
<|endoftext|>


<commit_before>//! Issues interface

use self::super::{Github, Result, SortDirection, State};
use rep::{Issue, IssueReq, Label};
use rustc_serialize::json;
use std::fmt;
use std::default::Default;
use url::form_urlencoded;

pub enum Filter {
    Assigned,
    Created,
    Mentioned,
    Subscribed,
    All,
}

impl fmt::Display for Filter {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Filter::Assigned => "assigned",
                   Filter::Created => "created",
                   Filter::Mentioned => "mentioned",
                   Filter::Subscribed => "subscribed",
                   Filter::All => "all",
               })
    }
}

impl Default for Filter {
    fn default() -> Filter {
        Filter::Assigned
    }
}

pub enum Sort {
    Created,
    Updated,
    Comments,
}

impl fmt::Display for Sort {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Sort::Created => "created",
                   Sort::Updated => "updated",
                   Sort::Comments => "comments",
               })
    }
}

impl Default for Sort {
    fn default() -> Sort {
        Sort::Created
    }
}

pub struct IssueLabels<'a> {
    github: &'a Github<'a>,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueLabels<'a> {
    pub fn new<O, R>(github: &'a Github<'a>, owner: O, repo: R, number: u64) -> IssueLabels<'a>
        where O: Into<String>,
              R: Into<String>
    {
        IssueLabels {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues/{}/labels{}",
                self.owner,
                self.repo,
                self.number,
                more)
    }

    /// add a set of labels to this issue ref
    pub fn add(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github
            .post::<Vec<Label>>(&self.path(""), try!(json::encode(&labels)).as_bytes())
    }

    /// remove a label from this issue
    pub fn remove(&self, label: &str) -> Result<()> {
        self.github
            .delete(&self.path(&format!("/{}", label)))
    }

    /// replace all labels associated with this issue with a new set.
    /// providing an empty set of labels is the same as clearing the
    /// current labels
    pub fn set(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github.put::<Vec<Label>>(&self.path(""), try!(json::encode(&labels)).as_bytes())
    }

    /// remove all labels from an issue
    pub fn clear(&self) -> Result<()> {
        self.github
            .delete(&self.path(""))
    }
}

pub struct IssueRef<'a> {
    github: &'a Github<'a>,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueRef<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github<'a>, owner: O, repo: R, number: u64) -> IssueRef<'a>
        where O: Into<String>,
              R: Into<String>
    {
        IssueRef {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues/{}{}",
                self.owner,
                self.repo,
                self.number,
                more)
    }

    pub fn labels(&self) -> IssueLabels {
        IssueLabels::new(self.github,
                         self.owner.as_ref(),
                         self.repo.as_ref(),
                         self.number)
    }

    pub fn edit(&self, is: &IssueReq) -> Result<Issue> {
        let data = try!(json::encode(&is));
        self.github.patch::<Issue>(&self.path(""), data.as_bytes())
    }
}

pub struct Issues<'a> {
    github: &'a Github<'a>,
    owner: String,
    repo: String,
}

/// an mutable issue list builder
pub struct ListBuilder<'a> {
    issues: &'a Issues<'a>,
    state: State,
    sort: Sort,
    direction: SortDirection,
    assignee: Option<&'static str>,
    creator: Option<&'static str>,
    mentioned: Option<&'static str>,
    labels: Vec<&'static str>,
    since: Option<&'static str>,
}

impl<'a> ListBuilder<'a> {

    pub fn new(is: &'a Issues<'a>) -> ListBuilder<'a> {
        ListBuilder {
            issues: is,
            state: Default::default(),
            sort: Default::default(),
            direction: Default::default(),
            assignee: None,
            creator: None,
            mentioned: None,
            labels: vec![],
            since: None,
        }
    }

    pub fn state(&mut self, state: State) -> &mut ListBuilder<'a> {
        self.state = state;
        self
    }

    pub fn sort(&mut self, sort: Sort) -> &mut ListBuilder<'a> {
        self.sort = sort;
        self
    }

    pub fn direction(&mut self, direction: SortDirection) -> &mut ListBuilder<'a> {
        self.direction = direction;
        self
    }

    pub fn assignee(&mut self, assignee: &'static str) -> &mut ListBuilder<'a> {
        self.assignee = Some(assignee);
        self
    }

    pub fn creator(&mut self, creator: &'static str) -> &mut ListBuilder<'a> {
        self.creator = Some(creator);
        self
    }

    pub fn mentioned(&mut self, mentioned: &'static str) -> &mut ListBuilder<'a> {
        self.mentioned = Some(mentioned);
        self
    }

    pub fn labels(&mut self, labels: Vec<&'static str>) -> &mut ListBuilder<'a> {
        self.labels = labels;
        self
    }

    pub fn since(&mut self, since: &'static str) -> &mut ListBuilder<'a> {
        self.since = Some(since);
        self
    }

    pub fn get(&self) -> Result<Vec<Issue>> {
        let mut params = Vec::new();
        params.push(("state", self.state.to_string()));
        params.push(("sort", self.sort.to_string()));
        params.push(("direction", self.direction.to_string()));
        if let Some(a) = self.assignee {
            params.push(("assignee", a.to_owned()));
        }
        if let Some(c) = self.creator {
            params.push(("creator", c.to_owned()));
        }
        if let Some(m) = self.mentioned {
            params.push(("mentioned", m.to_owned()));
        }
        if let Some(s) = self.since {
            params.push(("since", s.to_owned()));
        }
        if !self.labels.is_empty() {
            params.push(("labels", self.labels.connect(",")));
        }
        let url = self.issues.path(&format!("?{}", form_urlencoded::serialize(params)));
        self.issues.github.get::<Vec<Issue>>(&url)
    }

}

impl<'a> Issues<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github<'a>, owner: O, repo: R) -> Issues<'a>
        where O: Into<String>,
              R: Into<String>
    {
        Issues {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
    }

    pub fn get(&self, number: u64) -> IssueRef {
        IssueRef::new(self.github, self.owner.as_ref(), self.repo.as_ref(), number)
    }

    pub fn create(&self, is: &IssueReq) -> Result<Issue> {
        let data = try!(json::encode(&is));
        self.github.post::<Issue>(&self.path(""), data.as_bytes())
    }

    pub fn list(&self) -> ListBuilder {
        ListBuilder::new(self)
    }
}
<commit_msg>remove static lifetime restriction<commit_after>//! Issues interface

use self::super::{Github, Result, SortDirection, State};
use rep::{Issue, IssueReq, Label};
use rustc_serialize::json;
use std::fmt;
use std::default::Default;
use url::form_urlencoded;

pub enum Filter {
    Assigned,
    Created,
    Mentioned,
    Subscribed,
    All,
}

impl fmt::Display for Filter {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Filter::Assigned => "assigned",
                   Filter::Created => "created",
                   Filter::Mentioned => "mentioned",
                   Filter::Subscribed => "subscribed",
                   Filter::All => "all",
               })
    }
}

impl Default for Filter {
    fn default() -> Filter {
        Filter::Assigned
    }
}

pub enum Sort {
    Created,
    Updated,
    Comments,
}

impl fmt::Display for Sort {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Sort::Created => "created",
                   Sort::Updated => "updated",
                   Sort::Comments => "comments",
               })
    }
}

impl Default for Sort {
    fn default() -> Sort {
        Sort::Created
    }
}

pub struct IssueLabels<'a> {
    github: &'a Github<'a>,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueLabels<'a> {
    pub fn new<O, R>(github: &'a Github<'a>, owner: O, repo: R, number: u64) -> IssueLabels<'a>
        where O: Into<String>,
              R: Into<String>
    {
        IssueLabels {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues/{}/labels{}",
                self.owner,
                self.repo,
                self.number,
                more)
    }

    /// add a set of labels to this issue ref
    pub fn add(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github
            .post::<Vec<Label>>(&self.path(""), try!(json::encode(&labels)).as_bytes())
    }

    /// remove a label from this issue
    pub fn remove(&self, label: &str) -> Result<()> {
        self.github
            .delete(&self.path(&format!("/{}", label)))
    }

    /// replace all labels associated with this issue with a new set.
    /// providing an empty set of labels is the same as clearing the
    /// current labels
    pub fn set(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github.put::<Vec<Label>>(&self.path(""), try!(json::encode(&labels)).as_bytes())
    }

    /// remove all labels from an issue
    pub fn clear(&self) -> Result<()> {
        self.github
            .delete(&self.path(""))
    }
}

pub struct IssueRef<'a> {
    github: &'a Github<'a>,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueRef<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github<'a>, owner: O, repo: R, number: u64) -> IssueRef<'a>
        where O: Into<String>,
              R: Into<String>
    {
        IssueRef {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues/{}{}",
                self.owner,
                self.repo,
                self.number,
                more)
    }

    pub fn labels(&self) -> IssueLabels {
        IssueLabels::new(self.github,
                         self.owner.as_ref(),
                         self.repo.as_ref(),
                         self.number)
    }

    pub fn edit(&self, is: &IssueReq) -> Result<Issue> {
        let data = try!(json::encode(&is));
        self.github.patch::<Issue>(&self.path(""), data.as_bytes())
    }
}

pub struct Issues<'a> {
    github: &'a Github<'a>,
    owner: String,
    repo: String,
}

/// an mutable issue list builder
pub struct ListBuilder<'a> {
    issues: &'a Issues<'a>,
    state: State,
    sort: Sort,
    direction: SortDirection,
    assignee: Option<String>,
    creator: Option<String>,
    mentioned: Option<String>,
    labels: Vec<String>,
    since: Option<String>,
}

impl<'a> ListBuilder<'a> {

    pub fn new(is: &'a Issues<'a>) -> ListBuilder<'a> {
        ListBuilder {
            issues: is,
            state: Default::default(),
            sort: Default::default(),
            direction: Default::default(),
            assignee: Default::default(),
            creator: Default::default(),
            mentioned: Default::default(),
            labels: Default::default(),
            since: Default::default(),
        }
    }

    pub fn state(&mut self, state: State) -> &mut ListBuilder<'a> {
        self.state = state;
        self
    }

    pub fn sort(&mut self, sort: Sort) -> &mut ListBuilder<'a> {
        self.sort = sort;
        self
    }

    pub fn direction(&mut self, direction: SortDirection) -> &mut ListBuilder<'a> {
        self.direction = direction;
        self
    }

    pub fn assignee<A>(&mut self, assignee: A) -> &mut ListBuilder<'a> where A: Into<String> {
        self.assignee = Some(assignee.into());
        self
    }

    pub fn creator<C>(&mut self, creator: C) -> &mut ListBuilder<'a> where C: Into<String> {
        self.creator = Some(creator.into());
        self
    }

    pub fn mentioned<M>(&mut self, mentioned: M) -> &mut ListBuilder<'a> where M: Into<String> {
        self.mentioned = Some(mentioned.into());
        self
    }

    pub fn labels<L>(&mut self, labels: Vec<L>) -> &mut ListBuilder<'a> where L: Into<String> {
        self.labels = labels.into_iter().map(|l|l.into()).collect::<Vec<String>>();
        self
    }

    pub fn since<S>(&mut self, since: S) -> &mut ListBuilder<'a> where S: Into<String> {
        self.since = Some(since.into());
        self
    }

    pub fn get(&self) -> Result<Vec<Issue>> {
        let mut params = Vec::new();
        params.push(("state", self.state.to_string()));
        params.push(("sort", self.sort.to_string()));
        params.push(("direction", self.direction.to_string()));
        if let Some(ref a) = self.assignee {
            params.push(("assignee", a.to_owned()));
        }
        if let Some(ref c) = self.creator {
            params.push(("creator", c.to_owned()));
        }
        if let Some(ref m) = self.mentioned {
            params.push(("mentioned", m.to_owned()));
        }
        if let Some(ref s) = self.since {
            params.push(("since", s.to_owned()));
        }
        if !self.labels.is_empty() {
            params.push(("labels", self.labels.connect(",")));
        }
        let url = self.issues.path(&format!("?{}", form_urlencoded::serialize(params)));
        self.issues.github.get::<Vec<Issue>>(&url)
    }

}

impl<'a> Issues<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github<'a>, owner: O, repo: R) -> Issues<'a>
        where O: Into<String>,
              R: Into<String>
    {
        Issues {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
    }

    pub fn get(&self, number: u64) -> IssueRef {
        IssueRef::new(self.github, self.owner.as_ref(), self.repo.as_ref(), number)
    }

    pub fn create(&self, is: &IssueReq) -> Result<Issue> {
        let data = try!(json::encode(&is));
        self.github.post::<Issue>(&self.path(""), data.as_bytes())
    }

    pub fn list(&self) -> ListBuilder {
        ListBuilder::new(self)
    }
}
<|endoftext|>


<commit_before>//! Issues interface

use std::io::Result;
use self::super::{Github, SortDirection, State};
use rep::{Issue, IssueReq, Label};
use rustc_serialize::json;
use std::fmt;
use std::default::Default;

pub enum Filter {
  Assigned,
  Created,
  Mentioned,
  Subscribed,
  All
}

impl fmt::Display for Filter {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Filter::Assigned => "assigned",
      Filter::Created => "created",
      Filter::Mentioned => "mentioned",
      Filter::Subscribed => "subscribed",
      Filter::All => "all"
    })
  }
}

impl Default for Filter {
  fn default() -> Filter {
    Filter::Assigned
  }
}

pub enum Sort {
  Created,
  Updated,
  Comments
}

impl fmt::Display for Sort {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Sort::Created => "created",
      Sort::Updated => "updated",
      Sort::Comments => "comments"
    })
  }
}

impl Default for Sort {
  fn default() -> Sort {
    Sort::Created
  }
}

pub struct IssueRef<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str,
  number: &'static i64
}

impl<'a> IssueRef<'a> {
  /// create a new instance of a github repo issue ref
  pub fn new(
    github: &'a Github<'a>, owner: &'static str, repo: &'static str,
    number: &'static i64) -> IssueRef<'a> {
    IssueRef {
      github: github,
      owner: owner,
      repo: repo,
      number: number
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues/{}{}", self.owner, self.repo, self.number, more)
  }

  /// add a set of labels to this issue ref
  pub fn label(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
    let body = try!(self.github.post(
      &self.path("/labels"),
      json::encode(&labels).unwrap().as_bytes()
    ));
    Ok(json::decode::<Vec<Label>>(&body).unwrap())
  }

  /// remove a label from this issue
  pub fn unlabel(&self, label: &'static str) -> Result<()> {
    self.github.delete(
      &self.path(
        &format!("/labels/{}", label)
      )
    ).map(|_| ())
  }

  /// replace all labels associated with this issue with a new set.
  /// providing an empty set of labels is the same as clearing the
  /// current labels
  pub fn relabel(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
    let body = try!(self.github.patch(
      &self.path("/labels"),
      json::encode(&labels).unwrap().as_bytes()
    ));
    Ok(json::decode::<Vec<Label>>(&body).unwrap())
  }

  pub fn edit(&self, is: &IssueReq) -> Result<Issue> {
    let data = json::encode(&is).unwrap();
    let body = try!(
      self.github.patch(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Issue>(&body).unwrap())
  }
}

pub struct Issues<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str
}

/// an mutable issue list builder
pub struct ListBuilder<'a> {
  issues: &'a Issues<'a>,
  state: State,
  sort: Sort,
  direction: SortDirection,
  assignee: Option<&'static str>,
  creator: Option<&'static str>,
  mentioned: Option<&'static str>,
  labels: Vec<&'static str>,
  since: Option<&'static str>
}

impl<'a> ListBuilder<'a> {

  pub fn new(is: &'a Issues<'a>) -> ListBuilder<'a> {
    ListBuilder {
      issues: is,
      state: Default::default(),
      sort: Default::default(),
      direction: Default::default(),
      assignee: None,
      creator: None,
      mentioned: None,
      labels: vec![],
      since: None
    }
  }

  pub fn state(&mut self, state: State) -> &mut ListBuilder<'a> {
    self.state = state;
    self
  }

  pub fn sort(&mut self, sort: Sort) -> &mut ListBuilder<'a> {
    self.sort = sort;
    self
  }

  pub fn direction(&mut self, direction: SortDirection) -> &mut ListBuilder<'a> {
    self.direction = direction;
    self
  }

  pub fn assignee(&mut self, assignee: &'static str) -> &mut ListBuilder<'a> {
    self.assignee = Some(assignee);
    self
  }

  pub fn creator(&mut self, creator: &'static str) -> &mut ListBuilder<'a> {
    self.creator = Some(creator);
    self
  }

  pub fn mentioned(&mut self, mentioned: &'static str) -> &mut ListBuilder<'a> {
    self.mentioned = Some(mentioned);
    self
  }

  pub fn labels(&mut self, labels: Vec<&'static str>) -> &mut ListBuilder<'a> {
    self.labels = labels;
    self
  }

  pub fn since(&mut self, since: &'static str) -> &mut ListBuilder<'a> {
    self.since = Some(since);
    self
  }

  pub fn get(&self) -> Result<Vec<Issue>> {
    let mut params = Vec::new();
    params.push(format!("state={}", self.state));
    params.push(format!("sort={}", self.sort));
    params.push(format!("direction={}", self.direction));
    if let Some(a) = self.assignee {
      params.push(format!("assignee={}", a));
    }
    if let Some(c) = self.creator {
      params.push(format!("creator={}", c));
    }
    if let Some(m) = self.mentioned {
      params.push(format!("mentioned={}", m));
    }
    if let Some(s) = self.since {
      params.push(format!("since={}", s));
    }
    if !self.labels.is_empty() {
      params.push(format!("labels={}", self.labels.connect(",")));
    }
    println!("params {:?}", params);
    let url = self.issues.path(
      &format!("?{}", params.connect("&"))
    );
    let body = try!(
      self.issues.github.get(
        &url
      )
    );
    Ok(json::decode::<Vec<Issue>>(&body).unwrap())
  }

}

impl<'a> Issues<'a> {
  /// create a new instance of a github repo issue ref
  pub fn new(
    github: &'a Github<'a>, owner: &'static str, repo: &'static str) -> Issues<'a> {
    Issues {
      github: github,
      owner: owner,
      repo: repo
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
  }

  pub fn get(&self, number: &'static i64) -> IssueRef {
    IssueRef::new(self.github, self.owner, self.repo, number)
  }

  pub fn create(&self, is: &IssueReq) -> Result<Issue> {
    let data = json::encode(&is).unwrap();
    let body = try!(
      self.github.post(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Issue>(&body).unwrap())
  }

  pub fn list(&self) -> ListBuilder {
    ListBuilder::new(self)
  }
}
<commit_msg>give issue labels its own home<commit_after>//! Issues interface

use std::io::Result;
use self::super::{Github, SortDirection, State};
use rep::{Issue, IssueReq, Label};
use rustc_serialize::json;
use std::fmt;
use std::default::Default;

pub enum Filter {
  Assigned,
  Created,
  Mentioned,
  Subscribed,
  All
}

impl fmt::Display for Filter {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Filter::Assigned => "assigned",
      Filter::Created => "created",
      Filter::Mentioned => "mentioned",
      Filter::Subscribed => "subscribed",
      Filter::All => "all"
    })
  }
}

impl Default for Filter {
  fn default() -> Filter {
    Filter::Assigned
  }
}

pub enum Sort {
  Created,
  Updated,
  Comments
}

impl fmt::Display for Sort {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Sort::Created => "created",
      Sort::Updated => "updated",
      Sort::Comments => "comments"
    })
  }
}

impl Default for Sort {
  fn default() -> Sort {
    Sort::Created
  }
}

pub struct IssueLabels<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str,
  number: &'static i64
}

impl<'a> IssueLabels<'a> {
  pub fn new(github: &'a Github<'a>, owner: &'static str, repo: &'static str, number: &'static i64) -> IssueLabels<'a> {
    IssueLabels {
      github: github,
      owner: owner,
      repo: repo,
      number: number
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues/{}/labels{}", self.owner, self.repo, self.number, more)
  }

  /// add a set of labels to this issue ref
  pub fn add(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
    let body = try!(self.github.post(
      &self.path(""),
      json::encode(&labels).unwrap().as_bytes()
    ));
    Ok(json::decode::<Vec<Label>>(&body).unwrap())
  }

  /// remove a label from this issue
  pub fn remove(&self, label: &'static str) -> Result<()> {
    self.github.delete(
      &self.path(
        &format!("/{}", label)
      )
    ).map(|_| ())
  }

  /// replace all labels associated with this issue with a new set.
  /// providing an empty set of labels is the same as clearing the
  /// current labels
  pub fn set(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
    let body = try!(self.github.patch(
      &self.path(""),
      json::encode(&labels).unwrap().as_bytes()
    ));
    Ok(json::decode::<Vec<Label>>(&body).unwrap())
  }

  /// remove all labels from an issue
  pub fn clear(&self) -> Result<()> {
    self.github.delete(
      &self.path("")
    ).map(|_| ())
  }
}

pub struct IssueRef<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str,
  number: &'static i64
}

impl<'a> IssueRef<'a> {
  /// create a new instance of a github repo issue ref
  pub fn new(
    github: &'a Github<'a>, owner: &'static str, repo: &'static str,
    number: &'static i64) -> IssueRef<'a> {
    IssueRef {
      github: github,
      owner: owner,
      repo: repo,
      number: number
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues/{}{}", self.owner, self.repo, self.number, more)
  }

  pub fn labels(&self) -> IssueLabels {
    IssueLabels::new(self.github, self.owner, self.repo, self.number)
  }

  pub fn edit(&self, is: &IssueReq) -> Result<Issue> {
    let data = json::encode(&is).unwrap();
    let body = try!(
      self.github.patch(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Issue>(&body).unwrap())
  }
}

pub struct Issues<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str
}

/// an mutable issue list builder
pub struct ListBuilder<'a> {
  issues: &'a Issues<'a>,
  state: State,
  sort: Sort,
  direction: SortDirection,
  assignee: Option<&'static str>,
  creator: Option<&'static str>,
  mentioned: Option<&'static str>,
  labels: Vec<&'static str>,
  since: Option<&'static str>
}

impl<'a> ListBuilder<'a> {

  pub fn new(is: &'a Issues<'a>) -> ListBuilder<'a> {
    ListBuilder {
      issues: is,
      state: Default::default(),
      sort: Default::default(),
      direction: Default::default(),
      assignee: None,
      creator: None,
      mentioned: None,
      labels: vec![],
      since: None
    }
  }

  pub fn state(&mut self, state: State) -> &mut ListBuilder<'a> {
    self.state = state;
    self
  }

  pub fn sort(&mut self, sort: Sort) -> &mut ListBuilder<'a> {
    self.sort = sort;
    self
  }

  pub fn direction(&mut self, direction: SortDirection) -> &mut ListBuilder<'a> {
    self.direction = direction;
    self
  }

  pub fn assignee(&mut self, assignee: &'static str) -> &mut ListBuilder<'a> {
    self.assignee = Some(assignee);
    self
  }

  pub fn creator(&mut self, creator: &'static str) -> &mut ListBuilder<'a> {
    self.creator = Some(creator);
    self
  }

  pub fn mentioned(&mut self, mentioned: &'static str) -> &mut ListBuilder<'a> {
    self.mentioned = Some(mentioned);
    self
  }

  pub fn labels(&mut self, labels: Vec<&'static str>) -> &mut ListBuilder<'a> {
    self.labels = labels;
    self
  }

  pub fn since(&mut self, since: &'static str) -> &mut ListBuilder<'a> {
    self.since = Some(since);
    self
  }

  pub fn get(&self) -> Result<Vec<Issue>> {
    let mut params = Vec::new();
    params.push(format!("state={}", self.state));
    params.push(format!("sort={}", self.sort));
    params.push(format!("direction={}", self.direction));
    if let Some(a) = self.assignee {
      params.push(format!("assignee={}", a));
    }
    if let Some(c) = self.creator {
      params.push(format!("creator={}", c));
    }
    if let Some(m) = self.mentioned {
      params.push(format!("mentioned={}", m));
    }
    if let Some(s) = self.since {
      params.push(format!("since={}", s));
    }
    if !self.labels.is_empty() {
      params.push(format!("labels={}", self.labels.connect(",")));
    }
    println!("params {:?}", params);
    let url = self.issues.path(
      &format!("?{}", params.connect("&"))
    );
    let body = try!(
      self.issues.github.get(
        &url
      )
    );
    Ok(json::decode::<Vec<Issue>>(&body).unwrap())
  }

}

impl<'a> Issues<'a> {
  /// create a new instance of a github repo issue ref
  pub fn new(
    github: &'a Github<'a>, owner: &'static str, repo: &'static str) -> Issues<'a> {
    Issues {
      github: github,
      owner: owner,
      repo: repo
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
  }

  pub fn get(&self, number: &'static i64) -> IssueRef {
    IssueRef::new(self.github, self.owner, self.repo, number)
  }

  pub fn create(&self, is: &IssueReq) -> Result<Issue> {
    let data = json::encode(&is).unwrap();
    let body = try!(
      self.github.post(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Issue>(&body).unwrap())
  }

  pub fn list(&self) -> ListBuilder {
    ListBuilder::new(self)
  }
}
<|endoftext|>