<commit_before>extern crate xml;

use std::fs::File;
use std::io::BufReader;
use std::str::FromStr;

use xml::reader::{EventReader, XmlEvent};
use xml::attribute::OwnedAttribute;

mod error;
use error::{ErrorKind, AttributeError};

pub type Coordinate = f64;
pub type Id = i64;
pub type Role = String;

#[derive(Debug, PartialEq)]
pub struct Tag {
    pub key: String,
    pub val: String
}

#[derive(Debug, PartialEq)]
pub struct Bounds {
    pub minlat: Coordinate,
    pub minlon: Coordinate,
    pub maxlat: Coordinate,
    pub maxlon: Coordinate,
}

#[derive(Debug, PartialEq)]
pub struct Node {
    pub id: Id,
    pub lat: Coordinate,
    pub lon: Coordinate,
    pub tags: Vec<Tag>
}

#[derive(Debug, PartialEq)]
pub struct Way {
    pub id: Id,
    pub tags: Vec<Tag>,
    pub nodes: Vec<UnresolvedReference>
}

#[derive(Debug, PartialEq)]
pub struct Relation {
    pub id: Id,
    pub members: Vec<Member>,
    pub tags: Vec<Tag>
}

#[derive(Debug, PartialEq)]
pub enum Member {
    Node(UnresolvedReference, Role),
    Way(UnresolvedReference, Role),
    Relation(UnresolvedReference, Role),
}

#[derive(Debug, PartialEq)]
pub enum UnresolvedReference {
    Node(Id),
    Way(Id),
    Relation(Id)
}

