<commit_before>//! Nom, eating data byte by byte
//!
//! The goal is to make a parser combinator library that is safe,
//! supports streaming (push and pull), and as much as possible zero copy.
//!
//! The code is available on [Github](https://github.com/Geal/nom)
//!
//! # Example
//!
//! ```
//! #[macro_use]
//! extern crate nom;
//!
//! use nom::{IResult,digit,multispace};
//! use nom::IResult::*;
//!
//! // Parser definition
//!
//! use std::str;
//! use std::str::FromStr;
//!
//! named!(parens<i64>, delimited!(
//!     delimited!(opt!(multispace), tag!("("), opt!(multispace)),
//!     expr,
//!     delimited!(opt!(multispace), tag!(")"), opt!(multispace))
//!   )
//! );
//!
//! // We transform an integer string into a i64
//! // we look for a digit suite, and try to convert it.
//! // if either str::from_utf8 or FromStr::from_str fail,
//! // the parser will fail
//! named!(factor<i64>,
//!   alt!(
//!     map_res!(
//!       map_res!(
//!         delimited!(opt!(multispace), digit, opt!(multispace)),
//!         str::from_utf8
//!       ),
//!       FromStr::from_str
//!     )
//!   | parens
//!   )
//! );
//!
//! // we define acc as mutable to update its value whenever a new term is found
//! named!(term <i64>,
//!   chain!(
//!     mut acc: factor  ~
//!              many0!(
//!                alt!(
//!                  tap!(mul: preceded!(tag!("*"), factor) => acc = acc * mul) |
//!                  tap!(div: preceded!(tag!("/"), factor) => acc = acc / div)
//!                )
//!              ),
//!     || { return acc }
//!   )
//! );
//!
//! named!(expr <i64>,
//!   chain!(
//!     mut acc: term  ~
//!              many0!(
//!                alt!(
//!                  tap!(add: preceded!(tag!("+"), term) => acc = acc + add) |
//!                  tap!(sub: preceded!(tag!("-"), term) => acc = acc - sub)
//!                )
//!              ),
//!     || { return acc }
//!   )
//! );
//!
//! fn main() {
//!   assert_eq!(expr(&b" 1 +  2 "[..]),             IResult::Done(&b""[..], 3));
//!   assert_eq!(expr(&b" 12 + 6 - 4+  3"[..]),      IResult::Done(&b""[..], 17));
//!   assert_eq!(expr(&b" 1 + 2*3 + 4"[..]),         IResult::Done(&b""[..], 11));
//!
//!   assert_eq!(expr(&b" (  2 )"[..]),              IResult::Done(&b""[..], 2));
//!   assert_eq!(expr(&b" 2* (  3 + 4 ) "[..]),      IResult::Done(&b""[..], 14));
//!   assert_eq!(expr(&b"  2*2 / ( 5 - 1) + 3"[..]), IResult::Done(&b""[..], 4));
//! }
//! ```
#![cfg_attr(feature = "core", feature(no_std))]
#![cfg_attr(feature = "core", feature(collections))]
#![cfg_attr(feature = "core", no_std)]
#![cfg_attr(feature = "regexp_macros", feature(plugin))]
#![cfg_attr(feature = "regexp_macros", plugin(regex_macros))]
#![cfg_attr(feature = "nightly", feature(test))]

#[cfg(feature = "core")]
extern crate collections;
#[cfg(feature = "regexp")]
extern crate regex;
#[cfg(feature = "nightly")]
extern crate test;

#[cfg(feature = "core")]
mod std {
#[macro_use]
  pub use core::{fmt, iter, option, ops, slice, mem};
  pub use collections::{boxed, vec, string};
  pub mod prelude {
    pub use core::prelude as v1;
  }
}

pub use self::util::*;
pub use self::internal::*;
pub use self::macros::*;
pub use self::bytes::*;
pub use self::bits::*;

pub use self::nom::*;
pub use self::character::*;

#[cfg(feature = "regexp")]
pub use self::regexp::*;

#[cfg(not(feature = "core"))]
#[cfg(feature = "stream")]
pub use self::stream::*;

#[macro_use] mod util;
mod internal;
#[macro_use] mod macros;
#[macro_use] mod bytes;
#[macro_use] mod bits;

#[macro_use] mod nom;
#[macro_use] mod character;

#[cfg(feature = "regexp")]
#[macro_use] mod regexp;

#[macro_use]
#[cfg(not(feature = "core"))]
#[cfg(feature = "stream")]
mod stream;
<commit_msg>Added the str module to the project.<commit_after>//! Nom, eating data byte by byte
//!
//! The goal is to make a parser combinator library that is safe,
//! supports streaming (push and pull), and as much as possible zero copy.
//!
//! The code is available on [Github](https://github.com/Geal/nom)
//!
//! # Example
//!
//! ```
//! #[macro_use]
//! extern crate nom;
//!
//! use nom::{IResult,digit,multispace};
//! use nom::IResult::*;
//!
//! // Parser definition
//!
//! use std::str;
//! use std::str::FromStr;
//!
//! named!(parens<i64>, delimited!(
//!     delimited!(opt!(multispace), tag!("("), opt!(multispace)),
//!     expr,
//!     delimited!(opt!(multispace), tag!(")"), opt!(multispace))
//!   )
//! );
//!
//! // We transform an integer string into a i64
//! // we look for a digit suite, and try to convert it.
//! // if either str::from_utf8 or FromStr::from_str fail,
//! // the parser will fail
//! named!(factor<i64>,
//!   alt!(
//!     map_res!(
//!       map_res!(
//!         delimited!(opt!(multispace), digit, opt!(multispace)),
//!         str::from_utf8
//!       ),
//!       FromStr::from_str
//!     )
//!   | parens
//!   )
//! );
//!
//! // we define acc as mutable to update its value whenever a new term is found
//! named!(term <i64>,
//!   chain!(
//!     mut acc: factor  ~
//!              many0!(
//!                alt!(
//!                  tap!(mul: preceded!(tag!("*"), factor) => acc = acc * mul) |
//!                  tap!(div: preceded!(tag!("/"), factor) => acc = acc / div)
//!                )
//!              ),
//!     || { return acc }
//!   )
//! );
//!
//! named!(expr <i64>,
//!   chain!(
//!     mut acc: term  ~
//!              many0!(
//!                alt!(
//!                  tap!(add: preceded!(tag!("+"), term) => acc = acc + add) |
//!                  tap!(sub: preceded!(tag!("-"), term) => acc = acc - sub)
//!                )
//!              ),
//!     || { return acc }
//!   )
//! );
//!
//! fn main() {
//!   assert_eq!(expr(&b" 1 +  2 "[..]),             IResult::Done(&b""[..], 3));
//!   assert_eq!(expr(&b" 12 + 6 - 4+  3"[..]),      IResult::Done(&b""[..], 17));
//!   assert_eq!(expr(&b" 1 + 2*3 + 4"[..]),         IResult::Done(&b""[..], 11));
//!
//!   assert_eq!(expr(&b" (  2 )"[..]),              IResult::Done(&b""[..], 2));
//!   assert_eq!(expr(&b" 2* (  3 + 4 ) "[..]),      IResult::Done(&b""[..], 14));
//!   assert_eq!(expr(&b"  2*2 / ( 5 - 1) + 3"[..]), IResult::Done(&b""[..], 4));
//! }
//! ```
#![cfg_attr(feature = "core", feature(no_std))]
#![cfg_attr(feature = "core", feature(collections))]
#![cfg_attr(feature = "core", no_std)]
#![cfg_attr(feature = "regexp_macros", feature(plugin))]
#![cfg_attr(feature = "regexp_macros", plugin(regex_macros))]
#![cfg_attr(feature = "nightly", feature(test))]

#[cfg(feature = "core")]
extern crate collections;
#[cfg(feature = "regexp")]
extern crate regex;
#[cfg(feature = "nightly")]
extern crate test;

#[cfg(feature = "core")]
mod std {
#[macro_use]
  pub use core::{fmt, iter, option, ops, slice, mem};
  pub use collections::{boxed, vec, string};
  pub mod prelude {
    pub use core::prelude as v1;
  }
}

pub use self::util::*;
pub use self::internal::*;
pub use self::macros::*;
pub use self::bytes::*;
pub use self::bits::*;

pub use self::nom::*;
pub use self::character::*;

#[cfg(feature = "regexp")]
pub use self::regexp::*;

#[cfg(not(feature = "core"))]
#[cfg(feature = "stream")]
pub use self::stream::*;

#[macro_use] mod util;
mod internal;
#[macro_use] mod macros;
#[macro_use] mod bytes;
#[macro_use] mod bits;

#[macro_use] mod nom;
#[macro_use] mod character;

#[cfg(feature = "regexp")]
#[macro_use] mod regexp;

#[macro_use]
#[cfg(not(feature = "core"))]
#[cfg(feature = "stream")]
mod stream;

#[cfg(not(feature = "core"))]
mod str;
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![cfg_attr(test, deny(warnings))]
#![doc(html_root_url = "https://docs.rs/reqwest/0.9.5")]

//! # reqwest
//!
//! The `reqwest` crate provides a convenient, higher-level HTTP Client.
//!
//! It handles many of the things that most people just expect an HTTP client
//! to do for them.
//!
//! - Uses system-native TLS
//! - Plain bodies, JSON, urlencoded, multipart
//! - Customizable redirect policy
//! - Proxies
//! - Cookies (only rudimentary support, full support is TODO)
//!
//! The rudimentary cookie support means that the cookies need to be manually
//! configured for every single request. In other words, there's no cookie jar
//! support as of now. The tracking issue for this feature is available
//! [on GitHub][cookiejar_issue].
//!
//! The `reqwest::Client` is synchronous, making it a great fit for
//! applications that only require a few HTTP requests, and wish to handle
//! them synchronously.
//!
//! ## Making a GET request
//!
//! For a single request, you can use the [`get`][get] shortcut method.
//!
//! ```rust
//! # use reqwest::{Error, Response};
//!
//! # fn run() -> Result<(), Error> {
//! let body = reqwest::get("https://www.rust-lang.org")?
//!     .text()?;
//!
//! println!("body = {:?}", body);
//! # Ok(())
//! # }
//! ```
//!
//! Additionally, reqwest's [`Response`][response] struct implements Rust's
//! `Read` trait, so many useful standard library and third party crates will
//! have convenience methods that take a `Response` anywhere `T: Read` is
//! acceptable.
//!
//! **NOTE**: If you plan to perform multiple requests, it is best to create a
//! [`Client`][client] and reuse it, taking advantage of keep-alive connection
//! pooling.
//!
//! ## Making POST requests (or setting request bodies)
//!
//! There are several ways you can set the body of a request. The basic one is
//! by using the `body()` method of a [`RequestBuilder`][builder]. This lets you set the
//! exact raw bytes of what the body should be. It accepts various types,
//! including `String`, `Vec<u8>`, and `File`. If you wish to pass a custom
//! Reader, you can use the `reqwest::Body::new()` constructor.
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # fn run() -> Result<(), Error> {
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .body("the exact body that is sent")
//!     .send()?;
//! # Ok(())
//! # }
//! ```
//!
//! ### Forms
//!
//! It's very common to want to send form data in a request body. This can be
//! done with any type that can be serialized into form data.
//!
//! This can be an array of tuples, or a `HashMap`, or a custom type that
//! implements [`Serialize`][serde].
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # fn run() -> Result<(), Error> {
//! // This will POST a body of `foo=bar&baz=quux`
//! let params = [("foo", "bar"), ("baz", "quux")];
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .form(&params)
//!     .send()?;
//! # Ok(())
//! # }
//! ```
//!
//! ### JSON
//!
//! There is also a `json` method helper on the [`RequestBuilder`][builder] that works in
//! a similar fashion the `form` method. It can take any value that can be
//! serialized into JSON.
//!
//! ```rust
//! # use reqwest::Error;
//! # use std::collections::HashMap;
//! #
//! # fn run() -> Result<(), Error> {
//! // This will POST a body of `{"lang":"rust","body":"json"}`
//! let mut map = HashMap::new();
//! map.insert("lang", "rust");
//! map.insert("body", "json");
//!
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .json(&map)
//!     .send()?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Optional Features
//!
//! The following are a list of [Cargo features][cargo-features] that can be
//! enabled or disabled:
//!
//! - **default-tls** *(enabled by default)*: Provides TLS support via the
//!   `native-tls` library to connect over HTTPS.
//! - **hyper-011**: Provides support for hyper's old typed headers.
//!
//!
//! [hyper]: http://hyper.rs
//! [client]: ./struct.Client.html
//! [response]: ./struct.Response.html
//! [get]: ./fn.get.html
//! [builder]: ./struct.RequestBuilder.html
//! [serde]: http://serde.rs
//! [cookiejar_issue]: https://github.com/seanmonstar/reqwest/issues/14
//! [cargo-features]: https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section