#[derive(Debug, PartialEq)]
pub enum Reference<'a> {
    Node(&'a Node),
    Way(&'a Way),
    Relation(&'a Relation),
    Unresolved
}

#[derive(Debug)]
pub struct OSM {
    pub bounds: Option<Bounds>,
    pub nodes: Vec<Node>,
    pub ways: Vec<Way>,
    pub relations: Vec<Relation>
}

impl OSM {
    fn empty() -> OSM {
        OSM {
            bounds: None,
            nodes: Vec::new(),
            ways: Vec::new(),
            relations: Vec::new(),
        }
    }

    pub fn parse(file: File) -> Option<OSM> {
        let mut osm = OSM::empty();

        let reader = BufReader::new(file);
        let mut parser = EventReader::new(reader);

        loop {
            match parse_element_data(&mut parser) {
                Err(ErrorKind::XmlParseError(_)) => return None,
                Err(ErrorKind::BoundsMissing(_)) => osm.bounds = None,
                Err(ErrorKind::MalformedTag(_))       |
                Err(ErrorKind::MalformedNode(_))      |
                Err(ErrorKind::MalformedWay(_))       |
                Err(ErrorKind::MalformedRelation(_))  |
                Err(ErrorKind::UnknownElement)        => continue,
                Ok(data) => {
                    match data {
                        ElementData::EndOfDocument => return Some(osm),
                        ElementData::Ignored => continue,
                        ElementData::Bounds(minlat, minlon, maxlat, maxlon) => {
                            osm.bounds = Some(Bounds {
                                minlat: minlat,
                                minlon: minlon,
                                maxlat: maxlat,
                                maxlon: maxlon
                            });
                        },
                        ElementData::Node(id, lat, lon, tags) => {
                            osm.nodes.push(Node {
                                id: id,
                                lat: lat,
                                lon: lon,
                                tags: tags
                            });
                        },
                        ElementData::Way(id, node_refs, tags) => {
                            osm.ways.push(Way {
                                id: id,
                                nodes: node_refs,
                                tags: tags
                            });
                        },
                        ElementData::Relation(relation) => {
                            osm.relations.push(relation);
                        }
                    }
                }
            }
        }
    }

    pub fn resolve_reference<'a>(&self, reference: &UnresolvedReference) -> Reference {
        match *reference {
            UnresolvedReference::Node(id) => {
                match self.nodes.iter().find(|node| node.id == id) {
                    Some(node) => Reference::Node(&node),
                    None => Reference::Unresolved
                }
            },
            UnresolvedReference::Way(id) => {
                match self.ways.iter().find(|way| way.id == id) {
                    Some(way) => Reference::Way(&way),
                    None => Reference::Unresolved
                }
            },
            UnresolvedReference::Relation(id) => {
                match self.relations.iter().find(|relation| relation.id == id) {
                    Some(relation) => Reference::Relation(&relation),
                    None => Reference::Unresolved
                }
            }
        }
    }
}

enum ElementType {
    Bounds,
    Node,
    Way,
    Relation,
    Tag,
    NodeRef,
    Member,
}

enum ElementData {
    Bounds(Coordinate, Coordinate, Coordinate, Coordinate),
    Node(Id, Coordinate, Coordinate, Vec<Tag>),
    Way(Id, Vec<UnresolvedReference>, Vec<Tag>),
    Relation(Relation),
    // These two are here so we can terminate and skip uninteresting data without
    // using error handling.
    EndOfDocument,
    Ignored
}

impl FromStr for ElementType {
    type Err = ErrorKind;

    fn from_str(s: &str) -> Result<ElementType, ErrorKind> {
        let downcased = s.to_lowercase();

        if downcased == "bounds" {
            return Ok(ElementType::Bounds);
        }

        if downcased == "node" {
            return Ok(ElementType::Node);
        }

        if downcased == "way" {
            return Ok(ElementType::Way);
        }

        if downcased == "relation" {
            return Ok(ElementType::Relation);
        }

        if downcased == "tag" {
            return Ok(ElementType::Tag);
        }

        if downcased == "nd" {
            return Ok(ElementType::NodeRef);
        }

        if downcased == "member" {
            return Ok(ElementType::Member);
        }

        Err(ErrorKind::UnknownElement)
    }
}

fn parse_element_data(parser: &mut EventReader<BufReader<File>>) -> Result<ElementData, ErrorKind> {
    let element = try!(parser.next());
    match element {
        XmlEvent::EndDocument => Ok(ElementData::EndOfDocument),
        XmlEvent::StartElement { name, attributes, .. } => {
            let element_type = try!(ElementType::from_str(&name.local_name));

            match element_type {
                ElementType::Bounds => parse_bounds(&attributes),
                ElementType::Node => parse_node(parser, &attributes),
                ElementType::Way => parse_way(parser, &attributes),
                ElementType::Relation => parse_relation(parser, &attributes),
                _ => Err(ErrorKind::UnknownElement)
            }
        },
        _ => Ok(ElementData::Ignored)
    }
}

fn parse_relation(parser: &mut EventReader<BufReader<File>>, attrs: &Vec<OwnedAttribute>) -> Result<ElementData, ErrorKind> {
    let id = try!(find_attribute("id", attrs).map_err(ErrorKind::MalformedRelation));

    let mut members = Vec::new();
    let mut tags = Vec::new();

    loop {
        match try!(parser.next()) {
            XmlEvent::EndElement { name } => {
                let element_type = try!(ElementType::from_str(&name.local_name));

                match element_type {
                    ElementType::Relation => return Ok(ElementData::Relation(Relation {
                        id: id,
                        members: members,
                        tags: tags
                    })),
                    _ => continue
                }
            },
            XmlEvent::StartElement { name, attributes, .. } => {
                let element_type = try!(ElementType::from_str(&name.local_name));

                match element_type {
                    ElementType::Tag => {
                        if let Ok(tag) = parse_tag(&attributes) {
                            tags.push(tag);
                        }
                    },
                    ElementType::Member => {
                        let el_type = try!(find_attribute_uncasted("type", &attributes).map_err(ErrorKind::MalformedRelation));
                        let el_ref = try!(find_attribute("ref", &attributes).map_err(ErrorKind::MalformedRelation));
                        let el_role = try!(find_attribute_uncasted("role", &attributes).map_err(ErrorKind::MalformedRelation));

                        let el = match el_type.to_lowercase().as_ref() {
                            "node" => Member::Node(UnresolvedReference::Node(el_ref), el_role),
                            "way" => Member::Way(UnresolvedReference::Way(el_ref), el_role),
                            "relation" => Member::Relation(UnresolvedReference::Relation(el_ref), el_role),
                            _ => return Err(ErrorKind::MalformedRelation(AttributeError::Missing))
                        };

                        members.push(el);
                    },
                    ElementType::Bounds   |
                    ElementType::Node     |
                    ElementType::Relation |
                    ElementType::Way      |
                    ElementType::NodeRef  => return Err(
                        ErrorKind::MalformedRelation(AttributeError::IllegalNesting)
                    )
                }
            },
            _ => continue
        }
    }
}

fn parse_way(parser: &mut EventReader<BufReader<File>>, attrs: &Vec<OwnedAttribute>) -> Result<ElementData, ErrorKind> {
    let id = try!(find_attribute("id", attrs).map_err(ErrorKind::MalformedWay));

    let mut node_refs = Vec::new();
    let mut tags = Vec::new();

    loop {
        match try!(parser.next()) {
            XmlEvent::EndElement { name } => {
                let element_type = try!(ElementType::from_str(&name.local_name));

                match element_type {
                    ElementType::Way => return Ok(ElementData::Way(id, node_refs, tags)),
                    _ => continue
                }
            },
            XmlEvent::StartElement { name, attributes, .. } => {
                let element_type = try!(ElementType::from_str(&name.local_name));

                match element_type {
                    ElementType::Tag => {
                        if let Ok(tag) = parse_tag(&attributes) {
                            tags.push(tag);
                        }
                    },
                    ElementType::NodeRef => {
                        let node_ref = try!(find_attribute("ref", &attributes).map_err(ErrorKind::MalformedWay));
                        node_refs.push(UnresolvedReference::Node(node_ref));
                    },
                    ElementType::Bounds   |
                    ElementType::Node     |
                    ElementType::Relation |
                    ElementType::Way      |
                    ElementType::Member   => return Err(
                        ErrorKind::MalformedWay(AttributeError::IllegalNesting)
                    )
                }
            },
            _ => continue
        }
    }

}

fn parse_node(parser: &mut EventReader<BufReader<File>>, attrs: &Vec<OwnedAttribute>) -> Result<ElementData, ErrorKind> {
    let id = try!(find_attribute("id", attrs).map_err(ErrorKind::MalformedNode));
    let lat = try!(find_attribute("lat", attrs).map_err(ErrorKind::MalformedNode));
    let lon = try!(find_attribute("lon", attrs).map_err(ErrorKind::MalformedNode));

    let mut tags = Vec::new();

    loop {
        match try!(parser.next()) {
            XmlEvent::EndElement { name } => {
                let element_type = try!(ElementType::from_str(&name.local_name));

                match element_type {
                    ElementType::Node => return Ok(ElementData::Node(id, lat, lon, tags)),
                    _ => continue
                }
            },
            XmlEvent::StartElement { name, attributes, .. } => {
                let element_type = try!(ElementType::from_str(&name.local_name));

                match element_type {
                    ElementType::Tag => {
                        if let Ok(tag) = parse_tag(&attributes) {
                            tags.push(tag);
                        }
                    },
                    ElementType::Bounds   |
                    ElementType::Node     |
                    ElementType::Relation |
                    ElementType::Way      |
                    ElementType::NodeRef  |
                    ElementType::Member   => return Err(
                        ErrorKind::MalformedNode(AttributeError::IllegalNesting)
                    )
                }
            },
            _ => continue
        }
    }
}

fn parse_tag(attributes: &Vec<OwnedAttribute>) -> Result<Tag, ErrorKind> {
    let key = try!(find_attribute_uncasted("k", attributes).map_err(ErrorKind::MalformedTag));
    let val = try!(find_attribute_uncasted("v", attributes).map_err(ErrorKind::MalformedTag));
    Ok(Tag { key: key, val: val })
}

fn parse_bounds(attrs: &Vec<OwnedAttribute>) -> Result<ElementData, ErrorKind> {
    let minlat = try!(find_attribute("minlat", attrs).map_err(ErrorKind::BoundsMissing));
    let minlon = try!(find_attribute("minlon", attrs).map_err(ErrorKind::BoundsMissing));
    let maxlat = try!(find_attribute("maxlat", attrs).map_err(ErrorKind::BoundsMissing));
    let maxlon = try!(find_attribute("maxlon", attrs).map_err(ErrorKind::BoundsMissing));

    Ok(ElementData::Bounds(minlat, minlon, maxlat, maxlon))
}

fn find_attribute<T>(name: &str, attrs: &Vec<OwnedAttribute>) -> Result<T, AttributeError>
    where AttributeError: std::convert::From<<T as std::str::FromStr>::Err>,
          T: FromStr
{
    let val_raw = try!(find_attribute_uncasted(name, attrs));
    let val = try!(val_raw.parse::<T>());
    Ok(val)
}

fn find_attribute_uncasted(name: &str, attrs: &Vec<OwnedAttribute>) -> Result<String, AttributeError> {
    let attr = attrs.iter().find(|attr| attr.name.local_name == name);
    match attr {
        Some(a) => {
            Ok(a.value.clone())
        },
        None => Err(AttributeError::Missing)
    }
}
<commit_msg>Clean ElementType FromStr implementation<commit_after>extern crate xml;

use std::fs::File;
use std::io::BufReader;
use std::str::FromStr;

use xml::reader::{EventReader, XmlEvent};
use xml::attribute::OwnedAttribute;

mod error;
use error::{ErrorKind, AttributeError};

pub type Coordinate = f64;
pub type Id = i64;
pub type Role = String;

#[derive(Debug, PartialEq)]
pub struct Tag {
    pub key: String,
    pub val: String
}

#[derive(Debug, PartialEq)]
pub struct Bounds {
    pub minlat: Coordinate,
    pub minlon: Coordinate,
    pub maxlat: Coordinate,
    pub maxlon: Coordinate,
}

#[derive(Debug, PartialEq)]
pub struct Node {
    pub id: Id,
    pub lat: Coordinate,
    pub lon: Coordinate,
    pub tags: Vec<Tag>
}

#[derive(Debug, PartialEq)]
pub struct Way {
    pub id: Id,
    pub tags: Vec<Tag>,
    pub nodes: Vec<UnresolvedReference>
}

#[derive(Debug, PartialEq)]
pub struct Relation {
    pub id: Id,
    pub members: Vec<Member>,
    pub tags: Vec<Tag>
}

#[derive(Debug, PartialEq)]
pub enum Member {
    Node(UnresolvedReference, Role),
    Way(UnresolvedReference, Role),
    Relation(UnresolvedReference, Role),
}

#[derive(Debug, PartialEq)]
pub enum UnresolvedReference {
    Node(Id),
    Way(Id),
    Relation(Id)
}

#[derive(Debug, PartialEq)]
pub enum Reference<'a> {
    Node(&'a Node),
    Way(&'a Way),
    Relation(&'a Relation),
    Unresolved
}

#[derive(Debug)]
pub struct OSM {
    pub bounds: Option<Bounds>,
    pub nodes: Vec<Node>,
    pub ways: Vec<Way>,
    pub relations: Vec<Relation>
}

impl OSM {
    fn empty() -> OSM {
        OSM {
            bounds: None,
            nodes: Vec::new(),
            ways: Vec::new(),
            relations: Vec::new(),
        }
    }

    pub fn parse(file: File) -> Option<OSM> {
        let mut osm = OSM::empty();

        let reader = BufReader::new(file);
        let mut parser = EventReader::new(reader);

        loop {
            match parse_element_data(&mut parser) {
                Err(ErrorKind::XmlParseError(_)) => return None,
                Err(ErrorKind::BoundsMissing(_)) => osm.bounds = None,
                Err(ErrorKind::MalformedTag(_))       |
                Err(ErrorKind::MalformedNode(_))      |
                Err(ErrorKind::MalformedWay(_))       |
                Err(ErrorKind::MalformedRelation(_))  |
                Err(ErrorKind::UnknownElement)        => continue,
                Ok(data) => {
                    match data {
                        ElementData::EndOfDocument => return Some(osm),
                        ElementData::Ignored => continue,
                        ElementData::Bounds(minlat, minlon, maxlat, maxlon) => {
                            osm.bounds = Some(Bounds {
                                minlat: minlat,
                                minlon: minlon,
                                maxlat: maxlat,
                                maxlon: maxlon
                            });
                        },
                        ElementData::Node(id, lat, lon, tags) => {
                            osm.nodes.push(Node {
                                id: id,
                                lat: lat,
                                lon: lon,
                                tags: tags
                            });
                        },
                        ElementData::Way(id, node_refs, tags) => {
                            osm.ways.push(Way {
                                id: id,
                                nodes: node_refs,
                                tags: tags
                            });
                        },
                        ElementData::Relation(relation) => {
                            osm.relations.push(relation);
                        }
                    }
                }
            }
        }
    }

    pub fn resolve_reference<'a>(&self, reference: &UnresolvedReference) -> Reference {
        match *reference {
            UnresolvedReference::Node(id) => {
                match self.nodes.iter().find(|node| node.id == id) {
                    Some(node) => Reference::Node(&node),
                    None => Reference::Unresolved
                }
            },
            UnresolvedReference::Way(id) => {
                match self.ways.iter().find(|way| way.id == id) {
                    Some(way) => Reference::Way(&way),
                    None => Reference::Unresolved
                }
            },
            UnresolvedReference::Relation(id) => {
                match self.relations.iter().find(|relation| relation.id == id) {
                    Some(relation) => Reference::Relation(&relation),
                    None => Reference::Unresolved
                }
            }
        }
    }
}

enum ElementType {
    Bounds,
    Node,
    Way,
    Relation,
    Tag,
    NodeRef,
    Member,
}

enum ElementData {
    Bounds(Coordinate, Coordinate, Coordinate, Coordinate),
    Node(Id, Coordinate, Coordinate, Vec<Tag>),
    Way(Id, Vec<UnresolvedReference>, Vec<Tag>),
    Relation(Relation),
    // These two are here so we can terminate and skip uninteresting data without
    // using error handling.
    EndOfDocument,
    Ignored
}

impl FromStr for ElementType {
    type Err = ErrorKind;

    fn from_str(s: &str) -> Result<ElementType, ErrorKind> {
        match s.to_lowercase().as_ref() {
            "bounds"   => Ok(ElementType::Bounds),
            "node"     => Ok(ElementType::Node),
            "way"      => Ok(ElementType::Way),
            "relation" => Ok(ElementType::Relation),
            "tag"      => Ok(ElementType::Tag),
            "nd"       => Ok(ElementType::NodeRef),
            "member"   => Ok(ElementType::Member),
            _ => Err(ErrorKind::UnknownElement)
        }
    }
}

fn parse_element_data(parser: &mut EventReader<BufReader<File>>) -> Result<ElementData, ErrorKind> {
    let element = try!(parser.next());
    match element {
        XmlEvent::EndDocument => Ok(ElementData::EndOfDocument),
        XmlEvent::StartElement { name, attributes, .. } => {
            let element_type = try!(ElementType::from_str(&name.local_name));

            match element_type {
                ElementType::Bounds => parse_bounds(&attributes),
                ElementType::Node => parse_node(parser, &attributes),
                ElementType::Way => parse_way(parser, &attributes),
                ElementType::Relation => parse_relation(parser, &attributes),
                _ => Err(ErrorKind::UnknownElement)
            }
        },
        _ => Ok(ElementData::Ignored)
    }
}

fn parse_relation(parser: &mut EventReader<BufReader<File>>, attrs: &Vec<OwnedAttribute>) -> Result<ElementData, ErrorKind> {
    let id = try!(find_attribute("id", attrs).map_err(ErrorKind::MalformedRelation));

    let mut members = Vec::new();
    let mut tags = Vec::new();

    loop {
        match try!(parser.next()) {
            XmlEvent::EndElement { name } => {
                let element_type = try!(ElementType::from_str(&name.local_name));

                match element_type {
                    ElementType::Relation => return Ok(ElementData::Relation(Relation {
                        id: id,
                        members: members,
                        tags: tags
                    })),
                    _ => continue
                }
            },
            XmlEvent::StartElement { name, attributes, .. } => {
                let element_type = try!(ElementType::from_str(&name.local_name));

                match element_type {
                    ElementType::Tag => {
                        if let Ok(tag) = parse_tag(&attributes) {
                            tags.push(tag);
                        }
                    },
                    ElementType::Member => {
                        let el_type = try!(find_attribute_uncasted("type", &attributes).map_err(ErrorKind::MalformedRelation));
                        let el_ref = try!(find_attribute("ref", &attributes).map_err(ErrorKind::MalformedRelation));
                        let el_role = try!(find_attribute_uncasted("role", &attributes).map_err(ErrorKind::MalformedRelation));

                        let el = match el_type.to_lowercase().as_ref() {
                            "node" => Member::Node(UnresolvedReference::Node(el_ref), el_role),
                            "way" => Member::Way(UnresolvedReference::Way(el_ref), el_role),
                            "relation" => Member::Relation(UnresolvedReference::Relation(el_ref), el_role),
                            _ => return Err(ErrorKind::MalformedRelation(AttributeError::Missing))
                        };

                        members.push(el);
                    },
                    ElementType::Bounds   |
                    ElementType::Node     |
                    ElementType::Relation |
                    ElementType::Way      |
                    ElementType::NodeRef  => return Err(
                        ErrorKind::MalformedRelation(AttributeError::IllegalNesting)
                    )
                }
            },
            _ => continue
        }
    }
}

fn parse_way(parser: &mut EventReader<BufReader<File>>, attrs: &Vec<OwnedAttribute>) -> Result<ElementData, ErrorKind> {
    let id = try!(find_attribute("id", attrs).map_err(ErrorKind::MalformedWay));

    let mut node_refs = Vec::new();
    let mut tags = Vec::new();

    loop {
        match try!(parser.next()) {
            XmlEvent::EndElement { name } => {
                let element_type = try!(ElementType::from_str(&name.local_name));

                match element_type {
                    ElementType::Way => return Ok(ElementData::Way(id, node_refs, tags)),
                    _ => continue
                }
            },
            XmlEvent::StartElement { name, attributes, .. } => {
                let element_type = try!(ElementType::from_str(&name.local_name));

                match element_type {
                    ElementType::Tag => {
                        if let Ok(tag) = parse_tag(&attributes) {
                            tags.push(tag);
                        }
                    },
                    ElementType::NodeRef => {
                        let node_ref = try!(find_attribute("ref", &attributes).map_err(ErrorKind::MalformedWay));
                        node_refs.push(UnresolvedReference::Node(node_ref));
                    },
                    ElementType::Bounds   |
                    ElementType::Node     |
                    ElementType::Relation |
                    ElementType::Way      |
                    ElementType::Member   => return Err(
                        ErrorKind::MalformedWay(AttributeError::IllegalNesting)
                    )
                }
            },
            _ => continue
        }
    }

}

fn parse_node(parser: &mut EventReader<BufReader<File>>, attrs: &Vec<OwnedAttribute>) -> Result<ElementData, ErrorKind> {
    let id = try!(find_attribute("id", attrs).map_err(ErrorKind::MalformedNode));
    let lat = try!(find_attribute("lat", attrs).map_err(ErrorKind::MalformedNode));
    let lon = try!(find_attribute("lon", attrs).map_err(ErrorKind::MalformedNode));

    let mut tags = Vec::new();

    loop {
        match try!(parser.next()) {
            XmlEvent::EndElement { name } => {
                let element_type = try!(ElementType::from_str(&name.local_name));

                match element_type {
                    ElementType::Node => return Ok(ElementData::Node(id, lat, lon, tags)),
                    _ => continue
                }
            },
            XmlEvent::StartElement { name, attributes, .. } => {
                let element_type = try!(ElementType::from_str(&name.local_name));

                match element_type {
                    ElementType::Tag => {
                        if let Ok(tag) = parse_tag(&attributes) {
                            tags.push(tag);
                        }
                    },
                    ElementType::Bounds   |
                    ElementType::Node     |
                    ElementType::Relation |
                    ElementType::Way      |
                    ElementType::NodeRef  |
                    ElementType::Member   => return Err(
                        ErrorKind::MalformedNode(AttributeError::IllegalNesting)
                    )
                }
            },
            _ => continue
        }
    }
}

fn parse_tag(attributes: &Vec<OwnedAttribute>) -> Result<Tag, ErrorKind> {
    let key = try!(find_attribute_uncasted("k", attributes).map_err(ErrorKind::MalformedTag));
    let val = try!(find_attribute_uncasted("v", attributes).map_err(ErrorKind::MalformedTag));
    Ok(Tag { key: key, val: val })
}

fn parse_bounds(attrs: &Vec<OwnedAttribute>) -> Result<ElementData, ErrorKind> {
    let minlat = try!(find_attribute("minlat", attrs).map_err(ErrorKind::BoundsMissing));
    let minlon = try!(find_attribute("minlon", attrs).map_err(ErrorKind::BoundsMissing));
    let maxlat = try!(find_attribute("maxlat", attrs).map_err(ErrorKind::BoundsMissing));
    let maxlon = try!(find_attribute("maxlon", attrs).map_err(ErrorKind::BoundsMissing));

    Ok(ElementData::Bounds(minlat, minlon, maxlat, maxlon))
}

fn find_attribute<T>(name: &str, attrs: &Vec<OwnedAttribute>) -> Result<T, AttributeError>
    where AttributeError: std::convert::From<<T as std::str::FromStr>::Err>,
          T: FromStr
{
    let val_raw = try!(find_attribute_uncasted(name, attrs));
    let val = try!(val_raw.parse::<T>());
    Ok(val)
}

fn find_attribute_uncasted(name: &str, attrs: &Vec<OwnedAttribute>) -> Result<String, AttributeError> {
    let attr = attrs.iter().find(|attr| attr.name.local_name == name);
    match attr {
        Some(a) => {
            Ok(a.value.clone())
        },
        None => Err(AttributeError::Missing)
    }
}
<|endoftext|>


<commit_before>#![feature(specialization)]
 #![feature(type_ascription)]

extern crate rutorch;
#[macro_use]
extern crate modparse_derive;
#[macro_use]
extern crate derive_builder;

extern crate num;
extern crate rand;
extern crate itertools;

// only needed for torchvision
extern crate curl;
extern crate flate2;
extern crate memmap;

// serialization support
#[macro_use]
extern crate serde_derive;
extern crate rmp;
extern crate rmp_serde as rmps;
extern crate serde;

#[macro_use]
pub mod macros;

pub mod nn;
pub mod autograd;
pub mod optim;
pub mod utils;
pub mod tensor;
pub mod storage;
pub mod torch;
use std::rc::Rc;
use std::cell::RefCell;

// Mutable reference counted T
pub type RcMut<T> = Rc<RefCell<T>>;
// Nullable mutable reference counted T
pub type OptRcMut<T> = Option<RcMut<T>>;
pub type Ix = usize;
/// Array index type (signed)
pub type Ixs = isize;

#[allow(non_snake_case)]
pub fn RcMutNew<T>(arg: T) -> RcMut<T> {
    Rc::new(RefCell::new(arg))
}

#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {}
}
<commit_msg>enable concat_idents<commit_after>#![feature(specialization)]
 #![feature(type_ascription)]
 #![feature(concat_idents)]

extern crate rutorch;
#[macro_use]
extern crate modparse_derive;
#[macro_use]
extern crate derive_builder;

extern crate num;
extern crate rand;
extern crate itertools;

// only needed for torchvision
extern crate curl;
extern crate flate2;
extern crate memmap;

// serialization support
#[macro_use]
extern crate serde_derive;
extern crate rmp;
extern crate rmp_serde as rmps;
extern crate serde;

#[macro_use]
pub mod macros;

pub mod nn;
pub mod autograd;
pub mod optim;
pub mod utils;
pub mod tensor;
pub mod storage;
pub mod torch;
use std::rc::Rc;
use std::cell::RefCell;

// Mutable reference counted T
pub type RcMut<T> = Rc<RefCell<T>>;
// Nullable mutable reference counted T
pub type OptRcMut<T> = Option<RcMut<T>>;
pub type Ix = usize;
/// Array index type (signed)
pub type Ixs = isize;

#[allow(non_snake_case)]
pub fn RcMutNew<T>(arg: T) -> RcMut<T> {
    Rc::new(RefCell::new(arg))
}

#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(bad_style, raw_pointer_derive)]
#![cfg_attr(dox, feature(no_core, lang_items))]
#![cfg_attr(dox, no_core)]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico")]

#![cfg_attr(all(target_os = "linux", target_arch = "x86_64"), doc(
    html_root_url = "http://alexcrichton.com/libc/x86_64-unknown-linux-gnu"
))]
#![cfg_attr(all(target_os = "linux", target_arch = "x86"), doc(
    html_root_url = "http://alexcrichton.com/libc/i686-unknown-linux-gnu"
))]
#![cfg_attr(all(target_os = "linux", target_arch = "arm"), doc(
    html_root_url = "http://alexcrichton.com/libc/arm-unknown-linux-gnueabihf"
))]
#![cfg_attr(all(target_os = "linux", target_arch = "mips"), doc(
    html_root_url = "http://alexcrichton.com/libc/mips-unknown-linux-gnu"
))]
#![cfg_attr(all(target_os = "linux", target_env = "musl"), doc(
    html_root_url = "http://alexcrichton.com/libc/x86_64-unknown-linux-musl"
))]
#![cfg_attr(all(target_os = "macos", target_arch = "x86_64"), doc(
    html_root_url = "http://alexcrichton.com/libc/x86_64-apple-darwin"
))]
#![cfg_attr(all(target_os = "macos", target_arch = "x86"), doc(
    html_root_url = "http://alexcrichton.com/libc/i686-apple-darwin"
))]
#![cfg_attr(all(windows, target_arch = "x86_64", target_env = "gnu"), doc(
    html_root_url = "http://alexcrichton.com/libc/x86_64-pc-windows-gnu"
))]
#![cfg_attr(all(windows, target_arch = "i686", target_env = "gnu"), doc(
    html_root_url = "http://alexcrichton.com/libc/i686-pc-windows-gnu"
))]
#![cfg_attr(all(windows, target_arch = "x86_64", target_env = "msvc"), doc(
    html_root_url = "http://alexcrichton.com/libc/x86_64-pc-windows-msvc"
))]
#![cfg_attr(all(windows, target_arch = "i686", target_env = "msvc"), doc(
    html_root_url = "http://alexcrichton.com/libc/i686-pc-windows-msvc"
))]
#![cfg_attr(all(target_os = "android"), doc(
    html_root_url = "http://alexcrichton.com/libc/arm-linux-androideabi"
))]