extern crate base64;
extern crate bytes;
extern crate encoding_rs;
#[macro_use]
extern crate futures;
extern crate http;
extern crate hyper;
#[cfg(feature = "hyper-011")]
pub extern crate hyper_old_types as hyper_011;
#[cfg(feature = "default-tls")]
extern crate hyper_tls;
#[macro_use]
extern crate log;
extern crate libflate;
extern crate mime;
extern crate mime_guess;
#[cfg(feature = "default-tls")]
extern crate native_tls;
extern crate serde;
#[cfg(test)]
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde_urlencoded;
extern crate tokio;
#[cfg_attr(feature = "default-tls", macro_use)]
extern crate tokio_io;
extern crate trust_dns_resolver;
extern crate url;
extern crate uuid;

#[cfg(feature = "rustls-tls")]
extern crate hyper_rustls;
#[cfg(feature = "rustls-tls")]
extern crate tokio_rustls;
#[cfg(feature = "rustls-tls")]
extern crate webpki_roots;
#[cfg(feature = "rustls-tls")]
extern crate rustls;

pub use hyper::header;
pub use hyper::Method;
pub use hyper::{StatusCode, Version};
pub use url::Url;
pub use url::ParseError as UrlError;

pub use self::client::{Client, ClientBuilder};
pub use self::error::{Error, Result};
pub use self::body::Body;
pub use self::into_url::IntoUrl;
pub use self::proxy::Proxy;
pub use self::redirect::{RedirectAction, RedirectAttempt, RedirectPolicy};
pub use self::request::{Request, RequestBuilder};
pub use self::response::Response;
#[cfg(feature = "tls")]
pub use self::tls::{Certificate, Identity};

// this module must be first because of the `try_` macro
#[macro_use]
mod error;

mod async_impl;
mod connect;
#[cfg(feature = "default-tls")]
mod connect_async;
mod body;
mod client;
mod dns;
mod into_url;
mod proxy;
mod redirect;
mod request;
mod response;
#[cfg(feature = "tls")]
mod tls;
mod wait;

pub mod multipart;

/// An 'async' implementation of the reqwest `Client`.
///
/// Relies on the `futures` crate, which is unstable, hence this module
/// is **unstable**.
pub mod async {
    pub use ::async_impl::{
        Body,
        Chunk,
        Decoder,
        Client,
        ClientBuilder,
        Request,
        RequestBuilder,
        Response,
        ResponseBuilderExt,
    };
}

/// Shortcut method to quickly make a `GET` request.
///
/// See also the methods on the [`reqwest::Response`](./struct.Response.html)
/// type.
///
/// **NOTE**: This function creates a new internal `Client` on each call,
/// and so should not be used if making many requests. Create a
/// [`Client`](./struct.Client.html) instead.
///
/// # Examples
///
/// ```rust
/// # fn run() -> Result<(), reqwest::Error> {
/// let body = reqwest::get("https://www.rust-lang.org")?
///     .text()?;
/// # Ok(())
/// # }
/// # fn main() { }
/// ```
///
/// # Errors
///
/// This function fails if:
///
/// - native TLS backend cannot be initialized
/// - supplied `Url` cannot be parsed
/// - there was an error while sending request
/// - redirect loop was detected
/// - redirect limit was exhausted
pub fn get<T: IntoUrl>(url: T) -> ::Result<Response> {
    Client::builder()
        .build()?
        .get(url)
        .send()
}

fn _assert_impls() {
    fn assert_send<T: Send>() {}
    fn assert_sync<T: Sync>() {}
    fn assert_clone<T: Clone>() {}

    assert_send::<Client>();
    assert_sync::<Client>();
    assert_clone::<Client>();

    assert_send::<Request>();
    assert_send::<RequestBuilder>();

    assert_send::<Response>();

    assert_send::<Error>();
    assert_sync::<Error>();
}
<commit_msg>document native-tls-vendored and rustls-tls features<commit_after>#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![cfg_attr(test, deny(warnings))]
#![doc(html_root_url = "https://docs.rs/reqwest/0.9.5")]

//! # reqwest
//!
//! The `reqwest` crate provides a convenient, higher-level HTTP Client.
//!
//! It handles many of the things that most people just expect an HTTP client
//! to do for them.
//!
//! - Uses system-native TLS
//! - Plain bodies, JSON, urlencoded, multipart
//! - Customizable redirect policy
//! - Proxies
//! - Cookies (only rudimentary support, full support is TODO)
//!
//! The rudimentary cookie support means that the cookies need to be manually
//! configured for every single request. In other words, there's no cookie jar
//! support as of now. The tracking issue for this feature is available
//! [on GitHub][cookiejar_issue].
//!
//! The `reqwest::Client` is synchronous, making it a great fit for
//! applications that only require a few HTTP requests, and wish to handle
//! them synchronously.
//!
//! ## Making a GET request
//!
//! For a single request, you can use the [`get`][get] shortcut method.
//!
//! ```rust
//! # use reqwest::{Error, Response};
//!
//! # fn run() -> Result<(), Error> {
//! let body = reqwest::get("https://www.rust-lang.org")?
//!     .text()?;
//!
//! println!("body = {:?}", body);
//! # Ok(())
//! # }
//! ```
//!
//! Additionally, reqwest's [`Response`][response] struct implements Rust's
//! `Read` trait, so many useful standard library and third party crates will
//! have convenience methods that take a `Response` anywhere `T: Read` is
//! acceptable.
//!
//! **NOTE**: If you plan to perform multiple requests, it is best to create a
//! [`Client`][client] and reuse it, taking advantage of keep-alive connection
//! pooling.
//!
//! ## Making POST requests (or setting request bodies)
//!
//! There are several ways you can set the body of a request. The basic one is
//! by using the `body()` method of a [`RequestBuilder`][builder]. This lets you set the
//! exact raw bytes of what the body should be. It accepts various types,
//! including `String`, `Vec<u8>`, and `File`. If you wish to pass a custom
//! Reader, you can use the `reqwest::Body::new()` constructor.
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # fn run() -> Result<(), Error> {
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .body("the exact body that is sent")
//!     .send()?;
//! # Ok(())
//! # }
//! ```
//!
//! ### Forms
//!
//! It's very common to want to send form data in a request body. This can be
//! done with any type that can be serialized into form data.
//!
//! This can be an array of tuples, or a `HashMap`, or a custom type that
//! implements [`Serialize`][serde].
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # fn run() -> Result<(), Error> {
//! // This will POST a body of `foo=bar&baz=quux`
//! let params = [("foo", "bar"), ("baz", "quux")];
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .form(&params)
//!     .send()?;
//! # Ok(())
//! # }
//! ```
//!
//! ### JSON
//!
//! There is also a `json` method helper on the [`RequestBuilder`][builder] that works in
//! a similar fashion the `form` method. It can take any value that can be
//! serialized into JSON.
//!
//! ```rust
//! # use reqwest::Error;
//! # use std::collections::HashMap;
//! #
//! # fn run() -> Result<(), Error> {
//! // This will POST a body of `{"lang":"rust","body":"json"}`
//! let mut map = HashMap::new();
//! map.insert("lang", "rust");
//! map.insert("body", "json");
//!
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .json(&map)
//!     .send()?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Optional Features
//!
//! The following are a list of [Cargo features][cargo-features] that can be
//! enabled or disabled:
//!
//! - **default-tls** *(enabled by default)*: Provides TLS support via the
//!   `native-tls` library to connect over HTTPS.
//! - **default-tls-vendored**: Enables the `vendored` feature of `native-tls`.
//! - **rustls-tls**: Provides TLS support via the `rustls` library.
//! - **hyper-011**: Provides support for hyper's old typed headers.
//!
//!
//! [hyper]: http://hyper.rs
//! [client]: ./struct.Client.html
//! [response]: ./struct.Response.html
//! [get]: ./fn.get.html
//! [builder]: ./struct.RequestBuilder.html
//! [serde]: http://serde.rs
//! [cookiejar_issue]: https://github.com/seanmonstar/reqwest/issues/14
//! [cargo-features]: https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section

extern crate base64;
extern crate bytes;
extern crate encoding_rs;
#[macro_use]
extern crate futures;
extern crate http;
extern crate hyper;
#[cfg(feature = "hyper-011")]
pub extern crate hyper_old_types as hyper_011;
#[cfg(feature = "default-tls")]
extern crate hyper_tls;
#[macro_use]
extern crate log;
extern crate libflate;
extern crate mime;
extern crate mime_guess;
#[cfg(feature = "default-tls")]
extern crate native_tls;
extern crate serde;
#[cfg(test)]
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde_urlencoded;
extern crate tokio;
#[cfg_attr(feature = "default-tls", macro_use)]
extern crate tokio_io;
extern crate trust_dns_resolver;
extern crate url;
extern crate uuid;

#[cfg(feature = "rustls-tls")]
extern crate hyper_rustls;
#[cfg(feature = "rustls-tls")]
extern crate tokio_rustls;
#[cfg(feature = "rustls-tls")]
extern crate webpki_roots;
#[cfg(feature = "rustls-tls")]
extern crate rustls;

pub use hyper::header;
pub use hyper::Method;
pub use hyper::{StatusCode, Version};
pub use url::Url;
pub use url::ParseError as UrlError;

pub use self::client::{Client, ClientBuilder};
pub use self::error::{Error, Result};
pub use self::body::Body;
pub use self::into_url::IntoUrl;
pub use self::proxy::Proxy;
pub use self::redirect::{RedirectAction, RedirectAttempt, RedirectPolicy};
pub use self::request::{Request, RequestBuilder};
pub use self::response::Response;
#[cfg(feature = "tls")]
pub use self::tls::{Certificate, Identity};

// this module must be first because of the `try_` macro
#[macro_use]
mod error;

mod async_impl;
mod connect;
#[cfg(feature = "default-tls")]
mod connect_async;
mod body;
mod client;
mod dns;
mod into_url;
mod proxy;
mod redirect;
mod request;
mod response;
#[cfg(feature = "tls")]
mod tls;
mod wait;

pub mod multipart;

/// An 'async' implementation of the reqwest `Client`.
///
/// Relies on the `futures` crate, which is unstable, hence this module
/// is **unstable**.
pub mod async {
    pub use ::async_impl::{
        Body,
        Chunk,
        Decoder,
        Client,
        ClientBuilder,
        Request,
        RequestBuilder,
        Response,
        ResponseBuilderExt,
    };
}

/// Shortcut method to quickly make a `GET` request.
///
/// See also the methods on the [`reqwest::Response`](./struct.Response.html)
/// type.
///
/// **NOTE**: This function creates a new internal `Client` on each call,
/// and so should not be used if making many requests. Create a
/// [`Client`](./struct.Client.html) instead.
///
/// # Examples
///
/// ```rust
/// # fn run() -> Result<(), reqwest::Error> {
/// let body = reqwest::get("https://www.rust-lang.org")?
///     .text()?;
/// # Ok(())
/// # }
/// # fn main() { }
/// ```
///
/// # Errors
///
/// This function fails if:
///
/// - native TLS backend cannot be initialized
/// - supplied `Url` cannot be parsed
/// - there was an error while sending request
/// - redirect loop was detected
/// - redirect limit was exhausted
pub fn get<T: IntoUrl>(url: T) -> ::Result<Response> {
    Client::builder()
        .build()?
        .get(url)
        .send()
}

fn _assert_impls() {
    fn assert_send<T: Send>() {}
    fn assert_sync<T: Sync>() {}
    fn assert_clone<T: Clone>() {}

    assert_send::<Client>();
    assert_sync::<Client>();
    assert_clone::<Client>();

    assert_send::<Request>();
    assert_send::<RequestBuilder>();

    assert_send::<Response>();

    assert_send::<Error>();
    assert_sync::<Error>();
}
<|endoftext|>


<commit_before>extern crate chrono;
extern crate csv;
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate safe_unwrap;
extern crate term_painter;
extern crate term_size;
extern crate textwrap;
extern crate try_from;

pub mod err;
mod regexes;

use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
use err::{ColumnConstraintsError, ColumnTypeError, ErrorLoc, ErrorAtLocation, Location, ResultLoc,
          SchemaLoadError, ValidationError, ValueError};
use std::{fmt, path, slice};
use safe_unwrap::SafeUnwrap;
use regexes::{IDENT_UNDERSCORE_RE, ENUM_EXPR_RE, CONSTRAINT_RE, DECIMAL_RE, DATE_RE, DATETIME_RE,
              FN_RE, TIME_RE};
use try_from::TryFrom;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CsvxMetadata {
    pub table_name: String,
    pub date: NaiveDate,
    pub schema: String,
}

impl CsvxMetadata {
    pub fn is_schema(&self) -> bool {
        self.schema.starts_with("csvx-schema-")
    }
}

#[derive(Clone, Debug)]
pub enum ColumnType {
    String,
    Bool,
    Integer,
    Enum(Vec<String>),
    Decimal,
    Date,
    DateTime,
    Time,
}

impl fmt::Display for ColumnType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ColumnType::String => write!(f, "STRING"),
            ColumnType::Bool => write!(f, "BOOL"),
            ColumnType::Integer => write!(f, "INTEGER"),
            ColumnType::Enum(ref variants) => write!(f, "ENUM({})", variants.join(",")),
            ColumnType::Decimal => write!(f, "DECIMAL"),
            ColumnType::Date => write!(f, "DATE"),
            ColumnType::DateTime => write!(f, "DATETIME"),
            ColumnType::Time => write!(f, "TIME"),
        }
    }
}

#[derive(Clone, Debug)]
pub struct ColumnConstraints {
    nullable: bool,
    unique: bool,
}

impl Default for ColumnConstraints {
    fn default() -> ColumnConstraints {
        ColumnConstraints {
            nullable: false,
            unique: false,
        }
    }
}

impl fmt::Display for ColumnConstraints {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut parts = Vec::new();
        if self.nullable {
            parts.push("NULLABLE");
        }
        if self.unique {
            parts.push("UNIQUE");
        }
        write!(f, "{}", parts.join(","))
    }
}

impl<S> TryFrom<S> for ColumnConstraints
    where S: AsRef<str>
{
    type Err = ColumnConstraintsError;

    fn try_from(s: S) -> Result<ColumnConstraints, Self::Err> {
        if !CONSTRAINT_RE.is_match(s.as_ref()) {
            return Err(ColumnConstraintsError::MalformedConstraints(s.as_ref().to_string()));
        }

        let mut ccs = ColumnConstraints::default();

        if s.as_ref() == "" {
            return Ok(ccs);
        }

        for fragment in s.as_ref().split(',') {
            match fragment.as_ref() {
                "NULLABLE" => {
                    ccs.nullable = true;
                }
                "UNIQUE" => {
                    ccs.unique = true;
                }
                _ => return Err(ColumnConstraintsError::UnknownConstraint(s.as_ref().to_string())),
            }

        }

        Ok(ccs)
    }
}

impl<S> TryFrom<S> for ColumnType
    where S: AsRef<str>
{
    type Err = ColumnTypeError;

    fn try_from(s: S) -> Result<ColumnType, Self::Err> {
        match s.as_ref() {
            "STRING" => Ok(ColumnType::String),
            "BOOL" => Ok(ColumnType::Bool),
            "INTEGER" => Ok(ColumnType::Integer),
            "DECIMAL" => Ok(ColumnType::Decimal),
            "DATE" => Ok(ColumnType::Date),
            "DATETIME" => Ok(ColumnType::DateTime),
            "TIME" => Ok(ColumnType::Time),
            _ if ENUM_EXPR_RE.is_match(s.as_ref()) => {
                let variants: Vec<_> = ENUM_EXPR_RE
                    .captures(s.as_ref())
                    .safe_unwrap("match already exists")
                    .get(1)
                    .safe_unwrap("group 1 exists in regex")
                    .as_str()
                    .split(',')
                    .map(|s| s.to_owned())
                    .collect();

                Ok(ColumnType::Enum(variants))
            }
            _ => {
                if s.as_ref().starts_with("ENUM") {
                    return Err(ColumnTypeError::BadEnum(s.as_ref().to_owned()));
                }
                return Err(ColumnTypeError::UnknownType(s.as_ref().to_owned()));
            }

        }
    }
}

#[derive(Clone, Debug)]
pub struct CsvxColumnType {
    pub id: String,
    pub ty: ColumnType,
    pub constraints: ColumnConstraints,
    pub description: String,
}

#[derive(Debug)]
pub enum Value {
    String(String),
    Bool(bool),
    Integer(i64),
    Enum(String),
    Decimal(String),
    Date(NaiveDate),
    DateTime(NaiveDateTime),
    Time(NaiveTime),
}

impl CsvxColumnType {
    pub fn validate_value<S: AsRef<str>>(&self, s: &S) -> Result<Option<Value>, ValueError> {
        // FIXME: check UNIQUE

        // null check
        if s.as_ref() == "" {
            if self.constraints.nullable {
                return Ok(None);
            } else {
                return Err(ValueError::NonNullable);
            }
        }

        match self.ty {
            ColumnType::String => Ok(Some(Value::String(s.as_ref().to_string()))),
            ColumnType::Bool => {
                match s.as_ref() {
                    "TRUE" => Ok(Some(Value::Bool(true))),
                    "FALSE" => Ok(Some(Value::Bool(false))),
                    _ => Err(ValueError::InvalidBool(s.as_ref().to_owned())),
                }
            }
            ColumnType::Integer => {
                // FIXME: check for leading zeros
                Ok(Some(Value::Integer(s.as_ref()
                                           .parse()
                                           .map_err(|_| {
                                                        ValueError::InvalidInt(s.as_ref()
                                                                                .to_owned())
                                                    })?)))
            }
            ColumnType::Enum(ref variants) => {
                let v = s.as_ref().to_owned();
                if variants.contains(&v) {
                    Ok(Some(Value::Enum(v)))
                } else {
                    Err(ValueError::InvalidEnum(s.as_ref().to_owned(), variants.clone()))
                }
            }
            ColumnType::Decimal => {
                if DECIMAL_RE.is_match(s.as_ref()) {
                    Ok(Some(Value::Decimal(s.as_ref().to_owned())))
                } else {
                    Err(ValueError::InvalidDecimal(s.as_ref().to_owned()))
                }
            }
            ColumnType::Date => {
                match DATE_RE.captures(s.as_ref()) {
                    Some(ref c) => {
                        Ok(Some(Value::Date(NaiveDate::from_ymd_opt(cap(c, 1),
                                                                    cap(c, 2),
                                                                    cap(c, 3))
              .ok_or_else(||{
                      ValueError::InvalidDate(s.as_ref().to_owned ()) }
                      )?)))
                    }
                    None => Err(ValueError::InvalidDate(s.as_ref().to_owned())),
                }
            }
            ColumnType::DateTime => {
                match DATETIME_RE.captures(s.as_ref()) {
                    Some(ref c) => {
                        let dt =
                            NaiveDate::from_ymd_opt(cap(c, 1), cap(c, 2), cap(c, 3))
                                .ok_or_else(|| ValueError::InvalidDate(s.as_ref().to_string()))?;
                        Ok(Some(Value::DateTime(dt.and_hms_opt(cap(c, 4), cap(c, 5), cap(c, 6))
                                                    .ok_or_else(|| {
                                                                    ValueError::InvalidTime (s.as_ref ().to_string ()) })?)))
                    }
                    None => Err(ValueError::InvalidDateTime(s.as_ref().to_string())),
                }
            }
            ColumnType::Time => {
                match TIME_RE.captures(s.as_ref()) {
                    Some(ref c) => {
                        Ok(Some(Value::Time(NaiveTime::from_hms_opt(cap(c, 1),
                                                                    cap(c, 2),
                                                                    cap(c, 3))
                                                    .ok_or_else(||
                                                        ValueError::InvalidTime (s.as_ref ().to_string ()))?)))
                    }
                    None => Err(ValueError::InvalidTime(s.as_ref().to_string())),
                }
            }
        }
    }
}

#[derive(Clone, Debug)]
pub struct CsvxSchema {
    columns: Vec<CsvxColumnType>,
}

impl CsvxSchema {
    pub fn iter_columns(&self) -> slice::Iter<CsvxColumnType> {
        self.columns.iter()
    }

    pub fn from_file<P: AsRef<path::Path>>
        (filename: P)
         -> Result<CsvxSchema, ErrorAtLocation<SchemaLoadError, Location>> {

        // have a copy of the filename as a string ready for error locations
        let filename_s = filename.as_ref().to_string_lossy().to_string();

        let mut rdr = csv::Reader::from_file(filename)
            .err_at(|| Location::File(filename_s.clone()))?
            .has_headers(false);

        let mut it = rdr.decode();
        let header: Option<Result<(String, String, String, String), _>> = it.next();

        let mut columns = Vec::new();

        match header {
            None => {
                return Err(SchemaLoadError::MissingHeader.at(Location::FileLine(filename_s, 1)))
            }
            Some(res) => {
                let fields = res.err_at(|| Location::File(filename_s.clone()))?;
                if fields.0 != "id" || fields.1 != "type" || fields.2 != "constraints" ||
                   fields.3 != "description" {

                    return Err(SchemaLoadError::BadHeader.at(Location::FileLine(filename_s, 1)));
                }

                for (recno, rec) in it.enumerate() {
                    let (id, ty, constraints, desc) =
                        rec.err_at(|| Location::FileLine(filename_s.clone(), 1))?;
                    let lineno = recno + 2;

                    // check identifier
                    if !IDENT_UNDERSCORE_RE.is_match(&id.as_str()) {
                        return Err(SchemaLoadError::BadIdentifier(id)
                                       .at(Location::FileLineField(filename_s, lineno, 1)));
                    }

                    // create type
                    let col_type = match ColumnType::try_from(ty.as_str()) {
                        Ok(v) => v,
                        Err(e) => {
                            return Err(SchemaLoadError::BadType(e)
                                           .at(Location::FileLineField(filename_s, lineno, 1)))
                        }
                    };

                    // create constraints
                    let col_constraints = match ColumnConstraints::try_from(constraints.as_str()) {
                        Ok(v) => v,
                        // FIXME: location
                        Err(e) => {
                            return Err(SchemaLoadError::BadConstraints(e)
                                           .at(Location::FileLine(filename_s, lineno)))
                        }
                    };

                    let col = CsvxColumnType {
                        id: id,
                        ty: col_type,
                        constraints: col_constraints,
                        description: desc,
                    };

                    columns.push(col)
                }

                Ok(CsvxSchema { columns: columns })
            }
        }
    }