#[macro_use] mod macros;
mod dox;

#[repr(u8)]
pub enum c_void {
    // Two dummy variants so the #[repr] attribute can be used
    #[doc(hidden)]
    __variant1,
    #[doc(hidden)]
    __variant2,
}

pub type int8_t = i8;
pub type int16_t = i16;
pub type int32_t = i32;
pub type int64_t = i64;
pub type uint8_t = u8;
pub type uint16_t = u16;
pub type uint32_t = u32;
pub type uint64_t = u64;

pub enum FILE {}
pub enum fpos_t {}
pub enum DIR {}
pub enum dirent {}

extern {
    pub fn isalnum(c: c_int) -> c_int;
    pub fn isalpha(c: c_int) -> c_int;
    pub fn iscntrl(c: c_int) -> c_int;
    pub fn isdigit(c: c_int) -> c_int;
    pub fn isgraph(c: c_int) -> c_int;
    pub fn islower(c: c_int) -> c_int;
    pub fn isprint(c: c_int) -> c_int;
    pub fn ispunct(c: c_int) -> c_int;
    pub fn isspace(c: c_int) -> c_int;
    pub fn isupper(c: c_int) -> c_int;
    pub fn isxdigit(c: c_int) -> c_int;
    pub fn tolower(c: c_int) -> c_int;
    pub fn toupper(c: c_int) -> c_int;

    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "fopen$UNIX2003")]
    pub fn fopen(filename: *const c_char,
                 mode: *const c_char) -> *mut FILE;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "freopen$UNIX2003")]
    pub fn freopen(filename: *const c_char, mode: *const c_char,
                   file: *mut FILE) -> *mut FILE;
    pub fn fflush(file: *mut FILE) -> c_int;
    pub fn fclose(file: *mut FILE) -> c_int;
    pub fn remove(filename: *const c_char) -> c_int;
    pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int;
    pub fn tmpfile() -> *mut FILE;
    pub fn setvbuf(stream: *mut FILE,
                   buffer: *mut c_char,
                   mode: c_int,
                   size: size_t) -> c_int;
    pub fn setbuf(stream: *mut FILE, buf: *mut c_char);
    pub fn fgetc(stream: *mut FILE) -> c_int;
    pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char;
    pub fn fputc(c: c_int, stream: *mut FILE) -> c_int;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "fputs$UNIX2003")]
    pub fn fputs(s: *const c_char, stream: *mut FILE)-> c_int;
    pub fn puts(s: *const c_char) -> c_int;
    pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int;
    pub fn fread(ptr: *mut c_void,
                 size: size_t,
                 nobj: size_t,
                 stream: *mut FILE)
                 -> size_t;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "fwrite$UNIX2003")]
    pub fn fwrite(ptr: *const c_void,
                  size: size_t,
                  nobj: size_t,
                  stream: *mut FILE)
                  -> size_t;
    pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int;
    pub fn ftell(stream: *mut FILE) -> c_long;
    pub fn rewind(stream: *mut FILE);
    pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int;
    pub fn fsetpos(stream: *mut FILE, ptr: *const fpos_t) -> c_int;
    pub fn feof(stream: *mut FILE) -> c_int;
    pub fn ferror(stream: *mut FILE) -> c_int;
    pub fn perror(s: *const c_char);
    pub fn atoi(s: *const c_char) -> c_int;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "strtod$UNIX2003")]
    pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double;
    pub fn strtol(s: *const c_char,
                  endp: *mut *mut c_char, base: c_int) -> c_long;
    pub fn strtoul(s: *const c_char, endp: *mut *mut c_char,
                   base: c_int) -> c_ulong;
    pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void;
    pub fn malloc(size: size_t) -> *mut c_void;
    pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void;
    pub fn free(p: *mut c_void);
    pub fn exit(status: c_int) -> !;
    pub fn _exit(status: c_int) -> !;
    pub fn atexit(cb: extern fn()) -> c_int;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "system$UNIX2003")]
    pub fn system(s: *const c_char) -> c_int;
    pub fn getenv(s: *const c_char) -> *mut c_char;

    pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char;
    pub fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t)
                   -> *mut c_char;
    pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char;
    pub fn strncat(s: *mut c_char, ct: *const c_char, n: size_t) -> *mut c_char;
    pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int;
    pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int;
    pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int;
    pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char;
    pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char;
    pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t;
    pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t;
    pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char;
    pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char;
    pub fn strlen(cs: *const c_char) -> size_t;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "strerror$UNIX2003")]
    pub fn strerror(n: c_int) -> *mut c_char;
    pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char;
    pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t;
    pub fn wcslen(buf: *const wchar_t) -> size_t;

    pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int;
    pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void;
}