    pub fn validate_file<P: AsRef<path::Path>>
        (&self,
         filename: P)
         -> Result<(), Vec<ErrorAtLocation<ValidationError, Location>>> {
        let filename_s = filename.as_ref().to_string_lossy().to_string();

        let mut rdr = csv::Reader::from_file(filename)
            .map_err(|e| vec![e.at(Location::File(filename_s.clone()))])?
            .has_headers(true);

        let headers = rdr.headers()
            .map_err(|e| vec![e.at(Location::FileLine(filename_s.clone(), 1))])?;

        if headers.len() != self.columns.len() {
            return Err(vec![ValidationError::MissingHeaders
                                .at(Location::FileLine(filename_s.clone(), 1))]);
        }

        let mut errs = Vec::new();

        for (idx, (spec, actual)) in self.columns.iter().zip(headers.iter()).enumerate() {
            if spec.id.as_str() != actual {
                errs.push(ValidationError::HeaderMismatch(actual.to_string())
                              .at(Location::FileLineField(filename_s.clone(), 1, idx + 1)));
            }
        }

        // bail if headers are incorrect
        if errs.len() != 0 {
            return Err(errs);
        }

        for (rowid, row) in rdr.records().enumerate() {
            let lineno = rowid + 2;

            // bail early if we cannot read the fields, this is probably a
            // major csv issue
            let fields = row.map_err(|e| vec![e.at(Location::FileLine(filename_s.clone(), 1))])?;

            for (idx, (col, value)) in self.columns.iter().zip(fields.iter()).enumerate() {
                if let Err(e) = col.validate_value(value) {
                    let col_idx = idx + 1;

                    errs.push(ValidationError::ValueError(e)
                                  .at(Location::FileLineField(filename_s.clone(),
                                                              lineno,
                                                              col_idx)));
                    continue;
                }
            }
        }

        if errs.len() != 0 {
            return Err(errs);
        } else {
            Ok(())
        }
    }

    pub fn parse_row<T: AsRef<[String]>>(&self, fields: &T)
                 -> Result<Vec<Option<Value>>, ErrorAtLocation<ValidationError, usize>> {
        let mut rv = Vec::with_capacity(self.columns.len());
        let fields = fields.as_ref();
        for (idx, (col, value)) in self.columns.iter().zip(fields.iter()).enumerate() {
            match col.validate_value(value) {
                Err(e) => {
                    let col_idx = idx + 1;

                    return Err(ValidationError::ValueError(e).at(col_idx));
                }
                Ok(v) => rv.push(v),
            }
        }
        Ok(rv)
    }
}

#[inline]
fn cap<T>(c: &regex::Captures, idx: usize) -> T
    where T: std::str::FromStr,
          T::Err: std::fmt::Debug
{
    c.get(idx)
        .safe_unwrap("valid group")
        .as_str()
        .parse()
        .safe_unwrap("already validated through regex")

}

pub fn parse_filename<S: AsRef<str>>(filename: S) -> Option<CsvxMetadata> {
    match FN_RE.captures(filename.as_ref()) {
        Some(caps) => {
            let table_name = caps.get(1)
                .safe_unwrap("known group")
                .as_str()
                .to_string();
            let year = cap(&caps, 2);
            let month = cap(&caps, 3);
            let day = cap(&caps, 4);
            let schema = caps.get(5)
                .safe_unwrap("known group")
                .as_str()
                .to_string();

            Some(CsvxMetadata {
                     table_name: table_name,
                     date: match NaiveDate::from_ymd_opt(year, month, day) {
                         Some(d) => d,
                         None => return None,
                     },
                     schema: schema,
                 })
        }
        None => None,
    }
}

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

    use chrono::NaiveDate;

    #[test]
    fn filename_parsing_rejects_invalid() {
        assert_eq!(parse_filename("asdf"), None);
        assert_eq!(parse_filename(""), None);
        assert_eq!(parse_filename("test.csv"), None);
        assert_eq!(parse_filename("test.csv"), None);
    }

    #[test]
    fn filename_parsing_parses_valid() {
        assert_eq!(parse_filename("zoo-nyc_20170401_animals-2.csv").unwrap(),
                   CsvxMetadata {
                       table_name: "zoo-nyc".to_owned(),
                       date: NaiveDate::from_ymd(2017, 04, 01),
                       schema: "animals-2".to_owned(),
                   });
    }

}
<commit_msg>Added col_idx function.<commit_after>extern crate chrono;
extern crate csv;
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate safe_unwrap;
extern crate term_painter;
extern crate term_size;
extern crate textwrap;
extern crate try_from;

pub mod err;
mod regexes;

use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
use err::{ColumnConstraintsError, ColumnTypeError, ErrorLoc, ErrorAtLocation, Location, ResultLoc,
          SchemaLoadError, ValidationError, ValueError};
use std::{fmt, path, slice};
use safe_unwrap::SafeUnwrap;
use regexes::{IDENT_UNDERSCORE_RE, ENUM_EXPR_RE, CONSTRAINT_RE, DECIMAL_RE, DATE_RE, DATETIME_RE,
              FN_RE, TIME_RE};
use try_from::TryFrom;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CsvxMetadata {
    pub table_name: String,
    pub date: NaiveDate,
    pub schema: String,
}

impl CsvxMetadata {
    pub fn is_schema(&self) -> bool {
        self.schema.starts_with("csvx-schema-")
    }
}

#[derive(Clone, Debug)]
pub enum ColumnType {
    String,
    Bool,
    Integer,
    Enum(Vec<String>),
    Decimal,
    Date,
    DateTime,
    Time,
}

impl fmt::Display for ColumnType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ColumnType::String => write!(f, "STRING"),
            ColumnType::Bool => write!(f, "BOOL"),
            ColumnType::Integer => write!(f, "INTEGER"),
            ColumnType::Enum(ref variants) => write!(f, "ENUM({})", variants.join(",")),
            ColumnType::Decimal => write!(f, "DECIMAL"),
            ColumnType::Date => write!(f, "DATE"),
            ColumnType::DateTime => write!(f, "DATETIME"),
            ColumnType::Time => write!(f, "TIME"),
        }
    }
}

#[derive(Clone, Debug)]
pub struct ColumnConstraints {
    nullable: bool,
    unique: bool,
}

impl Default for ColumnConstraints {
    fn default() -> ColumnConstraints {
        ColumnConstraints {
            nullable: false,
            unique: false,
        }
    }
}

impl fmt::Display for ColumnConstraints {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut parts = Vec::new();
        if self.nullable {
            parts.push("NULLABLE");
        }
        if self.unique {
            parts.push("UNIQUE");
        }
        write!(f, "{}", parts.join(","))
    }
}

impl<S> TryFrom<S> for ColumnConstraints
    where S: AsRef<str>
{
    type Err = ColumnConstraintsError;

    fn try_from(s: S) -> Result<ColumnConstraints, Self::Err> {
        if !CONSTRAINT_RE.is_match(s.as_ref()) {
            return Err(ColumnConstraintsError::MalformedConstraints(s.as_ref().to_string()));
        }

        let mut ccs = ColumnConstraints::default();

        if s.as_ref() == "" {
            return Ok(ccs);
        }

        for fragment in s.as_ref().split(',') {
            match fragment.as_ref() {
                "NULLABLE" => {
                    ccs.nullable = true;
                }
                "UNIQUE" => {
                    ccs.unique = true;
                }
                _ => return Err(ColumnConstraintsError::UnknownConstraint(s.as_ref().to_string())),
            }

        }

        Ok(ccs)
    }
}

impl<S> TryFrom<S> for ColumnType
    where S: AsRef<str>
{
    type Err = ColumnTypeError;

    fn try_from(s: S) -> Result<ColumnType, Self::Err> {
        match s.as_ref() {
            "STRING" => Ok(ColumnType::String),
            "BOOL" => Ok(ColumnType::Bool),
            "INTEGER" => Ok(ColumnType::Integer),
            "DECIMAL" => Ok(ColumnType::Decimal),
            "DATE" => Ok(ColumnType::Date),
            "DATETIME" => Ok(ColumnType::DateTime),
            "TIME" => Ok(ColumnType::Time),
            _ if ENUM_EXPR_RE.is_match(s.as_ref()) => {
                let variants: Vec<_> = ENUM_EXPR_RE
                    .captures(s.as_ref())
                    .safe_unwrap("match already exists")
                    .get(1)
                    .safe_unwrap("group 1 exists in regex")
                    .as_str()
                    .split(',')
                    .map(|s| s.to_owned())
                    .collect();

                Ok(ColumnType::Enum(variants))
            }
            _ => {
                if s.as_ref().starts_with("ENUM") {
                    return Err(ColumnTypeError::BadEnum(s.as_ref().to_owned()));
                }
                return Err(ColumnTypeError::UnknownType(s.as_ref().to_owned()));
            }

        }
    }
}

#[derive(Clone, Debug)]
pub struct CsvxColumnType {
    pub id: String,
    pub ty: ColumnType,
    pub constraints: ColumnConstraints,
    pub description: String,
}

#[derive(Debug)]
pub enum Value {
    String(String),
    Bool(bool),
    Integer(i64),
    Enum(String),
    Decimal(String),
    Date(NaiveDate),
    DateTime(NaiveDateTime),
    Time(NaiveTime),
}

impl CsvxColumnType {
    pub fn validate_value<S: AsRef<str>>(&self, s: &S) -> Result<Option<Value>, ValueError> {
        // FIXME: check UNIQUE

        // null check
        if s.as_ref() == "" {
            if self.constraints.nullable {
                return Ok(None);
            } else {
                return Err(ValueError::NonNullable);
            }
        }

        match self.ty {
            ColumnType::String => Ok(Some(Value::String(s.as_ref().to_string()))),
            ColumnType::Bool => {
                match s.as_ref() {
                    "TRUE" => Ok(Some(Value::Bool(true))),
                    "FALSE" => Ok(Some(Value::Bool(false))),
                    _ => Err(ValueError::InvalidBool(s.as_ref().to_owned())),
                }
            }
            ColumnType::Integer => {
                // FIXME: check for leading zeros
                Ok(Some(Value::Integer(s.as_ref()
                                           .parse()
                                           .map_err(|_| {
                                                        ValueError::InvalidInt(s.as_ref()
                                                                                .to_owned())
                                                    })?)))
            }
            ColumnType::Enum(ref variants) => {
                let v = s.as_ref().to_owned();
                if variants.contains(&v) {
                    Ok(Some(Value::Enum(v)))
                } else {
                    Err(ValueError::InvalidEnum(s.as_ref().to_owned(), variants.clone()))
                }
            }
            ColumnType::Decimal => {
                if DECIMAL_RE.is_match(s.as_ref()) {
                    Ok(Some(Value::Decimal(s.as_ref().to_owned())))
                } else {
                    Err(ValueError::InvalidDecimal(s.as_ref().to_owned()))
                }
            }
            ColumnType::Date => {
                match DATE_RE.captures(s.as_ref()) {
                    Some(ref c) => {
                        Ok(Some(Value::Date(NaiveDate::from_ymd_opt(cap(c, 1),
                                                                    cap(c, 2),
                                                                    cap(c, 3))
              .ok_or_else(||{
                      ValueError::InvalidDate(s.as_ref().to_owned ()) }
                      )?)))
                    }
                    None => Err(ValueError::InvalidDate(s.as_ref().to_owned())),
                }
            }
            ColumnType::DateTime => {
                match DATETIME_RE.captures(s.as_ref()) {
                    Some(ref c) => {
                        let dt =
                            NaiveDate::from_ymd_opt(cap(c, 1), cap(c, 2), cap(c, 3))
                                .ok_or_else(|| ValueError::InvalidDate(s.as_ref().to_string()))?;
                        Ok(Some(Value::DateTime(dt.and_hms_opt(cap(c, 4), cap(c, 5), cap(c, 6))
                                                    .ok_or_else(|| {
                                                                    ValueError::InvalidTime (s.as_ref ().to_string ()) })?)))
                    }
                    None => Err(ValueError::InvalidDateTime(s.as_ref().to_string())),
                }
            }
            ColumnType::Time => {
                match TIME_RE.captures(s.as_ref()) {
                    Some(ref c) => {
                        Ok(Some(Value::Time(NaiveTime::from_hms_opt(cap(c, 1),
                                                                    cap(c, 2),
                                                                    cap(c, 3))
                                                    .ok_or_else(||
                                                        ValueError::InvalidTime (s.as_ref ().to_string ()))?)))
                    }
                    None => Err(ValueError::InvalidTime(s.as_ref().to_string())),
                }
            }
        }
    }
}