// These are all inline functions on android
#[cfg(not(target_os = "android"))]
extern {
    pub fn abs(i: c_int) -> c_int;
    pub fn atof(s: *const c_char) -> c_double;
    pub fn labs(i: c_long) -> c_long;
    pub fn rand() -> c_int;
    pub fn srand(seed: c_uint);
}

cfg_if! {
    if #[cfg(windows)] {
        mod windows;
        pub use windows::*;
    } else {
        mod unix;
        pub use unix::*;
    }
}
<commit_msg>i686 => x86<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(bad_style, raw_pointer_derive)]
#![cfg_attr(dox, feature(no_core, lang_items))]
#![cfg_attr(dox, no_core)]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico")]

#![cfg_attr(all(target_os = "linux", target_arch = "x86_64"), doc(
    html_root_url = "http://alexcrichton.com/libc/x86_64-unknown-linux-gnu"
))]
#![cfg_attr(all(target_os = "linux", target_arch = "x86"), doc(
    html_root_url = "http://alexcrichton.com/libc/i686-unknown-linux-gnu"
))]
#![cfg_attr(all(target_os = "linux", target_arch = "arm"), doc(
    html_root_url = "http://alexcrichton.com/libc/arm-unknown-linux-gnueabihf"
))]
#![cfg_attr(all(target_os = "linux", target_arch = "mips"), doc(
    html_root_url = "http://alexcrichton.com/libc/mips-unknown-linux-gnu"
))]
#![cfg_attr(all(target_os = "linux", target_env = "musl"), doc(
    html_root_url = "http://alexcrichton.com/libc/x86_64-unknown-linux-musl"
))]
#![cfg_attr(all(target_os = "macos", target_arch = "x86_64"), doc(
    html_root_url = "http://alexcrichton.com/libc/x86_64-apple-darwin"
))]
#![cfg_attr(all(target_os = "macos", target_arch = "x86"), doc(
    html_root_url = "http://alexcrichton.com/libc/i686-apple-darwin"
))]
#![cfg_attr(all(windows, target_arch = "x86_64", target_env = "gnu"), doc(
    html_root_url = "http://alexcrichton.com/libc/x86_64-pc-windows-gnu"
))]
#![cfg_attr(all(windows, target_arch = "x86", target_env = "gnu"), doc(
    html_root_url = "http://alexcrichton.com/libc/i686-pc-windows-gnu"
))]
#![cfg_attr(all(windows, target_arch = "x86_64", target_env = "msvc"), doc(
    html_root_url = "http://alexcrichton.com/libc/x86_64-pc-windows-msvc"
))]
#![cfg_attr(all(windows, target_arch = "x86", target_env = "msvc"), doc(
    html_root_url = "http://alexcrichton.com/libc/i686-pc-windows-msvc"
))]
#![cfg_attr(all(target_os = "android"), doc(
    html_root_url = "http://alexcrichton.com/libc/arm-linux-androideabi"
))]

#[macro_use] mod macros;
mod dox;

#[repr(u8)]
pub enum c_void {
    // Two dummy variants so the #[repr] attribute can be used
    #[doc(hidden)]
    __variant1,
    #[doc(hidden)]
    __variant2,
}

pub type int8_t = i8;
pub type int16_t = i16;
pub type int32_t = i32;
pub type int64_t = i64;
pub type uint8_t = u8;
pub type uint16_t = u16;
pub type uint32_t = u32;
pub type uint64_t = u64;

pub enum FILE {}
pub enum fpos_t {}
pub enum DIR {}
pub enum dirent {}

extern {
    pub fn isalnum(c: c_int) -> c_int;
    pub fn isalpha(c: c_int) -> c_int;
    pub fn iscntrl(c: c_int) -> c_int;
    pub fn isdigit(c: c_int) -> c_int;
    pub fn isgraph(c: c_int) -> c_int;
    pub fn islower(c: c_int) -> c_int;
    pub fn isprint(c: c_int) -> c_int;
    pub fn ispunct(c: c_int) -> c_int;
    pub fn isspace(c: c_int) -> c_int;
    pub fn isupper(c: c_int) -> c_int;
    pub fn isxdigit(c: c_int) -> c_int;
    pub fn tolower(c: c_int) -> c_int;
    pub fn toupper(c: c_int) -> c_int;

    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "fopen$UNIX2003")]
    pub fn fopen(filename: *const c_char,
                 mode: *const c_char) -> *mut FILE;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "freopen$UNIX2003")]
    pub fn freopen(filename: *const c_char, mode: *const c_char,
                   file: *mut FILE) -> *mut FILE;
    pub fn fflush(file: *mut FILE) -> c_int;
    pub fn fclose(file: *mut FILE) -> c_int;
    pub fn remove(filename: *const c_char) -> c_int;
    pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int;
    pub fn tmpfile() -> *mut FILE;
    pub fn setvbuf(stream: *mut FILE,
                   buffer: *mut c_char,
                   mode: c_int,
                   size: size_t) -> c_int;
    pub fn setbuf(stream: *mut FILE, buf: *mut c_char);
    pub fn fgetc(stream: *mut FILE) -> c_int;
    pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char;
    pub fn fputc(c: c_int, stream: *mut FILE) -> c_int;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "fputs$UNIX2003")]
    pub fn fputs(s: *const c_char, stream: *mut FILE)-> c_int;
    pub fn puts(s: *const c_char) -> c_int;
    pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int;
    pub fn fread(ptr: *mut c_void,
                 size: size_t,
                 nobj: size_t,
                 stream: *mut FILE)
                 -> size_t;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "fwrite$UNIX2003")]
    pub fn fwrite(ptr: *const c_void,
                  size: size_t,
                  nobj: size_t,
                  stream: *mut FILE)
                  -> size_t;
    pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int;
    pub fn ftell(stream: *mut FILE) -> c_long;
    pub fn rewind(stream: *mut FILE);
    pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int;
    pub fn fsetpos(stream: *mut FILE, ptr: *const fpos_t) -> c_int;
    pub fn feof(stream: *mut FILE) -> c_int;
    pub fn ferror(stream: *mut FILE) -> c_int;
    pub fn perror(s: *const c_char);
    pub fn atoi(s: *const c_char) -> c_int;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "strtod$UNIX2003")]
    pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double;
    pub fn strtol(s: *const c_char,
                  endp: *mut *mut c_char, base: c_int) -> c_long;
    pub fn strtoul(s: *const c_char, endp: *mut *mut c_char,
                   base: c_int) -> c_ulong;
    pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void;
    pub fn malloc(size: size_t) -> *mut c_void;
    pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void;
    pub fn free(p: *mut c_void);
    pub fn exit(status: c_int) -> !;
    pub fn _exit(status: c_int) -> !;
    pub fn atexit(cb: extern fn()) -> c_int;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "system$UNIX2003")]
    pub fn system(s: *const c_char) -> c_int;
    pub fn getenv(s: *const c_char) -> *mut c_char;

    pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char;
    pub fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t)
                   -> *mut c_char;
    pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char;
    pub fn strncat(s: *mut c_char, ct: *const c_char, n: size_t) -> *mut c_char;
    pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int;
    pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int;
    pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int;
    pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char;
    pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char;
    pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t;
    pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t;
    pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char;
    pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char;
    pub fn strlen(cs: *const c_char) -> size_t;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "strerror$UNIX2003")]
    pub fn strerror(n: c_int) -> *mut c_char;
    pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char;
    pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t;
    pub fn wcslen(buf: *const wchar_t) -> size_t;

    pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int;
    pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void;
}