#[derive(Clone, Debug)]
pub struct CsvxSchema {
    columns: Vec<CsvxColumnType>,
}

impl CsvxSchema {
    pub fn iter_columns(&self) -> slice::Iter<CsvxColumnType> {
        self.columns.iter()
    }

    pub fn col_idx(&self, col: &str) -> Option<usize> {
        self.columns.iter().position(|c| col == c.id)
    }

    pub fn from_file<P: AsRef<path::Path>>
        (filename: P)
         -> Result<CsvxSchema, ErrorAtLocation<SchemaLoadError, Location>> {

        // have a copy of the filename as a string ready for error locations
        let filename_s = filename.as_ref().to_string_lossy().to_string();

        let mut rdr = csv::Reader::from_file(filename)
            .err_at(|| Location::File(filename_s.clone()))?
            .has_headers(false);

        let mut it = rdr.decode();
        let header: Option<Result<(String, String, String, String), _>> = it.next();

        let mut columns = Vec::new();

        match header {
            None => {
                return Err(SchemaLoadError::MissingHeader.at(Location::FileLine(filename_s, 1)))
            }
            Some(res) => {
                let fields = res.err_at(|| Location::File(filename_s.clone()))?;
                if fields.0 != "id" || fields.1 != "type" || fields.2 != "constraints" ||
                   fields.3 != "description" {

                    return Err(SchemaLoadError::BadHeader.at(Location::FileLine(filename_s, 1)));
                }

                for (recno, rec) in it.enumerate() {
                    let (id, ty, constraints, desc) =
                        rec.err_at(|| Location::FileLine(filename_s.clone(), 1))?;
                    let lineno = recno + 2;

                    // check identifier
                    if !IDENT_UNDERSCORE_RE.is_match(&id.as_str()) {
                        return Err(SchemaLoadError::BadIdentifier(id)
                                       .at(Location::FileLineField(filename_s, lineno, 1)));
                    }

                    // create type
                    let col_type = match ColumnType::try_from(ty.as_str()) {
                        Ok(v) => v,
                        Err(e) => {
                            return Err(SchemaLoadError::BadType(e)
                                           .at(Location::FileLineField(filename_s, lineno, 1)))
                        }
                    };

                    // create constraints
                    let col_constraints = match ColumnConstraints::try_from(constraints.as_str()) {
                        Ok(v) => v,
                        // FIXME: location
                        Err(e) => {
                            return Err(SchemaLoadError::BadConstraints(e)
                                           .at(Location::FileLine(filename_s, lineno)))
                        }
                    };

                    let col = CsvxColumnType {
                        id: id,
                        ty: col_type,
                        constraints: col_constraints,
                        description: desc,
                    };

                    columns.push(col)
                }

                Ok(CsvxSchema { columns: columns })
            }
        }
    }

    pub fn validate_file<P: AsRef<path::Path>>
        (&self,
         filename: P)
         -> Result<(), Vec<ErrorAtLocation<ValidationError, Location>>> {
        let filename_s = filename.as_ref().to_string_lossy().to_string();

        let mut rdr = csv::Reader::from_file(filename)
            .map_err(|e| vec![e.at(Location::File(filename_s.clone()))])?
            .has_headers(true);

        let headers = rdr.headers()
            .map_err(|e| vec![e.at(Location::FileLine(filename_s.clone(), 1))])?;

        if headers.len() != self.columns.len() {
            return Err(vec![ValidationError::MissingHeaders
                                .at(Location::FileLine(filename_s.clone(), 1))]);
        }

        let mut errs = Vec::new();

        for (idx, (spec, actual)) in self.columns.iter().zip(headers.iter()).enumerate() {
            if spec.id.as_str() != actual {
                errs.push(ValidationError::HeaderMismatch(actual.to_string())
                              .at(Location::FileLineField(filename_s.clone(), 1, idx + 1)));
            }
        }

        // bail if headers are incorrect
        if errs.len() != 0 {
            return Err(errs);
        }

        for (rowid, row) in rdr.records().enumerate() {
            let lineno = rowid + 2;

            // bail early if we cannot read the fields, this is probably a
            // major csv issue
            let fields = row.map_err(|e| vec![e.at(Location::FileLine(filename_s.clone(), 1))])?;

            for (idx, (col, value)) in self.columns.iter().zip(fields.iter()).enumerate() {
                if let Err(e) = col.validate_value(value) {
                    let col_idx = idx + 1;

                    errs.push(ValidationError::ValueError(e)
                                  .at(Location::FileLineField(filename_s.clone(),
                                                              lineno,
                                                              col_idx)));
                    continue;
                }
            }
        }

        if errs.len() != 0 {
            return Err(errs);
        } else {
            Ok(())
        }
    }

    pub fn parse_row<T: AsRef<[String]>>(&self, fields: &T)
                 -> Result<Vec<Option<Value>>, ErrorAtLocation<ValidationError, usize>> {
        let mut rv = Vec::with_capacity(self.columns.len());
        let fields = fields.as_ref();
        for (idx, (col, value)) in self.columns.iter().zip(fields.iter()).enumerate() {
            match col.validate_value(value) {
                Err(e) => {
                    let col_idx = idx + 1;

                    return Err(ValidationError::ValueError(e).at(col_idx));
                }
                Ok(v) => rv.push(v),
            }
        }
        Ok(rv)
    }
}

#[inline]
fn cap<T>(c: &regex::Captures, idx: usize) -> T
    where T: std::str::FromStr,
          T::Err: std::fmt::Debug
{
    c.get(idx)
        .safe_unwrap("valid group")
        .as_str()
        .parse()
        .safe_unwrap("already validated through regex")

}

pub fn parse_filename<S: AsRef<str>>(filename: S) -> Option<CsvxMetadata> {
    match FN_RE.captures(filename.as_ref()) {
        Some(caps) => {
            let table_name = caps.get(1)
                .safe_unwrap("known group")
                .as_str()
                .to_string();
            let year = cap(&caps, 2);
            let month = cap(&caps, 3);
            let day = cap(&caps, 4);
            let schema = caps.get(5)
                .safe_unwrap("known group")
                .as_str()
                .to_string();

            Some(CsvxMetadata {
                     table_name: table_name,
                     date: match NaiveDate::from_ymd_opt(year, month, day) {
                         Some(d) => d,
                         None => return None,
                     },
                     schema: schema,
                 })
        }
        None => None,
    }
}

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

    use chrono::NaiveDate;

    #[test]
    fn filename_parsing_rejects_invalid() {
        assert_eq!(parse_filename("asdf"), None);
        assert_eq!(parse_filename(""), None);
        assert_eq!(parse_filename("test.csv"), None);
        assert_eq!(parse_filename("test.csv"), None);
    }

    #[test]
    fn filename_parsing_parses_valid() {
        assert_eq!(parse_filename("zoo-nyc_20170401_animals-2.csv").unwrap(),
                   CsvxMetadata {
                       table_name: "zoo-nyc".to_owned(),
                       date: NaiveDate::from_ymd(2017, 04, 01),
                       schema: "animals-2".to_owned(),
                   });
    }

}
<|endoftext|>


<commit_before>
use std::net::TcpListener;
use std::io::Result;
use std::iter::Iterator;

/// Returns the next available network port
/// on the current host
pub fn next() -> Result<u16> {
  TcpListener::bind("0.0.0.0:0")
    .and_then(|l| {
      let addr = l.local_addr();
      drop(l);
      addr
     })
    .and_then(|a| Ok(a.port()))
}

pub struct Iter;

impl Iterator for Iter {
  type Item = u16;
  fn next(&mut self) -> Option<u16> {
    ::next().ok()
  }
}

pub fn iter() -> Iter {
  Iter
}

#[test]
fn it_works() {
}
<commit_msg>next -> open<commit_after>
use std::net::TcpListener;
use std::io::Result;
use std::iter::Iterator;

/// Returns the next available network port
/// on the current host
pub fn open() -> Result<u16> {
  TcpListener::bind("0.0.0.0:0")
    .and_then(|l| {
      let addr = l.local_addr();
      drop(l);
      addr
     })
    .and_then(|a| Ok(a.port()))
}

pub struct Iter;

impl Iterator for Iter {
  type Item = u16;
  fn next(&mut self) -> Option<u16> {
    ::open().ok()
  }
}

pub fn iter() -> Iter {
  Iter
}

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


<commit_before>#![crate_name = "neovim"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![allow(raw_pointer_derive)]

extern crate libc;

use std::ffi::CString;
use std::fmt;
use std::string::String;
use std::vec::Vec;

#[cfg(target_os="macos")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    #[link(name = "iconv")]
    extern{}
}

#[cfg(target_os="linux")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    extern{}
}

#[cfg(target_os="windows")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    extern{}
}

mod ffi;

pub enum Object {
    Buffer(ffi::C_Buffer),
    Window(ffi::C_Window),
    Tabpage(ffi::C_Tabpage),
    Boolean(ffi::C_Boolean),
    Integer(ffi::C_Integer),
    Float(ffi::C_Float),
    String(String),
    Array(ffi::C_Array),
    Dictionary(ffi::C_Dictionary),
}

impl fmt::Debug for Object {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Object::Buffer(ref obj) => write!(f, "Buffer({:?})", obj),
            Object::Window(ref obj) => write!(f, "Window({:?})", obj),
            Object::Tabpage(ref obj) => write!(f, "Tabpage({:?})", obj),
            Object::Boolean(ref obj) => write!(f, "Boolean({:?})", obj),
            Object::Integer(ref obj) => write!(f, "Integer({:?})", obj),
            Object::Float(ref obj) => write!(f, "Float({:?})", obj),
            Object::String(ref obj) => write!(f, "String({:?})", obj),
            Object::Array(ref obj) => {
                write!(f, "Array(").ok();
                for i in range(0, obj.size) {
                    let inner_obj_opt = unsafe { c_object_to_object(obj.items.offset(i as isize)) };
                    if let Some(inner_obj) = inner_obj_opt {
                        write!(f, "{:?}", inner_obj).ok();
                        if i + 1 < obj.size {
                            write!(f, ", ").ok();
                        }
                    } else {
                        write!(f, "Nil ").ok();
                    }
                }
                write!(f, ")")
            },
            Object::Dictionary(ref obj) => write!(f, "Dictionary(Length: {:?})", obj.size),
        }
    }
}