// These are all inline functions on android
#[cfg(not(target_os = "android"))]
extern {
    pub fn abs(i: c_int) -> c_int;
    pub fn atof(s: *const c_char) -> c_double;
    pub fn labs(i: c_long) -> c_long;
    pub fn rand() -> c_int;
    pub fn srand(seed: c_uint);
}

cfg_if! {
    if #[cfg(windows)] {
        mod windows;
        pub use windows::*;
    } else {
        mod unix;
        pub use unix::*;
    }
}
<|endoftext|>


<commit_before>//! RethinkDB protocol implementation in Rust

extern crate protobuf;
extern crate serde_json;

pub mod proto;

use serde_json::value::{Value, Map, ToJson};
use protobuf::repeated::RepeatedField;
use protobuf::ProtobufEnum;
use proto::{
    Term, Datum,
    Datum_DatumType as DT,
    Term_TermType as TT,
    Term_AssocPair as TA,
};

macro_rules! command {
    ($T:expr, $cmd:expr, $args:expr) => {{
        let mut term = Term::new();
        term.set_field_type($T);
        let mut args = Vec::new();
        let cmd = $cmd.to();
        if !cmd.is_empty() {
            args.push(cmd);
        }
        if let Some(list) = $args {
            args.extend(list);
        }
        if !args.is_empty() {
            let args = RepeatedField::from_vec(args);
            term.set_args(args);
        }
        FromTerm::from(term)
    }}
}

macro_rules! closure_par {
    () => {{
        // ID
        let mut id = Datum::new();
        id.set_field_type(DT::R_NUM);
        id.set_r_num(1.0);
        // DATUM
        let mut datum = Term::new();
        datum.set_field_type(TT::DATUM);
        datum.set_datum(id);
        // VAR
        let mut var = Term::new();
        var.set_field_type(TT::VAR);
        let args = RepeatedField::from_vec(vec![datum]);
        var.set_args(args);
        var
    }}
}

macro_rules! closure_arg {
    ($func:expr) => {{
        // ID
        let mut id = Datum::new();
        id.set_field_type(DT::R_NUM);
        id.set_r_num(1.0);
        // ARRAY
        let mut array = Datum::new();
        array.set_field_type(DT::R_ARRAY);
        let args = RepeatedField::from_vec(vec![id]);
        array.set_r_array(args);
        // DATUM
        let mut datum = Term::new();
        datum.set_field_type(TT::DATUM);
        datum.set_datum(array);
        // FUNC
        let mut func = Term::new();
        func.set_field_type(TT::FUNC);
        let res = $func(closure_par!());
        let args = RepeatedField::from_vec(vec![datum, res]);
        func.set_args(args);
        vec![func]
    }}
}

pub type Array = Vec<Value>;

pub type Object = Map<String, Value>;

pub trait IsDatum {
    fn is_datum(&self) -> bool;
}

pub trait IsEmpty {
    fn is_empty(&self) -> bool;
}

pub trait Encode {
    fn encode(&self) -> String;
}

pub trait ToTerm {
    fn to(&self) -> Term;
}

pub trait FromTerm {
    fn from(t: Term) -> Self;
}

impl IsDatum for Term {
    fn is_datum(&self) -> bool {
        self.get_field_type() == TT::DATUM
    }
}

impl IsEmpty for Term {
    fn is_empty(&self) -> bool {
        *self == Term::new()
    }
}

impl Encode for Datum {
    fn encode(&self) -> String {
        match self.get_field_type() {
            DT::R_NULL => {
                unimplemented!();
            },
            DT::R_BOOL => {
                if self.has_r_bool() {
                    format!("{:?}", self.get_r_bool())
                } else {
                    unimplemented!();
                }
            },
            DT::R_NUM => {
                if self.has_r_num() {
                    format!("{}", self.get_r_num())
                } else {
                    unimplemented!();
                }
            },
            DT::R_STR => {
                if self.has_r_str() {
                    format!("{:?}", self.get_r_str())
                } else {
                    unimplemented!();
                }
            },
            DT::R_ARRAY => {
                let mut args = format!("[{},[", TT::MAKE_ARRAY.value());
                for term in self.get_r_array() {
                    args.push_str(&format!("{},", term.encode()));
                }
                args = args.trim_right_matches(",").to_string();
                args.push_str("]]");
                args
            },
            DT::R_OBJECT => {
                unimplemented!();
            },
            DT::R_JSON => {
                unimplemented!();
            },
        }
    }
}

impl Encode for Term {
    fn encode(&self) -> String {
        let mut res = String::new();
        if !self.is_datum() {
            res.push_str(&format!("[{},", self.get_field_type().value()));
        }
        let terms = self.get_args();
        if !terms.is_empty() {
            let mut args = String::from("[");
            for term in terms {
                args.push_str(&format!("{},", term.encode()));
            }
            args = args.trim_right_matches(",").to_string();
            args.push_str("]");
            res.push_str(&args);
        }
        if self.has_datum() {
            let datum = self.get_datum();
            res.push_str(&datum.encode());
        }
        if !self.is_datum() {
            res.push_str("]");
        }
        res
    }
}

impl<T: ToJson> ToTerm for T {
    fn to(&self) -> Term {
        // Datum
        let mut datum = Datum::new();
        match self.to_json() {
            Value::String(val) => {
                datum.set_field_type(DT::R_STR);
                datum.set_r_str(val);
            },
            Value::Bool(val) => {
                datum.set_field_type(DT::R_BOOL);
                datum.set_r_bool(val);
            },
            Value::I64(val) => {
                datum.set_field_type(DT::R_NUM);
                datum.set_r_num(val as f64);
            },
            Value::U64(val) => {
                datum.set_field_type(DT::R_NUM);
                datum.set_r_num(val as f64);
            },
            Value::F64(val) => {
                datum.set_field_type(DT::R_NUM);
                datum.set_r_num(val);
            },
            Value::Array(_val) => {
                unimplemented!();
            },
            Value::Object(_val) => {
                unimplemented!();
            },
            Value::Null => {
                datum.set_field_type(DT::R_NULL);
            },
        }
        // Term
        let mut term = Term::new();
        term.set_field_type(TT::DATUM);
        term.set_datum(datum);
        term
    }
}

impl ToTerm for Term {
    fn to(&self) -> Term {
        self.clone()
    }
}

impl FromTerm for Term {
    fn from(t: Term) -> Term {
        t
    }
}

pub trait Command : FromTerm + ToTerm {
    fn expr<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        FromTerm::from(arg.to())
    }

    fn db<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::DB, self, Some(vec![arg.to()]))
    }

    fn db_create<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::DB_CREATE, self, Some(vec![arg.to()]))
    }

    fn db_drop<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::DB_DROP, self, Some(vec![arg.to()]))
    }

    fn table<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::TABLE, self, Some(vec![arg.to()]))
    }

    fn table_create<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::TABLE_CREATE, self, Some(vec![arg.to()]))
    }

    fn table_drop<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::TABLE_DROP, self, Some(vec![arg.to()]))
    }

    fn index_create<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::INDEX_CREATE, self, Some(vec![arg.to()]))
    }

    fn index_drop<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::INDEX_DROP, self, Some(vec![arg.to()]))
    }

    fn replace<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::REPLACE, self, Some(vec![arg.to()]))
    }

    fn update<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::UPDATE, self, Some(vec![arg.to()]))
    }

    fn order_by<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::ORDER_BY, self, Some(vec![arg.to()]))
    }

    fn without<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::WITHOUT, self, Some(vec![arg.to()]))
    }

    fn contains<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::CONTAINS, self, Some(vec![arg.to()]))
    }

    fn limit<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::LIMIT, self, Some(vec![arg.to()]))
    }

    fn get<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::GET, self, Some(vec![arg.to()]))
    }

    fn get_all<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::GET_ALL, self, Some(vec![arg.to()]))
    }

    fn opt_arg<T>(self, name: &str, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        let mut opt = TA::new();
        opt.set_key(name.into());
        opt.set_val(arg.to());
        let arg = RepeatedField::from_vec(vec![opt]);
        let mut term = self.to();
        term.set_optargs(arg);
        FromTerm::from(term)
    }

    fn insert<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::INSERT, self, Some(vec![arg.to()]))
    }

    fn delete(self) -> Self
        where Self: Sized
    {
        command!(TT::DELETE, self, None as Option<Vec<Term>>)
    }

    fn changes(self) -> Self
        where Self: Sized
    {
        command!(TT::CHANGES, self, None as Option<Vec<Term>>)
    }

    fn has_fields<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::HAS_FIELDS, self, Some(vec![arg.to()]))
    }

    fn get_field<T>(self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::GET_FIELD, self, Some(vec![arg.to()]))
    }

    fn filter<F>(self, func: F) -> Self
        where F: FnOnce(Term) -> Term, Self: Sized
    {
        command!(TT::FILTER, self, Some(closure_arg!(func)))
    }

    fn map<F>(self, func: F) -> Self
        where F: FnOnce(Term) -> Term, Self: Sized
    {
        command!(TT::MAP, self, Some(closure_arg!(func)))
    }

    fn branch<T, O>(self, arg: T) -> Self
        where O: ToTerm + Sized, T: IntoIterator<Item=O>, Self: Sized
    {
        let args: Vec<Term> = arg.into_iter()
            .map(|a| a.to())
            .collect();
        command!(TT::BRANCH, self, Some(args))
    }

    fn object<T, O>(self, arg: T) -> Self
        where O: ToTerm + Sized, T: IntoIterator<Item=O>, Self: Sized
    {
        let args: Vec<Term> = arg.into_iter()
            .map(|a| a.to())
            .collect();
        command!(TT::MAKE_OBJ, self, Some(args))
    }

    fn array<T, O>(self, arg: T) -> Self
        where O: ToTerm + Sized, T: IntoIterator<Item=O>, Self: Sized
    {
        let args: Vec<Term> = arg.into_iter()
            .map(|a| a.to())
            .collect();
        command!(TT::MAKE_ARRAY, self, Some(args))
    }
}

#[test]
fn test_commands_can_be_chained() {
    impl Command for Term { }
    let r = Term::new();
    let term = r.db("heroes").table("marvel").map(|row| row.get_field("first_appearance"));
    panic!(format!("{:?}\n\n{}", term, term.encode()));
}
<commit_msg>Add support for objects and arrays<commit_after>//! RethinkDB protocol implementation in Rust

extern crate protobuf;
extern crate serde_json;

pub mod proto;

use std::collections::BTreeMap;

use serde_json::value::{Value, Map, ToJson};
use protobuf::repeated::RepeatedField;
use protobuf::ProtobufEnum;
use proto::{
    Term, Datum,
    Term_TermType as TT,
    Term_AssocPair as TA,
    Datum_DatumType as DT,
    Datum_AssocPair as DA
};

macro_rules! command {
    ($T:expr, $cmd:expr, $args:expr) => {{
        let mut term = Term::new();
        term.set_field_type($T);
        let mut args = Vec::new();
        let cmd = $cmd.to();
        if !cmd.is_empty() {
            args.push(cmd);
        }
        if let Some(list) = $args {
            args.extend(list);
        }
        if !args.is_empty() {
            let args = RepeatedField::from_vec(args);
            term.set_args(args);
        }
        FromTerm::from(term)
    }}
}

macro_rules! closure_par {
    () => {{
        // ID
        let mut id = Datum::new();
        id.set_field_type(DT::R_NUM);
        id.set_r_num(1.0);
        // DATUM
        let mut datum = Term::new();
        datum.set_field_type(TT::DATUM);
        datum.set_datum(id);
        // VAR
        let mut var = Term::new();
        var.set_field_type(TT::VAR);
        let args = RepeatedField::from_vec(vec![datum]);
        var.set_args(args);
        var
    }}
}

macro_rules! closure_arg {
    ($func:expr) => {{
        // ID
        let mut id = Datum::new();
        id.set_field_type(DT::R_NUM);
        id.set_r_num(1.0);
        // ARRAY
        let mut array = Datum::new();
        array.set_field_type(DT::R_ARRAY);
        let args = RepeatedField::from_vec(vec![id]);
        array.set_r_array(args);
        // DATUM
        let mut datum = Term::new();
        datum.set_field_type(TT::DATUM);
        datum.set_datum(array);
        // FUNC
        let mut func = Term::new();
        func.set_field_type(TT::FUNC);
        let res = $func(closure_par!());
        let args = RepeatedField::from_vec(vec![datum, res]);
        func.set_args(args);
        vec![func]
    }}
}

pub type Array = Vec<Value>;

pub type Object = Map<String, Value>;

pub trait IsDatum {
    fn is_datum(&self) -> bool;
}

pub trait IsEmpty {
    fn is_empty(&self) -> bool;
}

pub trait Encode {
    fn encode(&self) -> String;
}

pub trait ToTerm {
    fn to(&self) -> Term;
}

pub trait FromTerm {
    fn from(t: Term) -> Self;
}

impl IsDatum for Term {
    fn is_datum(&self) -> bool {
        self.get_field_type() == TT::DATUM
    }
}

impl IsEmpty for Term {
    fn is_empty(&self) -> bool {
        *self == Term::new()
    }
}

impl Encode for Datum {
    fn encode(&self) -> String {
        match self.get_field_type() {
            DT::R_NULL => {
                unimplemented!();
            },
            DT::R_BOOL => {
                if self.has_r_bool() {
                    format!("{:?}", self.get_r_bool())
                } else {
                    unimplemented!();
                }
            },
            DT::R_NUM => {
                if self.has_r_num() {
                    format!("{}", self.get_r_num())
                } else {
                    unimplemented!();
                }
            },
            DT::R_STR => {
                if self.has_r_str() {
                    format!("{:?}", self.get_r_str())
                } else {
                    unimplemented!();
                }
            },
            DT::R_ARRAY => {
                let mut args = format!("[{},[", TT::MAKE_ARRAY.value());
                for term in self.get_r_array() {
                    args.push_str(&format!("{},", term.encode()));
                }
                args = args.trim_right_matches(",").to_string();
                args.push_str("]]");
                args
            },
            DT::R_OBJECT => {
                let mut args = String::from("{");
                for term in self.get_r_object() {
                    args.push_str(&format!("{:?}: {},", term.get_key(), term.get_val().encode()));
                }
                args = args.trim_right_matches(",").to_string();
                args.push_str("}");
                args
            },
            DT::R_JSON => {
                unimplemented!();
            },
        }
    }
}

impl Encode for Term {
    fn encode(&self) -> String {
        let mut res = String::new();
        if !self.is_datum() {
            res.push_str(&format!("[{},", self.get_field_type().value()));
        }
        let terms = self.get_args();
        if !terms.is_empty() {
            let mut args = String::from("[");
            for term in terms {
                args.push_str(&format!("{},", term.encode()));
            }
            args = args.trim_right_matches(",").to_string();
            args.push_str("]");
            res.push_str(&args);
        }
        if self.has_datum() {
            let datum = self.get_datum();
            res.push_str(&datum.encode());
        }
        if !self.is_datum() {
            res.push_str("]");
        }
        res
    }
}

impl<T: ToJson> ToTerm for T {
    fn to(&self) -> Term {
        // Datum
        let mut datum = Datum::new();
        match self.to_json() {
            Value::String(val) => {
                datum.set_field_type(DT::R_STR);
                datum.set_r_str(val);
            },
            Value::Bool(val) => {
                datum.set_field_type(DT::R_BOOL);
                datum.set_r_bool(val);
            },
            Value::I64(val) => {
                datum.set_field_type(DT::R_NUM);
                datum.set_r_num(val as f64);
            },
            Value::U64(val) => {
                datum.set_field_type(DT::R_NUM);
                datum.set_r_num(val as f64);
            },
            Value::F64(val) => {
                datum.set_field_type(DT::R_NUM);
                datum.set_r_num(val);
            },
            Value::Array(val) => {
                datum.set_field_type(DT::R_ARRAY);
                let args: Vec<Datum> = val.iter()
                    .map(|a| a.to().take_datum())
                    .collect();
                let arr = RepeatedField::from_vec(args);
                datum.set_r_array(arr);
            },
            Value::Object(val) => {
                datum.set_field_type(DT::R_OBJECT);
                let args: Vec<DA> = val.into_iter()
                    .map(|(name, arg)| {
                        let mut obj = DA::new();
                        obj.set_key(name.into());
                        obj.set_val(arg.to().take_datum());
                        obj
                    })
                    .collect();
                let obj = RepeatedField::from_vec(args);
                datum.set_r_object(obj);
            },
            Value::Null => {
                datum.set_field_type(DT::R_NULL);
            },
        }
        // Term
        let mut term = Term::new();
        term.set_field_type(TT::DATUM);
        term.set_datum(datum);
        term
    }
}

impl ToTerm for Term {
    fn to(&self) -> Term {
        self.clone()
    }
}

impl FromTerm for Term {
    fn from(t: Term) -> Term {
        t
    }
}