unsafe fn c_object_to_object(obj: *mut ffi::C_Object) -> Option<Object> {
    match (*obj).object_type {
        ffi::ObjectType::BufferType =>
            Some(Object::Buffer((*(obj as *mut ffi::C_Object_Buffer)).data)),
        ffi::ObjectType::WindowType =>
            Some(Object::Window((*(obj as *mut ffi::C_Object_Window)).data)),
        ffi::ObjectType::TabpageType =>
            Some(Object::Tabpage((*(obj as *mut ffi::C_Object_Tabpage)).data)),
        ffi::ObjectType::NilType =>
            None,
        ffi::ObjectType::BooleanType =>
            Some(Object::Boolean((*(obj as *mut ffi::C_Object_Boolean)).data)),
        ffi::ObjectType::IntegerType =>
            Some(Object::Integer((*(obj as *mut ffi::C_Object_Integer)).data)),
        ffi::ObjectType::FloatType =>
            Some(Object::Float((*(obj as *mut ffi::C_Object_Float)).data)),
        ffi::ObjectType::StringType => {
            let vim_str: ffi::C_String = (*(obj as *mut ffi::C_Object_String)).data;
            let v = Vec::from_raw_buf(vim_str.data as *const u8, vim_str.size as usize);
            Some(Object::String(String::from_utf8_unchecked(v)))
        },
        ffi::ObjectType::ArrayType =>
            Some(Object::Array((*(obj as *mut ffi::C_Object_Array)).data)),
        ffi::ObjectType::DictionaryType =>
            Some(Object::Dictionary((*(obj as *mut ffi::C_Object_Dictionary)).data)),
    }
}

pub fn main_setup(args: Vec<String>) -> i32 {
    let v: Vec<CString> = args.iter().map(|s| CString::from_slice(s.as_bytes())).collect();
    let vp: Vec<*const ffi::c_char> = v.iter().map(|s| s.as_ptr()).collect();
    let p_vp: *const *const ffi::c_char = vp.as_ptr();

    unsafe { ffi::nvim_main_setup(vp.len() as i32, p_vp) }
}

pub fn main_loop() -> i32 {
    unsafe { ffi::nvim_main_loop() }
}

pub fn channel_from_fds(read_fd: i32, write_fd: i32) -> u64 {
    unsafe { ffi::channel_from_fds(read_fd, write_fd) }
}

pub fn serialize_message(id: u64, method: &'static str, args: &Array) -> String {
    unsafe {
        let buf = ffi::vim_msgpack_new();
        let vim_str = ffi::C_String {data: method.as_ptr() as *const i8, size: method.len() as u64};
        ffi::vim_serialize_request(id, vim_str, args.unwrap_value(), buf);
        let v = Vec::from_raw_buf((*buf).data as *const u8, (*buf).size as usize);
        ffi::vim_msgpack_free(buf);
        String::from_utf8_unchecked(v)
    }
}

pub fn deserialize_message(message: &String) -> Array {
    let s = ffi::C_String {
        data: message.as_slice().as_ptr() as *const i8,
        size: message.len() as u64
    };
    let mut arr_raw = ffi::C_Array {
        items: ::std::ptr::null_mut(),
        size: 0,
        capacity: 0,
    };
    unsafe { ffi::vim_msgpack_parse(s, &mut arr_raw) };
    Array::wrap_value(arr_raw)
}

pub struct Array {
    value: ffi::C_Array
}

impl Array {
    pub fn new() -> Array {
        Array {
            value: ffi::C_Array {
                items: ::std::ptr::null_mut(),
                size: 0,
                capacity: 0,
            }
        }
    }

    pub fn add_buffer(&mut self, val: ffi::C_Buffer) {
        unsafe { ffi::vim_array_add_buffer(val, &mut self.value) }
    }

    pub fn add_window(&mut self, val: ffi::C_Window) {
        unsafe { ffi::vim_array_add_window(val, &mut self.value) }
    }

    pub fn add_tabpage(&mut self, val: ffi::C_Tabpage) {
        unsafe { ffi::vim_array_add_tabpage(val, &mut self.value) }
    }

    pub fn add_nil(&mut self) {
        unsafe { ffi::vim_array_add_nil(&mut self.value) }
    }

    pub fn add_boolean(&mut self, val: ffi::C_Boolean) {
        unsafe { ffi::vim_array_add_boolean(val, &mut self.value) }
    }

    pub fn add_integer(&mut self, val: ffi::C_Integer) {
        unsafe { ffi::vim_array_add_integer(val, &mut self.value) }
    }

    pub fn add_float(&mut self, val: ffi::C_Float) {
        unsafe { ffi::vim_array_add_float(val, &mut self.value) }
    }

    pub fn add_string(&mut self, val: &str) {
        unsafe {
            // we need to copy the string into memory not managed by Rust,
            // so api_free_array can clear it
            let ptr = ffi::malloc(val.len() as u64);
            ::std::ptr::copy_memory(ptr, val.as_ptr() as *const ffi::c_void, val.len());
            let vim_str = ffi::C_String {data: ptr as *const i8, size: val.len() as u64};
            ffi::vim_array_add_string(vim_str, &mut self.value)
        }
    }

    pub fn add_array(&mut self, val: &Array) {
        unsafe { ffi::vim_array_add_array(val.unwrap_value(), &mut self.value) }
    }

    pub fn add_dictionary(&mut self, val: ffi::C_Dictionary) {
        unsafe { ffi::vim_array_add_dictionary(val, &mut self.value) }
    }

    pub fn get(&self, index: u64) -> Option<Object> {
        if index >= self.len() {
            return None;
        }
        unsafe { c_object_to_object(self.value.items.offset(index as isize)) }
    }

    pub fn len(&self) -> u64 {
        self.value.size
    }

    #[doc(hidden)]
    pub fn unwrap_value(&self) -> ffi::C_Array {
        self.value
    }

    #[doc(hidden)]
    pub fn wrap_value(c_array: ffi::C_Array) -> Array {
        Array {
            value: c_array
        }
    }
}

impl Drop for Array {
    fn drop(&mut self) {
        unsafe { ffi::api_free_array(self.value) };
    }
}

impl fmt::Debug for Array {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Array(").ok();
        for i in range(0, self.len()) {
            if let Some(obj) = self.get(i) {
                write!(f, "{:?}", obj).ok();
            } else {
                write!(f, "Nil").ok();
            }
            if i + 1 < self.len() {
                write!(f, ", ").ok();
            }
        }
        write!(f, ")")
    }
}

#[test]
fn test_request() {
    let mut args = Array::new();
    args.add_integer(80);
    args.add_integer(24);
    args.add_string("hello");

    let msg = serialize_message(1, "test", &args);
    let arr = deserialize_message(&msg);
    println!("LENGTH: {}", arr.len());
    for i in range(0, arr.len()) {
        println!("{:?}", arr.get(i));
    }
}
<commit_msg>Pass args as reference<commit_after>#![crate_name = "neovim"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![allow(raw_pointer_derive)]

extern crate libc;

use std::ffi::CString;
use std::fmt;
use std::string::String;
use std::vec::Vec;

#[cfg(target_os="macos")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    #[link(name = "iconv")]
    extern{}
}

#[cfg(target_os="linux")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    extern{}
}

#[cfg(target_os="windows")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    extern{}
}

mod ffi;

pub enum Object {
    Buffer(ffi::C_Buffer),
    Window(ffi::C_Window),
    Tabpage(ffi::C_Tabpage),
    Boolean(ffi::C_Boolean),
    Integer(ffi::C_Integer),
    Float(ffi::C_Float),
    String(String),
    Array(ffi::C_Array),
    Dictionary(ffi::C_Dictionary),
}

impl fmt::Debug for Object {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Object::Buffer(ref obj) => write!(f, "Buffer({:?})", obj),
            Object::Window(ref obj) => write!(f, "Window({:?})", obj),
            Object::Tabpage(ref obj) => write!(f, "Tabpage({:?})", obj),
            Object::Boolean(ref obj) => write!(f, "Boolean({:?})", obj),
            Object::Integer(ref obj) => write!(f, "Integer({:?})", obj),
            Object::Float(ref obj) => write!(f, "Float({:?})", obj),
            Object::String(ref obj) => write!(f, "String({:?})", obj),
            Object::Array(ref obj) => {
                write!(f, "Array(").ok();
                for i in range(0, obj.size) {
                    let inner_obj_opt = unsafe { c_object_to_object(obj.items.offset(i as isize)) };
                    if let Some(inner_obj) = inner_obj_opt {
                        write!(f, "{:?}", inner_obj).ok();
                        if i + 1 < obj.size {
                            write!(f, ", ").ok();
                        }
                    } else {
                        write!(f, "Nil ").ok();
                    }
                }
                write!(f, ")")
            },
            Object::Dictionary(ref obj) => write!(f, "Dictionary(Length: {:?})", obj.size),
        }
    }
}

unsafe fn c_object_to_object(obj: *mut ffi::C_Object) -> Option<Object> {
    match (*obj).object_type {
        ffi::ObjectType::BufferType =>
            Some(Object::Buffer((*(obj as *mut ffi::C_Object_Buffer)).data)),
        ffi::ObjectType::WindowType =>
            Some(Object::Window((*(obj as *mut ffi::C_Object_Window)).data)),
        ffi::ObjectType::TabpageType =>
            Some(Object::Tabpage((*(obj as *mut ffi::C_Object_Tabpage)).data)),
        ffi::ObjectType::NilType =>
            None,
        ffi::ObjectType::BooleanType =>
            Some(Object::Boolean((*(obj as *mut ffi::C_Object_Boolean)).data)),
        ffi::ObjectType::IntegerType =>
            Some(Object::Integer((*(obj as *mut ffi::C_Object_Integer)).data)),
        ffi::ObjectType::FloatType =>
            Some(Object::Float((*(obj as *mut ffi::C_Object_Float)).data)),
        ffi::ObjectType::StringType => {
            let vim_str: ffi::C_String = (*(obj as *mut ffi::C_Object_String)).data;
            let v = Vec::from_raw_buf(vim_str.data as *const u8, vim_str.size as usize);
            Some(Object::String(String::from_utf8_unchecked(v)))
        },
        ffi::ObjectType::ArrayType =>
            Some(Object::Array((*(obj as *mut ffi::C_Object_Array)).data)),
        ffi::ObjectType::DictionaryType =>
            Some(Object::Dictionary((*(obj as *mut ffi::C_Object_Dictionary)).data)),
    }
}

pub fn main_setup(args: &Vec<String>) -> i32 {
    let v: Vec<CString> = args.iter().map(|s| CString::from_slice(s.as_bytes())).collect();
    let vp: Vec<*const ffi::c_char> = v.iter().map(|s| s.as_ptr()).collect();
    let p_vp: *const *const ffi::c_char = vp.as_ptr();

    unsafe { ffi::nvim_main_setup(vp.len() as i32, p_vp) }
}

pub fn main_loop() -> i32 {
    unsafe { ffi::nvim_main_loop() }
}

pub fn channel_from_fds(read_fd: i32, write_fd: i32) -> u64 {
    unsafe { ffi::channel_from_fds(read_fd, write_fd) }
}

pub fn serialize_message(id: u64, method: &'static str, args: &Array) -> String {
    unsafe {
        let buf = ffi::vim_msgpack_new();
        let vim_str = ffi::C_String {data: method.as_ptr() as *const i8, size: method.len() as u64};
        ffi::vim_serialize_request(id, vim_str, args.unwrap_value(), buf);
        let v = Vec::from_raw_buf((*buf).data as *const u8, (*buf).size as usize);
        ffi::vim_msgpack_free(buf);
        String::from_utf8_unchecked(v)
    }
}

pub fn deserialize_message(message: &String) -> Array {
    let s = ffi::C_String {
        data: message.as_slice().as_ptr() as *const i8,
        size: message.len() as u64
    };
    let mut arr_raw = ffi::C_Array {
        items: ::std::ptr::null_mut(),
        size: 0,
        capacity: 0,
    };
    unsafe { ffi::vim_msgpack_parse(s, &mut arr_raw) };
    Array::wrap_value(arr_raw)
}

pub struct Array {
    value: ffi::C_Array
}

impl Array {
    pub fn new() -> Array {
        Array {
            value: ffi::C_Array {
                items: ::std::ptr::null_mut(),
                size: 0,
                capacity: 0,
            }
        }
    }

    pub fn add_buffer(&mut self, val: ffi::C_Buffer) {
        unsafe { ffi::vim_array_add_buffer(val, &mut self.value) }
    }

    pub fn add_window(&mut self, val: ffi::C_Window) {
        unsafe { ffi::vim_array_add_window(val, &mut self.value) }
    }

    pub fn add_tabpage(&mut self, val: ffi::C_Tabpage) {
        unsafe { ffi::vim_array_add_tabpage(val, &mut self.value) }
    }

    pub fn add_nil(&mut self) {
        unsafe { ffi::vim_array_add_nil(&mut self.value) }
    }

    pub fn add_boolean(&mut self, val: ffi::C_Boolean) {
        unsafe { ffi::vim_array_add_boolean(val, &mut self.value) }
    }

    pub fn add_integer(&mut self, val: ffi::C_Integer) {
        unsafe { ffi::vim_array_add_integer(val, &mut self.value) }
    }

    pub fn add_float(&mut self, val: ffi::C_Float) {
        unsafe { ffi::vim_array_add_float(val, &mut self.value) }
    }

    pub fn add_string(&mut self, val: &str) {
        unsafe {
            // we need to copy the string into memory not managed by Rust,
            // so api_free_array can clear it
            let ptr = ffi::malloc(val.len() as u64);
            ::std::ptr::copy_memory(ptr, val.as_ptr() as *const ffi::c_void, val.len());
            let vim_str = ffi::C_String {data: ptr as *const i8, size: val.len() as u64};
            ffi::vim_array_add_string(vim_str, &mut self.value)
        }
    }

    pub fn add_array(&mut self, val: &Array) {
        unsafe { ffi::vim_array_add_array(val.unwrap_value(), &mut self.value) }
    }

    pub fn add_dictionary(&mut self, val: ffi::C_Dictionary) {
        unsafe { ffi::vim_array_add_dictionary(val, &mut self.value) }
    }

    pub fn get(&self, index: u64) -> Option<Object> {
        if index >= self.len() {
            return None;
        }
        unsafe { c_object_to_object(self.value.items.offset(index as isize)) }
    }

    pub fn len(&self) -> u64 {
        self.value.size
    }

    #[doc(hidden)]
    pub fn unwrap_value(&self) -> ffi::C_Array {
        self.value
    }

    #[doc(hidden)]
    pub fn wrap_value(c_array: ffi::C_Array) -> Array {
        Array {
            value: c_array
        }
    }
}

impl Drop for Array {
    fn drop(&mut self) {
        unsafe { ffi::api_free_array(self.value) };
    }
}

impl fmt::Debug for Array {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Array(").ok();
        for i in range(0, self.len()) {
            if let Some(obj) = self.get(i) {
                write!(f, "{:?}", obj).ok();
            } else {
                write!(f, "Nil").ok();
            }
            if i + 1 < self.len() {
                write!(f, ", ").ok();
            }
        }
        write!(f, ")")
    }
}

#[test]
fn test_request() {
    let mut args = Array::new();
    args.add_integer(80);
    args.add_integer(24);
    args.add_string("hello");

    let msg = serialize_message(1, "test", &args);
    let arr = deserialize_message(&msg);
    println!("LENGTH: {}", arr.len());
    for i in range(0, arr.len()) {
        println!("{:?}", arr.get(i));
    }
}
<|endoftext|>


<commit_before>#![crate_name = "gfx_graphics"]
#![deny(missing_doc)]
#![feature(phase)]

//! The implementation of a Rust-Graphics back-end using gfx-rs.

#[phase(plugin)]
extern crate gfx_macros;
extern crate device;
extern crate gfx;
extern crate graphics;
extern crate image;
extern crate gfx_texture;

pub use gfx_texture::Texture;

pub use g2d::G2D;
pub use g2d::GraphicsBackEnd;

mod g2d;
<commit_msg>Fixed missing docs warning<commit_after>#![deny(missing_docs)]
#![feature(phase)]

//! The implementation of a Rust-Graphics back-end using gfx-rs.

#[phase(plugin)]
extern crate gfx_macros;
extern crate device;
extern crate gfx;
extern crate graphics;
extern crate image;
extern crate gfx_texture;

pub use gfx_texture::Texture;

pub use g2d::G2D;
pub use g2d::GraphicsBackEnd;

mod g2d;
<|endoftext|>


<commit_before>extern crate glib_sys as glib;
extern crate gobject_2_0_sys as gobject;
extern crate gtypes;

use glib::{GList, GError, GVariant};
use gobject::GObject;
use gtypes::gboolean;
use std::os::raw::c_char;
use std::os::raw::c_int;

enum NotifyNotificationPrivate {}

#[repr(C)]
pub struct NotifyNotification {
    _parent_object: GObject,
    _priv_: NotifyNotificationPrivate,
}

extern "C" {
    pub fn notify_init(app_name: *const c_char) -> gboolean;
    pub fn notify_uninit();
    pub fn notify_is_initted() -> gboolean;

    pub fn notify_get_app_name() -> *const c_char;
    pub fn notify_set_app_name(app_name: *const c_char);

    pub fn notify_get_server_caps() -> *mut GList;

    pub fn notify_get_server_info(ret_name: *mut *mut c_char,
                                  ret_vendor: *mut *mut c_char,
                                  ret_version: *mut *mut c_char,
                                  ret_spec_version: *mut *mut c_char);

    pub fn notify_notification_new(summary: *const c_char,
                                   body: *const c_char,
                                   icon: *const c_char)
                                   -> *mut NotifyNotification;

    pub fn notify_notification_show(notification: *mut NotifyNotification,
                                    error: *mut *mut GError);

    pub fn notify_notification_set_hint(notification: *mut NotifyNotification,
                                        key: *const c_char,
                                        value: *mut GVariant);

    pub fn notify_notification_update(notification: *mut NotifyNotification,
                                      summary: *const c_char,
                                      body: *const c_char,
                                      icon: *const c_char)
                                      -> gboolean;

    pub fn notify_notification_set_timeout(notification: *mut NotifyNotification, timeout: c_int);

    pub fn notify_notification_set_category(notification: *mut NotifyNotification,
                                             category: *const c_char);
}
<commit_msg>Add notify_notification_set_urgency()<commit_after>extern crate glib_sys as glib;
extern crate gobject_2_0_sys as gobject;
extern crate gtypes;

use glib::{GList, GError, GVariant};
use gobject::GObject;
use gtypes::gboolean;
use std::os::raw::c_char;
use std::os::raw::c_int;

enum NotifyNotificationPrivate {}

#[repr(C)]
pub struct NotifyNotification {
    _parent_object: GObject,
    _priv_: NotifyNotificationPrivate,
}

#[repr(C)]
pub enum NotifyUrgency {
    NotifyUrgencyLow,
    NotifyUrgencyNormal,
    NotifyUrgencyCritical,
}

extern "C" {
    pub fn notify_init(app_name: *const c_char) -> gboolean;
    pub fn notify_uninit();
    pub fn notify_is_initted() -> gboolean;

    pub fn notify_get_app_name() -> *const c_char;
    pub fn notify_set_app_name(app_name: *const c_char);

    pub fn notify_get_server_caps() -> *mut GList;

    pub fn notify_get_server_info(ret_name: *mut *mut c_char,
                                  ret_vendor: *mut *mut c_char,
                                  ret_version: *mut *mut c_char,
                                  ret_spec_version: *mut *mut c_char);

    pub fn notify_notification_new(summary: *const c_char,
                                   body: *const c_char,
                                   icon: *const c_char)
                                   -> *mut NotifyNotification;

    pub fn notify_notification_show(notification: *mut NotifyNotification,
                                    error: *mut *mut GError);

    pub fn notify_notification_set_hint(notification: *mut NotifyNotification,
                                        key: *const c_char,
                                        value: *mut GVariant);

    pub fn notify_notification_update(notification: *mut NotifyNotification,
                                      summary: *const c_char,
                                      body: *const c_char,
                                      icon: *const c_char)
                                      -> gboolean;

    pub fn notify_notification_set_timeout(notification: *mut NotifyNotification, timeout: c_int);

    pub fn notify_notification_set_category(notification: *mut NotifyNotification,
                                             category: *const c_char);

    pub fn notify_notification_set_urgency(notification: *mut NotifyNotification,
                                            urgency: NotifyUrgency);
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate rustc_serialize;
extern crate url;
extern crate regex;

use regex::{Captures, Regex};
use rustc_serialize::json;

use hyper::Client;
use hyper::server::{Handler, Server, Request, Response};
use std::collections::HashMap;
use std::io::Read;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::channel;
use std::thread;

fn params<R: Read>(read: &mut R) -> HashMap<String, String> {
    let mut buffer = String::new();
    read.read_to_string(&mut buffer).unwrap();
    let mut params = HashMap::new();
    for (k, v) in url::form_urlencoded::parse(buffer.as_bytes()) {
        params.insert(k, v);
    }
    params
}

pub enum Resp {
    Say(String),
    Reply(String),
}

pub trait Responder {
    fn respond(&self, response: Resp) -> ();
}

pub struct DefaultResponder {
    response_url: String,
}

// todo: attachments
#[derive(Debug, RustcEncodable)]
pub struct ResponseBody {
    pub text: String,
    pub response_type: Option<String>,
}

impl Responder for DefaultResponder {
    fn respond(&self, response: Resp) {
        let body = match response {
            Resp::Say(text) => {
                ResponseBody {
                    text: text,
                    response_type: Some("in_channel".to_owned()),
                }
            }
            Resp::Reply(text) => {
                ResponseBody {
                    text: text,
                    response_type: None,
                }
            }
        };
        let client = Client::new();
        let _ = client.post(&self.response_url[..])
                      .body(json::encode(&body).unwrap().as_bytes())
                      .send();
    }
}

/// A Handle handles matched commands
pub trait Handle: Sync + Send {
    fn handle(&self,
              cmd: &Command,
              caps: &Option<Captures>,
              responder: Box<Responder>)
              -> Option<Resp>;
}

impl<F> Handle for F
    where F: Fn(&Command, &Option<Captures>, Box<Responder>) -> Option<Resp>,
          F: Send + Sync
{
    fn handle(&self,
              cmd: &Command,
              caps: &Option<Captures>,
              responder: Box<Responder>)
              -> Option<Resp> {
        self(cmd, caps, responder)
    }
}

pub struct TokenValidator<H: Handle + 'static> {
    handler: H,
    token: String,
}