pub trait Command : FromTerm + ToTerm {
    fn expr<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        FromTerm::from(arg.to())
    }

    fn db<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::DB, self, Some(vec![arg.to()]))
    }

    fn db_create<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::DB_CREATE, self, Some(vec![arg.to()]))
    }

    fn db_drop<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::DB_DROP, self, Some(vec![arg.to()]))
    }

    fn table<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::TABLE, self, Some(vec![arg.to()]))
    }

    fn table_create<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::TABLE_CREATE, self, Some(vec![arg.to()]))
    }

    fn table_drop<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::TABLE_DROP, self, Some(vec![arg.to()]))
    }

    fn index_create<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::INDEX_CREATE, self, Some(vec![arg.to()]))
    }

    fn index_drop<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::INDEX_DROP, self, Some(vec![arg.to()]))
    }

    fn replace<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::REPLACE, self, Some(vec![arg.to()]))
    }

    fn update<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::UPDATE, self, Some(vec![arg.to()]))
    }

    fn order_by<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::ORDER_BY, self, Some(vec![arg.to()]))
    }

    fn without<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::WITHOUT, self, Some(vec![arg.to()]))
    }

    fn contains<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::CONTAINS, self, Some(vec![arg.to()]))
    }

    fn limit<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::LIMIT, self, Some(vec![arg.to()]))
    }

    fn get<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::GET, self, Some(vec![arg.to()]))
    }

    fn get_all<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::GET_ALL, self, Some(vec![arg.to()]))
    }

    fn opt_arg<T>(&self, name: &str, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        let mut opt = TA::new();
        opt.set_key(name.into());
        opt.set_val(arg.to());
        let arg = RepeatedField::from_vec(vec![opt]);
        let mut term = self.to();
        term.set_optargs(arg);
        FromTerm::from(term)
    }

    fn insert<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::INSERT, self, Some(vec![arg.to()]))
    }

    fn delete(&self) -> Self
        where Self: Sized
    {
        command!(TT::DELETE, self, None as Option<Vec<Term>>)
    }

    fn changes(&self) -> Self
        where Self: Sized
    {
        command!(TT::CHANGES, self, None as Option<Vec<Term>>)
    }

    fn has_fields<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::HAS_FIELDS, self, Some(vec![arg.to()]))
    }

    fn get_field<T>(&self, arg: T) -> Self
        where T: ToTerm, Self: Sized
    {
        command!(TT::GET_FIELD, self, Some(vec![arg.to()]))
    }

    fn filter<F>(&self, func: F) -> Self
        where F: FnOnce(Term) -> Term, Self: Sized
    {
        command!(TT::FILTER, self, Some(closure_arg!(func)))
    }

    fn map<F>(&self, func: F) -> Self
        where F: FnOnce(Term) -> Term, Self: Sized
    {
        command!(TT::MAP, self, Some(closure_arg!(func)))
    }

    fn branch<T, O>(&self, arg: T) -> Self
        where O: ToTerm + Sized, T: IntoIterator<Item=O>, Self: Sized
    {
        let args: Vec<Term> = arg.into_iter()
            .map(|a| a.to())
            .collect();
        command!(TT::BRANCH, self, Some(args))
    }

    fn object<'a, T, O>(&self, arg: T) -> Self
        where O: ToJson + Sized, T: IntoIterator<Item=(&'a str, O)>, Self: Sized
    {
        let mut obj = BTreeMap::new();
        for (key, val) in arg {
            obj.insert(key.to_string(), val.to_json());
        }
        let obj = Value::Object(obj);
        FromTerm::from(obj.to())
    }

    fn array<T, O>(&self, arg: T) -> Self
        where O: ToJson + Sized, T: IntoIterator<Item=O>, Self: Sized
    {
        let args: Vec<Value> = arg.into_iter()
            .map(|a| a.to_json())
            .collect();
        let arr = Value::Array(args);
        FromTerm::from(arr.to())
    }
}

#[test]
fn test_commands_can_be_chained() {
    impl Command for Term { }
    let r = Term::new();
    let term = r.db("heroes").table("marvel").map(|row| row.get_field("first_appearance"));
    panic!(format!("{:?}\n\n{}", term, term.encode()));
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! ## mysql-async
//! Tokio based asynchronous MySql client library for rust programming language.
//!
//! ### Installation
//! Library hosted on [crates.io](https://crates.io/crates/mysql_async/).
//!
//! ```toml
//! [dependencies]
//! mysql_async = "<desired version>"
//! ```
//!
//! ### Example
//!
//! ```rust
//! extern crate futures;
//! #[macro_use]
//! extern crate mysql_async as my;
//! extern crate tokio;
//! // ...
//!
//! use futures::Future;
//! use my::prelude::*;
//! # use std::env;
//!
//! #[derive(Debug, PartialEq, Eq, Clone)]
//! struct Payment {
//!     customer_id: i32,
//!     amount: i32,
//!     account_name: Option<String>,
//! }
//!
//! /// Same as `tokio::run`, but will panic if future panics and will return the result
//! /// of future execution.
//! pub fn run<F, T, U>(future: F) -> Result<T, U>
//! where
//!     F: Future<Item = T, Error = U> + Send + 'static,
//!     T: Send + 'static,
//!     U: Send + 'static,
//! {
//!     let mut runtime = tokio::runtime::Runtime::new().unwrap();
//!     let result = runtime.block_on(future);
//!     runtime.shutdown_on_idle().wait().unwrap();
//!     result
//! }
//!
//! fn main() {
//!     let payments = vec![
//!         Payment { customer_id: 1, amount: 2, account_name: None },
//!         Payment { customer_id: 3, amount: 4, account_name: Some("foo".into()) },
//!         Payment { customer_id: 5, amount: 6, account_name: None },
//!         Payment { customer_id: 7, amount: 8, account_name: None },
//!         Payment { customer_id: 9, amount: 10, account_name: Some("bar".into()) },
//!     ];
//!     let payments_clone = payments.clone();
//!
//!     # let database_url: String = if let Ok(url) = env::var("DATABASE_URL") {
//!     #     let opts = my::Opts::from_url(&url).expect("DATABASE_URL invalid");
//!     #     if opts.get_db_name().expect("a database name is required").is_empty() {
//!     #         panic!("database name is empty");
//!     #     }
//!     #     url
//!     # } else {
//!     #     "mysql://root:password@127.0.0.1:3307/mysql".into()
//!     # };
//!
//!     let pool = my::Pool::new(database_url);
//!     let future = pool.get_conn().and_then(|conn| {
//!         // Create temporary table
//!         conn.drop_query(
//!             r"CREATE TEMPORARY TABLE payment (
//!                 customer_id int not null,
//!                 amount int not null,
//!                 account_name text
//!             )"
//!         )
//!     }).and_then(move |conn| {
//!         // Save payments
//!         let params = payments_clone.into_iter().map(|payment| {
//!             params! {
//!                 "customer_id" => payment.customer_id,
//!                 "amount" => payment.amount,
//!                 "account_name" => payment.account_name.clone(),
//!             }
//!         });
//!
//!         conn.batch_exec(r"INSERT INTO payment (customer_id, amount, account_name)
//!                         VALUES (:customer_id, :amount, :account_name)", params)
//!     }).and_then(|conn| {
//!         // Load payments from database.
//!         conn.prep_exec("SELECT customer_id, amount, account_name FROM payment", ())
//!     }).and_then(|result| {
//!         // Collect payments
//!         result.map_and_drop(|row| {
//!             let (customer_id, amount, account_name) = my::from_row(row);
//!             Payment {
//!                 customer_id: customer_id,
//!                 amount: amount,
//!                 account_name: account_name,
//!             }
//!         })
//!     }).and_then(|(_ /* conn */, payments)| {
//!         // The destructor of a connection will return it to the pool,
//!         // but pool should be disconnected explicitly because it's
//!         // an asynchronous procedure.
//!         pool.disconnect().map(|_| payments)
//!     });
//!
//!     let loaded_payments = run(future).unwrap();
//!     assert_eq!(loaded_payments, payments);
//! }
//! ```

#![recursion_limit = "1024"]
#![cfg_attr(feature = "nightly", feature(test, const_fn))]

#[cfg(feature = "nightly")]
extern crate test;

pub use mysql_common::{chrono, constants as consts, params, time, uuid};

#[macro_use]
mod macros;
mod conn;
mod connection_like;
/// Errors used in this crate
pub mod error;
mod io;
mod local_infile_handler;
mod opts;
mod queryable;

pub type BoxFuture<T> = Box<dyn ::futures::Future<Item = T, Error = error::Error> + Send + 'static>;

/// Alias for `Future` with library error as `Future::Error`.
pub trait MyFuture<T>: ::futures::Future<Item = T, Error = error::Error> + Send + 'static {}
impl<T, U> MyFuture<T> for U where
    U: ::futures::Future<Item = T, Error = error::Error> + Send + 'static
{
}

#[doc(inline)]
pub use self::conn::Conn;

#[doc(inline)]
pub use self::conn::pool::Pool;

#[doc(inline)]
pub use self::queryable::transaction::IsolationLevel;

#[doc(inline)]
pub use self::opts::{Opts, OptsBuilder, SslOpts};

#[doc(inline)]
pub use self::local_infile_handler::builtin::WhiteListFsLocalInfileHandler;

#[doc(inline)]
pub use mysql_common::packets::Column;

#[doc(inline)]
pub use mysql_common::row::Row;

#[doc(inline)]
pub use mysql_common::params::Params;

#[doc(inline)]
pub use mysql_common::value::Value;

#[doc(inline)]
pub use mysql_common::row::convert::{from_row, from_row_opt, FromRowError};

#[doc(inline)]
pub use mysql_common::value::convert::{from_value, from_value_opt, FromValueError};

#[doc(inline)]
pub use mysql_common::value::json::{Deserialized, Serialized};

#[doc(inline)]
pub use self::queryable::query_result::QueryResult;

#[doc(inline)]
pub use self::queryable::transaction::{Transaction, TransactionOptions};

#[doc(inline)]
pub use self::queryable::{BinaryProtocol, TextProtocol};

#[doc(inline)]
pub use self::queryable::stmt::Stmt;

/// Futures used in this crate
pub mod futures {
    pub use crate::queryable::query_result::{
        ForEach, ForEachAndDrop, Map, MapAndDrop, Reduce, ReduceAndDrop,
    };
}

/// Traits used in this crate
pub mod prelude {
    #[doc(inline)]
    pub use crate::local_infile_handler::LocalInfileHandler;
    #[doc(inline)]
    pub use crate::queryable::Queryable;
    #[doc(inline)]
    pub use mysql_common::row::convert::FromRow;
    #[doc(inline)]
    pub use mysql_common::value::convert::{ConvIr, FromValue, ToValue};
}

#[cfg(test)]
mod test_misc {
    use lazy_static::lazy_static;

    use std::env;

    use crate::opts;

    #[allow(dead_code)]
    fn error_should_implement_send_and_sync() {
        fn _dummy<T: Send + Sync>(_: T) {}
        _dummy(crate::error::Error::from("foo"));
    }

    lazy_static! {
        pub static ref DATABASE_URL: String = {
            if let Ok(url) = env::var("DATABASE_URL") {
                let opts = opts::Opts::from_url(&url).expect("DATABASE_URL invalid");
                if opts
                    .get_db_name()
                    .expect("a database name is required")
                    .is_empty()
                {
                    panic!("database name is empty");
                }
                url
            } else {
                "mysql://root:password@127.0.0.1:3307/mysql".into()
            }
        };
    }
}
<commit_msg>Publish PoolConstraints<commit_after>// Copyright (c) 2016 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! ## mysql-async
//! Tokio based asynchronous MySql client library for rust programming language.
//!
//! ### Installation
//! Library hosted on [crates.io](https://crates.io/crates/mysql_async/).
//!
//! ```toml
//! [dependencies]
//! mysql_async = "<desired version>"
//! ```
//!
//! ### Example
//!
//! ```rust
//! extern crate futures;
//! #[macro_use]
//! extern crate mysql_async as my;
//! extern crate tokio;
//! // ...
//!
//! use futures::Future;
//! use my::prelude::*;
//! # use std::env;
//!
//! #[derive(Debug, PartialEq, Eq, Clone)]
//! struct Payment {
//!     customer_id: i32,
//!     amount: i32,
//!     account_name: Option<String>,
//! }
//!
//! /// Same as `tokio::run`, but will panic if future panics and will return the result
//! /// of future execution.
//! pub fn run<F, T, U>(future: F) -> Result<T, U>
//! where
//!     F: Future<Item = T, Error = U> + Send + 'static,
//!     T: Send + 'static,
//!     U: Send + 'static,
//! {
//!     let mut runtime = tokio::runtime::Runtime::new().unwrap();
//!     let result = runtime.block_on(future);
//!     runtime.shutdown_on_idle().wait().unwrap();
//!     result
//! }
//!
//! fn main() {
//!     let payments = vec![
//!         Payment { customer_id: 1, amount: 2, account_name: None },
//!         Payment { customer_id: 3, amount: 4, account_name: Some("foo".into()) },
//!         Payment { customer_id: 5, amount: 6, account_name: None },
//!         Payment { customer_id: 7, amount: 8, account_name: None },
//!         Payment { customer_id: 9, amount: 10, account_name: Some("bar".into()) },
//!     ];
//!     let payments_clone = payments.clone();
//!
//!     # let database_url: String = if let Ok(url) = env::var("DATABASE_URL") {
//!     #     let opts = my::Opts::from_url(&url).expect("DATABASE_URL invalid");
//!     #     if opts.get_db_name().expect("a database name is required").is_empty() {
//!     #         panic!("database name is empty");
//!     #     }
//!     #     url
//!     # } else {
//!     #     "mysql://root:password@127.0.0.1:3307/mysql".into()
//!     # };
//!
//!     let pool = my::Pool::new(database_url);
//!     let future = pool.get_conn().and_then(|conn| {
//!         // Create temporary table
//!         conn.drop_query(
//!             r"CREATE TEMPORARY TABLE payment (
//!                 customer_id int not null,
//!                 amount int not null,
//!                 account_name text
//!             )"
//!         )
//!     }).and_then(move |conn| {
//!         // Save payments
//!         let params = payments_clone.into_iter().map(|payment| {
//!             params! {
//!                 "customer_id" => payment.customer_id,
//!                 "amount" => payment.amount,
//!                 "account_name" => payment.account_name.clone(),
//!             }
//!         });
//!
//!         conn.batch_exec(r"INSERT INTO payment (customer_id, amount, account_name)
//!                         VALUES (:customer_id, :amount, :account_name)", params)
//!     }).and_then(|conn| {
//!         // Load payments from database.
//!         conn.prep_exec("SELECT customer_id, amount, account_name FROM payment", ())
//!     }).and_then(|result| {
//!         // Collect payments
//!         result.map_and_drop(|row| {
//!             let (customer_id, amount, account_name) = my::from_row(row);
//!             Payment {
//!                 customer_id: customer_id,
//!                 amount: amount,
//!                 account_name: account_name,
//!             }
//!         })
//!     }).and_then(|(_ /* conn */, payments)| {
//!         // The destructor of a connection will return it to the pool,
//!         // but pool should be disconnected explicitly because it's
//!         // an asynchronous procedure.
//!         pool.disconnect().map(|_| payments)
//!     });
//!
//!     let loaded_payments = run(future).unwrap();
//!     assert_eq!(loaded_payments, payments);
//! }
//! ```

#![recursion_limit = "1024"]
#![cfg_attr(feature = "nightly", feature(test, const_fn))]

#[cfg(feature = "nightly")]
extern crate test;

pub use mysql_common::{chrono, constants as consts, params, time, uuid};

#[macro_use]
mod macros;
mod conn;
mod connection_like;
/// Errors used in this crate
pub mod error;
mod io;
mod local_infile_handler;
mod opts;
mod queryable;

pub type BoxFuture<T> = Box<dyn ::futures::Future<Item = T, Error = error::Error> + Send + 'static>;

/// Alias for `Future` with library error as `Future::Error`.
pub trait MyFuture<T>: ::futures::Future<Item = T, Error = error::Error> + Send + 'static {}
impl<T, U> MyFuture<T> for U where
    U: ::futures::Future<Item = T, Error = error::Error> + Send + 'static
{
}

#[doc(inline)]
pub use self::conn::Conn;

#[doc(inline)]
pub use self::conn::pool::Pool;

#[doc(inline)]
pub use self::queryable::transaction::IsolationLevel;

#[doc(inline)]
pub use self::opts::{Opts, OptsBuilder, PoolConstraints, SslOpts};

#[doc(inline)]
pub use self::local_infile_handler::builtin::WhiteListFsLocalInfileHandler;

#[doc(inline)]
pub use mysql_common::packets::Column;

#[doc(inline)]
pub use mysql_common::row::Row;

#[doc(inline)]
pub use mysql_common::params::Params;

#[doc(inline)]
pub use mysql_common::value::Value;

#[doc(inline)]
pub use mysql_common::row::convert::{from_row, from_row_opt, FromRowError};

#[doc(inline)]
pub use mysql_common::value::convert::{from_value, from_value_opt, FromValueError};

#[doc(inline)]
pub use mysql_common::value::json::{Deserialized, Serialized};

#[doc(inline)]
pub use self::queryable::query_result::QueryResult;

#[doc(inline)]
pub use self::queryable::transaction::{Transaction, TransactionOptions};

#[doc(inline)]
pub use self::queryable::{BinaryProtocol, TextProtocol};

#[doc(inline)]
pub use self::queryable::stmt::Stmt;

/// Futures used in this crate
pub mod futures {
    pub use crate::queryable::query_result::{
        ForEach, ForEachAndDrop, Map, MapAndDrop, Reduce, ReduceAndDrop,
    };
}

/// Traits used in this crate
pub mod prelude {
    #[doc(inline)]
    pub use crate::local_infile_handler::LocalInfileHandler;
    #[doc(inline)]
    pub use crate::queryable::Queryable;
    #[doc(inline)]
    pub use mysql_common::row::convert::FromRow;
    #[doc(inline)]
    pub use mysql_common::value::convert::{ConvIr, FromValue, ToValue};
}

#[cfg(test)]
mod test_misc {
    use lazy_static::lazy_static;

    use std::env;

    use crate::opts;

    #[allow(dead_code)]
    fn error_should_implement_send_and_sync() {
        fn _dummy<T: Send + Sync>(_: T) {}
        _dummy(crate::error::Error::from("foo"));
    }

    lazy_static! {
        pub static ref DATABASE_URL: String = {
            if let Ok(url) = env::var("DATABASE_URL") {
                let opts = opts::Opts::from_url(&url).expect("DATABASE_URL invalid");
                if opts
                    .get_db_name()
                    .expect("a database name is required")
                    .is_empty()
                {
                    panic!("database name is empty");
                }
                url
            } else {
                "mysql://root:password@127.0.0.1:3307/mysql".into()
            }
        };
    }
}
<|endoftext|>


<commit_before>use std::thread;
use std::sync::mpsc;

pub fn pihex(d: u32) -> String {
    let (tx, rx) = mpsc::channel();
    for &(j, k) in &[(1, 4.0), (4, -2.0), (5, -1.0), (6, -1.0)] {
        let tx = tx.clone();
        thread::spawn(move || tx.send(k * series_sum(d, j as u32)).unwrap());
    }
    drop(tx);
    let fraction: f64 = rx.iter().sum();
    (0..4)
        .scan(fraction, |x, _| {
            *x = (*x - x.floor()) * 16.0;
            Some(format!("{:x}", x.floor() as u64))
        })
        .fold(String::new(), |s, t| s + &t)
}

fn series_sum(d: u32, j: u32) -> f64 {
    let fraction1: f64 = (0..d + 1)
        .map(|i| (powmod(16, d - i, (8 * i + j) as u64) as f64) / ((8 * i + j) as f64))
        .sum();
    let fraction2: f64 = (d + 1..)
        .map(|i| 16.0_f64.powi(d as i32 - i as i32) / ((8 * i + j) as f64))
        .take_while(|&x| x > 1e-13_f64)
        .sum();
    (fraction1 + fraction2).fract()
}

fn powmod(n: u64, m: u32, d: u64) -> u64 {
    if m == 0 {
        1 % d
    } else if m == 1 {
        n % d
    } else {
        let k: u64 = powmod(n, m / 2, d);
        if m % 2 == 0 {
            (k * k) % d
        } else {
            (k * k * n) % d
        }
    }
}
<commit_msg>fix a precision bug: instead of taking fraction after summation, take fraction each time<commit_after>use std::thread;
use std::sync::mpsc;

pub fn pihex(d: u32) -> String {
    let (tx, rx) = mpsc::channel();
    for &(j, k) in &[(1, 4.0), (4, -2.0), (5, -1.0), (6, -1.0)] {
        let tx = tx.clone();
        thread::spawn(move || tx.send(k * series_sum(d, j as u32)).unwrap());
    }
    drop(tx);
    let fraction: f64 = rx.iter().sum();
    (0..4)
        .scan(fraction, |x, _| {
            *x = (*x - x.floor()) * 16.0;
            Some(format!("{:x}", x.floor() as u64))
        })
        .fold(String::new(), |s, t| s + &t)
}

fn series_sum(d: u32, j: u32) -> f64 {
    let fraction1: f64 = (0..d + 1)
        .map(|i| (powmod(16, d - i, (8 * i + j) as u64) as f64) / ((8 * i + j) as f64))
        .fold(0.0, |x, y| (x + y).fract());
    let fraction2: f64 = (d + 1..)
        .map(|i| 16.0_f64.powi(d as i32 - i as i32) / ((8 * i + j) as f64))
        .take_while(|&x| x > 1e-13_f64)
        .sum();
    fraction1 + fraction2
}

fn powmod(n: u64, m: u32, d: u64) -> u64 {
    if m == 0 {
        1 % d
    } else if m == 1 {
        n % d
    } else {
        let k: u64 = powmod(n, m / 2, d);
        if m % 2 == 0 {
            (k * k) % d
        } else {
            (k * k * n) % d
        }
    }
}
<|endoftext|>