impl<H: Handle + 'static> Handle for TokenValidator<H> {
    fn handle(&self,
              cmd: &Command,
              caps: &Option<Captures>,
              responder: Box<Responder>)
              -> Option<Resp> {
        if (cmd.token == self.token) {
            self.handler.handle(cmd, caps, responder)
        } else {
            None
        }
    }
}

/// A matcher matches commands
pub trait Matcher: Send + Sync {
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool);
}

impl<F> Matcher for F
    where F: Fn(&Command) -> (Option<Captures>, bool),
          F: Send + Sync
{
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool) {
        self(cmd)
    }
}

/// A direct command matcher
///
/// ```
/// mux.matching(MatchCommand("foo"), handler)
/// ```
pub struct MatchCommand(String);

impl Matcher for MatchCommand {
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool) {
        (None, cmd.command == self.0)
    }
}

/// A regex pattern matcher
///
/// ```
/// mux.matching(MatchRegex(regex), handler)
/// ```
pub struct MatchRegex(Regex);

impl Matcher for MatchRegex {
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool) {
        if self.0.is_match(cmd.command.as_ref()) {
            (self.0.captures(cmd.command.as_ref()), true)
        } else {
            (None, false)
        }
    }
}

/// A binding between a command handler and which commands its handles
pub struct Route {
    handler: Box<Handle>,
    matcher: Box<Matcher>,
}

///
/// A command de-multiplexor
///
#[derive(Default)]
pub struct Mux {
    routes: Vec<Box<Route>>,
}

impl Mux {
    ///
    /// ```
    /// mux.command("/foo", foo_handler)
    /// ```
    pub fn command<C, T, H>(&mut self, cmd: C, token: T, handler: H)
        where C: Into<String>,
              T: Into<String>,
              H: Handle + 'static
    {
        self.matching(MatchCommand(cmd.into()),
                      TokenValidator {
                          handler: handler,
                          token: token.into(),
                      })
    }

    ///
    /// ```
    /// mux.matching(matcher, handler)
    /// ```
    pub fn matching<M, H>(&mut self, matcher: M, handler: H)
        where M: Matcher + 'static,
              H: Handle + 'static
    {
        let route = Route {
            handler: Box::new(handler),
            matcher: Box::new(matcher),
        };
        self.route(route)
    }

    ///
    pub fn route(&mut self, route: Route) {
        self.routes.push(Box::new(route));
    }

    pub fn handler<'a>(&self, cmd: &'a Command) -> Option<(Option<Captures<'a>>, &Box<Handle>)> {
        for r in self.routes.iter() {
            if let (captures, true) = r.matcher.matches(cmd) {
                return Some((captures, &r.handler));
            }
        }
        None
    }
}

pub struct Listener {
    pub mux: Mux,
}

pub struct Command {
    token: String,
    team_id: String,
    team_domain: String,
    channel_id: String,
    channel_name: String,
    user_id: String,
    user_name: String,
    command: String,
    text: String,
    response_url: String,
}

impl Command {
    pub fn from_params(params: HashMap<String, String>) -> Option<Command> {
        if let (Some(token),
                Some(team_id),
                Some(team_domain),
                Some(channel_id),
                Some(channel_name),
                Some(user_id),
                Some(user_name),
                Some(command),
                Some(text),
                Some(response_url)) = (params.get("token"),
                                       params.get("team_id"),
                                       params.get("team_domain"),
                                       params.get("channel_id"),
                                       params.get("channel_name"),
                                       params.get("user_id"),
                                       params.get("user_name"),
                                       params.get("command"),
                                       params.get("text"),
                                       params.get("response_url")) {
            Some(Command {
                token: token.clone(),
                team_id: team_id.clone(),
                team_domain: team_domain.clone(),
                channel_id: channel_id.clone(),
                channel_name: channel_name.clone(),
                user_id: user_id.clone(),
                user_name: user_name.clone(),
                command: command.clone(),
                text: text.clone(),
                response_url: response_url.clone(),
            })
        } else {
            None
        }
    }
}

impl Handler for Listener {
    // https://api.slack.com/slash-commands
    fn handle(&self, req: Request, res: Response) {
        let (_, _, _, _, _, mut body) = req.deconstruct();
        // parse params
        let params = params(&mut body);
        // parse cmd
        let cmd = Command::from_params(params).unwrap();
        // set up responder
        let responder = DefaultResponder { response_url: cmd.response_url.clone() };
        // handle cmd
        if let &Some((ref captures, handler)) = &self.mux.handler(&cmd) {
            handler.handle(&cmd, &captures, Box::new(responder));
        }
        res.send(b"ok");
        ()
    }
}

#[test]
fn it_works() {}
<commit_msg>few basic tests<commit_after>extern crate hyper;
extern crate rustc_serialize;
extern crate url;
extern crate regex;

use regex::{Captures, Regex};
use rustc_serialize::json;

use hyper::Client;
use hyper::server::{Handler, Server, Request, Response};
use std::collections::HashMap;
use std::io::Read;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::channel;
use std::thread;

fn params<R: Read>(read: &mut R) -> HashMap<String, String> {
    let mut buffer = String::new();
    read.read_to_string(&mut buffer).unwrap();
    let mut params = HashMap::new();
    for (k, v) in url::form_urlencoded::parse(buffer.as_bytes()) {
        params.insert(k, v);
    }
    params
}

pub enum Resp {
    Say(String),
    Reply(String),
}

pub trait Responder {
    fn respond(&self, response: Resp) -> ();
}

pub struct DefaultResponder {
    response_url: String,
}

// todo: attachments
#[derive(Debug, RustcEncodable)]
pub struct ResponseBody {
    pub text: String,
    pub response_type: Option<String>,
}

impl Responder for DefaultResponder {
    fn respond(&self, response: Resp) {
        let body = match response {
            Resp::Say(text) => {
                ResponseBody {
                    text: text,
                    response_type: Some("in_channel".to_owned()),
                }
            }
            Resp::Reply(text) => {
                ResponseBody {
                    text: text,
                    response_type: None,
                }
            }
        };
        let client = Client::new();
        let _ = client.post(&self.response_url[..])
                      .body(json::encode(&body).unwrap().as_bytes())
                      .send();
    }
}

pub struct DiscardResponder;

impl Responder for DiscardResponder {
    fn respond(&self, resp: Resp) {

    }
}

/// A Handle handles matched commands
pub trait Handle: Sync + Send {
    fn handle(&self,
              cmd: &Command,
              caps: &Option<Captures>,
              responder: Box<Responder>)
              -> Option<Resp>;
}

impl<F> Handle for F
    where F: Fn(&Command, &Option<Captures>, Box<Responder>) -> Option<Resp>,
          F: Send + Sync
{
    fn handle(&self,
              cmd: &Command,
              caps: &Option<Captures>,
              responder: Box<Responder>)
              -> Option<Resp> {
        self(cmd, caps, responder)
    }
}

pub struct TokenValidator<H: Handle + 'static> {
    handler: H,
    token: String,
}

impl<H: Handle + 'static> Handle for TokenValidator<H> {
    fn handle(&self,
              cmd: &Command,
              caps: &Option<Captures>,
              responder: Box<Responder>)
              -> Option<Resp> {
        if cmd.token == self.token {
            self.handler.handle(cmd, caps, responder)
        } else {
            None
        }
    }
}

/// A matcher matches commands
pub trait Matcher: Send + Sync {
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool);
}

impl<F> Matcher for F
    where F: Fn(&Command) -> (Option<Captures>, bool),
          F: Send + Sync
{
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool) {
        self(cmd)
    }
}

/// A direct command matcher
///
pub struct MatchCommand(String);

impl Matcher for MatchCommand {
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool) {
        (None, cmd.command == self.0)
    }
}

/// A regex pattern matcher
///
pub struct MatchRegex(Regex);

impl Matcher for MatchRegex {
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool) {
        if self.0.is_match(cmd.command.as_ref()) {
            (self.0.captures(cmd.command.as_ref()), true)
        } else {
            (None, false)
        }
    }
}

/// A binding between a command handler and which commands its handles
pub struct Route {
    handler: Box<Handle>,
    matcher: Box<Matcher>,
}

///
/// A command de-multiplexor
///
#[derive(Default)]
pub struct Mux {
    routes: Vec<Box<Route>>,
}

impl Mux {
    pub fn command<C, T, H>(&mut self, cmd: C, token: T, handler: H)
        where C: Into<String>,
              T: Into<String>,
              H: Handle + 'static
    {
        self.matching(MatchCommand(cmd.into()),
                      TokenValidator {
                          handler: handler,
                          token: token.into(),
                      })
    }

    pub fn matching<M, H>(&mut self, matcher: M, handler: H)
        where M: Matcher + 'static,
              H: Handle + 'static
    {
        let route = Route {
            handler: Box::new(handler),
            matcher: Box::new(matcher),
        };
        self.route(route)
    }

    ///
    pub fn route(&mut self, route: Route) {
        self.routes.push(Box::new(route));
    }

    pub fn handler<'a>(&self, cmd: &'a Command) -> Option<(Option<Captures<'a>>, &Box<Handle>)> {
        for r in self.routes.iter() {
            if let (captures, true) = r.matcher.matches(cmd) {
                return Some((captures, &r.handler));
            }
        }
        None
    }
}

pub struct Listener {
    pub mux: Mux,
}

#[derive(Default)]
pub struct Command {
    token: String,
    team_id: String,
    team_domain: String,
    channel_id: String,
    channel_name: String,
    user_id: String,
    user_name: String,
    command: String,
    text: String,
    response_url: String,
}

impl Command {
    pub fn from_params(params: HashMap<String, String>) -> Option<Command> {
        if let (Some(token),
                Some(team_id),
                Some(team_domain),
                Some(channel_id),
                Some(channel_name),
                Some(user_id),
                Some(user_name),
                Some(command),
                Some(text),
                Some(response_url)) = (params.get("token"),
                                       params.get("team_id"),
                                       params.get("team_domain"),
                                       params.get("channel_id"),
                                       params.get("channel_name"),
                                       params.get("user_id"),
                                       params.get("user_name"),
                                       params.get("command"),
                                       params.get("text"),
                                       params.get("response_url")) {
            Some(Command {
                token: token.clone(),
                team_id: team_id.clone(),
                team_domain: team_domain.clone(),
                channel_id: channel_id.clone(),
                channel_name: channel_name.clone(),
                user_id: user_id.clone(),
                user_name: user_name.clone(),
                command: command.clone(),
                text: text.clone(),
                response_url: response_url.clone(),
            })
        } else {
            None
        }
    }
}

impl Handler for Listener {
    // https://api.slack.com/slash-commands
    fn handle(&self, req: Request, res: Response) {
        let (_, _, _, _, _, mut body) = req.deconstruct();
        // parse params
        let params = params(&mut body);
        // parse cmd
        let cmd = Command::from_params(params).unwrap();
        // set up responder
        let responder = DefaultResponder { response_url: cmd.response_url.clone() };
        // handle cmd
        if let &Some((ref captures, handler)) = &self.mux.handler(&cmd) {
            handler.handle(&cmd, &captures, Box::new(responder));
        }
        res.send(b"ok");
        ()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::regex::{Regex,Captures};

    #[test]
    fn matches_commands() {
        let cmd = Command { command: "/test".to_owned(), ..Default::default() };
        let (caps, matched) = MatchCommand("/test".to_owned()).matches(&cmd);
        assert!(matched)
    }

    #[test]
    fn matches_regexes() {
        let cmd = Command { command: "/test".to_owned(), ..Default::default() };
        let (caps, matched) = MatchRegex(Regex::new("(test)").unwrap()).matches(&cmd);
        assert!(matched)
    }
}
<|endoftext|>