<commit_before>//! A random.org api bindings.
//!
//! The randomness comes from atmospheric noise, which for many purposes is better than the
//! pseudo-random number algorithms typically used in computer programs. To use the library you
//! must have an api key which you may get [from here](https://api.random.org/api-keys/beta).
//!
//! # Usage
//!
//! ```rust,no_run
//! extern crate randomorg;
//!
//! fn main() {
//!     use randomorg::Random;
//!     let r = Random::new("API KEY HERE").unwrap();
//!     println!("Result: {:?}", r.generate_integers(-100, 100, 15, true));
//!     let random_data = r.request_integers().min(0).max(100).limit(5).collect::<Vec<i32>>();
//!     println!("Random integers: {:?}", random_data);
//! }
//! ```

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate reqwest;
extern crate chrono;

use reqwest::header::ContentType;

mod date_de;
mod model;
mod methods;
mod error;
mod params;
mod requests;
mod results;
mod request_builders;
pub mod version;

use methods::Method;
use requests::{
    EmptyRequest,
    GenerateIntegersRequest,
    GenerateDecimalFractionsRequest,
    GenerateGaussiansRequest,
    GenerateStringsRequest,
    GenerateUUIDsRequest,
    GenerateBlobsRequest,
};
pub use request_builders::{
    RequestIntegers,
    RequestDecimalFractions,
    RequestGaussians,
    RequestStrings,
    RequestUUIDs,
    RequestBlobs,
};
pub use model::{
    ApiKey,
    ApiKeyStatus,
    AllowedCharacters,
    Request,
    RequestId,
    Response,
};
pub use results:: {
    GetUsageResult,
    RandomResult,
    RandomData,
    GenerateIntegersResult,
    GenerateDecimalFractionsResult,
    GenerateGaussiansResult,
    GenerateStringsResult,
    GenerateUUIDsResult,
    GenerateBlobsResult,
};
pub use error::{ Error, ErrorCode, ResponseError, Result };

const API_INVOKE: &'static str = "https://api.random.org/json-rpc/2/invoke";

fn retry<F: Fn() -> reqwest::RequestBuilder>(f: F)
    -> Result<reqwest::Response> {
    let f2 = || check_status(f().send());
    // retry on a ConnectionAborted, which occurs if it's been a while since the last request
    match f2() {
        Err(_) => f2(),
        other => other
    }
}

fn check_status(response: reqwest::Result<reqwest::Response>) -> Result<reqwest::Response> {
    let response = response?;
    if !response.status().is_success() {
        return Err(Error::from(response))
    }
    Ok(response)
}

/// Macro only for internal use with the `Random` object (relies on it's fields)
macro_rules! request {
    ($api:ident, $body:expr) => {
        {
            retry(|| $api.client.post(API_INVOKE)
                                .body($body)
                                .header(ContentType::json()))
        }
    };
}

/// A random.org api client.
pub struct Random {
    client: reqwest::Client,
    api_key: ApiKey,
}

impl Random {
    /// Creates new random.org client.
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    /// }
    /// ```
    pub fn new<S: Into<String>>(api_key: S) -> Result<Random> {
        Ok(Random {
            client: reqwest::Client::new()?,
            api_key: ApiKey(api_key.into()),
        })
    }

    /// Create a request object for generating random integers
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     let random_data = r.request_integers().min(0).max(100).limit(5).collect::<Vec<i32>>();
    ///     println!("Random integers: {:?}", random_data);
    /// }
    /// ```
    pub fn request_integers(&self) -> RequestIntegers {
        RequestIntegers::new(self)
    }

    /// Create a request object for generating random decimal fractions
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     let random_data = r.request_decimal_fractions().limit(5)
    ///                                                    .decimal_places(4)
    ///                                                    .collect::<Vec<f32>>();
    ///     println!("Random decimal fractions: {:?}", random_data);
    /// }
    /// ```
    pub fn request_decimal_fractions(&self) -> RequestDecimalFractions {
        RequestDecimalFractions::new(self)
    }

    /// Create a request object for generating random gaussians
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     let random_data = r.request_gaussians().limit(5)
    ///                                            .collect::<Vec<f32>>();
    ///     println!("Random gaussians: {:?}", random_data);
    /// }
    /// ```
    pub fn request_gaussians(&self) -> RequestGaussians {
        RequestGaussians::new(self)
    }

    /// Create a request object for generating random strings
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     let random_data = r.request_strings().limit(5)
    ///                                          .collect::<Vec<String>>();
    ///     println!("Random strings: {:?}", random_data);
    /// }
    /// ```
    pub fn request_strings(&self) -> RequestStrings {
        RequestStrings::new(self)
    }

    /// Create a request object for generating random UUIDs
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     let random_data = r.request_uuids().limit(5)
    ///                                        .collect::<Vec<String>>();
    ///     println!("Random strings: {:?}", random_data);
    /// }
    /// ```
    pub fn request_uuids(&self) -> RequestUUIDs {
        RequestUUIDs::new(self)
    }

    /// Create a request object for generating random blobs
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     let random_data = r.request_blobs().limit(5)
    ///                                        .collect::<Vec<String>>();
    ///     println!("Random strings: {:?}", random_data);
    /// }
    /// ```
    pub fn request_blobs(&self) -> RequestBlobs {
        RequestBlobs::new(self)
    }

    /// This method generates true random integers within a user-defined range.
    ///
    /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateIntegers)
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     println!("Result: {:?}", r.generate_integers(-100, 100, 15, true));
    /// }
    /// ```
    ///
    /// # Constraints
    /// * `min` must be within [-1e9; 1e9] range
    /// * `max` must be within [-1e9; 1e9] range
    /// * `limit` must be within [1; 1e4] range
    pub fn generate_integers(&self, min: i32, max: i32, limit: u16, replacement: bool)
        -> Result<Response<GenerateIntegersResult>> {
        let request = GenerateIntegersRequest::new(self.api_key.clone(),
                                                   min,
                                                   max,
                                                   limit,
                                                   replacement);
        let body = serde_json::to_string(&request)?;
        Ok(request!(self, body.as_str())?.json()?)
    }

    /// This method generates true random decimal fractions from a uniform distribution across
    /// the [0,1] interval with a user-defined number of decimal places.
    ///
    /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateDecimalFractions)
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     println!("Result: {:?}", r.generate_decimal_fractions(10, 8));
    /// }
    /// ```
    ///
    /// # Constraints
    /// * `limit` must be within [1; 1e4] range
    /// * `decimal_places` must be within [1; 20] range
    pub fn generate_decimal_fractions(&self, limit: u16, decimal_places: u8)
        -> Result<Response<GenerateDecimalFractionsResult>> {
        let request = GenerateDecimalFractionsRequest::new(self.api_key.clone(),
                                                           limit,
                                                           decimal_places);
        let body = serde_json::to_string(&request)?;
        Ok(request!(self, body.as_str())?.json()?)
    }

    /// This method generates true random numbers from a Gaussian distribution (also known as a
    /// normal distribution). The form uses a Box-Muller Transform to generate the Gaussian
    /// distribution from uniformly distributed numbers.
    ///
    /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateGaussians)
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     println!("Result: {:?}", r.generate_gaussians(2000, 1100, 100, 4));
    /// }
    /// ```
    ///
    /// # Constraints
    /// * `limit` must be within [1; 1e4] range
    /// * `mean` must be within [-1e6; 1e6] range
    /// * `standard_deviation` must be within [-1e6; 1e6] range
    /// * `significant_digits` must be within [2; 20] range
    pub fn generate_gaussians(&self,
                              limit: u16,
                              mean: i32,
                              standard_deviation: i32,
                              significant_digits: u8)
        -> Result<Response<GenerateGaussiansResult>> {
        let request = GenerateGaussiansRequest::new(self.api_key.clone(),
                                                    limit,
                                                    mean,
                                                    standard_deviation,
                                                    significant_digits);
        let body = serde_json::to_string(&request)?;
        Ok(request!(self, body.as_str())?.json()?)
    }

    /// This method generates true random strings.
    ///
    /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateStrings)
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::{ Random, AllowedCharacters };
    ///     use std::collections::BTreeSet;
    ///     let chars = "abcde".chars().collect::<BTreeSet<char>>();
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     println!("Result: {:?}", r.generate_strings(5, 10, AllowedCharacters(chars)));
    /// }
    /// ```
    ///
    /// # Constraints
    /// * `limit` must be within [1; 1e4] range
    /// * `length` must be within [1; 20] range
    /// * `characters` must contain maximum 80 characters.
    pub fn generate_strings(&self, limit: u16, length: u8, characters: AllowedCharacters)
        -> Result<Response<GenerateStringsResult>> {
        let request = GenerateStringsRequest::new(self.api_key.clone(),
                                                  limit,
                                                  length,
                                                  characters);
        let body = serde_json::to_string(&request)?;
        Ok(request!(self, body.as_str())?.json()?)
    }

    /// This method generates version 4 true random Universally Unique IDentifiers (UUIDs) in
    /// accordance with section 4.4 of RFC 4122.
    ///
    /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateUUIDs)
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     println!("Result: {:?}", r.generate_uuids(5));
    /// }
    /// ```
    ///
    /// # Constraints
    /// * `limit` must be within [1; 1e3] range
    pub fn generate_uuids(&self, limit: u16) -> Result<Response<GenerateUUIDsResult>> {
        let request = GenerateUUIDsRequest::new(self.api_key.clone(), limit);
        let body = serde_json::to_string(&request)?;
        Ok(request!(self, body.as_str())?.json()?)
    }

    /// This method generates Binary Large OBjects (BLOBs) containing true random data.
    ///
    /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateBlobs)
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     println!("Result: {:?}", r.generate_blobs(5, 16));
    /// }
    /// ```
    ///
    /// # Constraints
    /// * `limit` must be within [1; 100] range
    /// * `size` must be within [1, 1048576] range
    pub fn generate_blobs(&self, limit: u16, size: u32) -> Result<Response<GenerateBlobsResult>> {
        let request = GenerateBlobsRequest::new(self.api_key.clone(), limit, size);
        let body = serde_json::to_string(&request)?;
        Ok(request!(self, body.as_str())?.json()?)
    }

    /// Returns information related to the usage of a given API key.
    ///
    /// * [Official documentation](https://api.random.org/json-rpc/2/basic#getUsage)
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     println!("Result: {:?}", r.get_usage());
    /// }
    /// ```
    pub fn get_usage(&self) -> Result<Response<GetUsageResult>> {
        let request = EmptyRequest::new(Method::GetUsage, self.api_key.clone());
        let body = serde_json::to_string(&request)?;
        Ok(request!(self, body.as_str())?.json()?)
    }
}

#[cfg(test)]
mod tests {
    fn assert_sync_and_send<T: Sync + Send>() {}

    #[test]
    fn test_sync_and_send() {
        assert_sync_and_send::<::Random>();
    }
}
<commit_msg>Add warning about multithread use<commit_after>//! A random.org api bindings.
//!
//! The randomness comes from atmospheric noise, which for many purposes is better than the
//! pseudo-random number algorithms typically used in computer programs. To use the library you
//! must have an api key which you may get [from here](https://api.random.org/api-keys/beta).
//!
//! # Usage
//!
//! ```rust,no_run
//! extern crate randomorg;
//!
//! fn main() {
//!     use randomorg::Random;
//!     let r = Random::new("API KEY HERE").unwrap();
//!     println!("Result: {:?}", r.generate_integers(-100, 100, 15, true));
//!     let random_data = r.request_integers().min(0).max(100).limit(5).collect::<Vec<i32>>();
//!     println!("Random integers: {:?}", random_data);
//! }
//! ```
//!
//! # Warning
//!
//! However the library provides a thread-safe object, the **random.org** service does not allow
//! to use their API from multithreaded-apps. The service processes incoming calls according the
//! `request_id` parameter, it must be different for concurrent calls, while this library always
//! provides `request_id` equal to `1`. So when you use the library from multiple threads the
//! library will send multiple requests simultaneously with the same `request_id` field and the
//! **random.org** service will refuse to process them.

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate reqwest;
extern crate chrono;

use reqwest::header::ContentType;

mod date_de;
mod model;
mod methods;
mod error;
mod params;
mod requests;
mod results;
mod request_builders;
pub mod version;

use methods::Method;
use requests::{
    EmptyRequest,
    GenerateIntegersRequest,
    GenerateDecimalFractionsRequest,
    GenerateGaussiansRequest,
    GenerateStringsRequest,
    GenerateUUIDsRequest,
    GenerateBlobsRequest,
};
pub use request_builders::{
    RequestIntegers,
    RequestDecimalFractions,
    RequestGaussians,
    RequestStrings,
    RequestUUIDs,
    RequestBlobs,
};
pub use model::{
    ApiKey,
    ApiKeyStatus,
    AllowedCharacters,
    Request,
    RequestId,
    Response,
};
pub use results:: {
    GetUsageResult,
    RandomResult,
    RandomData,
    GenerateIntegersResult,
    GenerateDecimalFractionsResult,
    GenerateGaussiansResult,
    GenerateStringsResult,
    GenerateUUIDsResult,
    GenerateBlobsResult,
};
pub use error::{ Error, ErrorCode, ResponseError, Result };

const API_INVOKE: &'static str = "https://api.random.org/json-rpc/2/invoke";

fn retry<F: Fn() -> reqwest::RequestBuilder>(f: F)
    -> Result<reqwest::Response> {
    let f2 = || check_status(f().send());
    // retry on a ConnectionAborted, which occurs if it's been a while since the last request
    match f2() {
        Err(_) => f2(),
        other => other
    }
}

fn check_status(response: reqwest::Result<reqwest::Response>) -> Result<reqwest::Response> {
    let response = response?;
    if !response.status().is_success() {
        return Err(Error::from(response))
    }
    Ok(response)
}

/// Macro only for internal use with the `Random` object (relies on it's fields)
macro_rules! request {
    ($api:ident, $body:expr) => {
        {
            retry(|| $api.client.post(API_INVOKE)
                                .body($body)
                                .header(ContentType::json()))
        }
    };
}

/// A random.org api client.
pub struct Random {
    client: reqwest::Client,
    api_key: ApiKey,
}

impl Random {
    /// Creates new random.org client.
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    /// }
    /// ```
    pub fn new<S: Into<String>>(api_key: S) -> Result<Random> {
        Ok(Random {
            client: reqwest::Client::new()?,
            api_key: ApiKey(api_key.into()),
        })
    }

    /// Create a request object for generating random integers
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     let random_data = r.request_integers().min(0).max(100).limit(5).collect::<Vec<i32>>();
    ///     println!("Random integers: {:?}", random_data);
    /// }
    /// ```
    pub fn request_integers(&self) -> RequestIntegers {
        RequestIntegers::new(self)
    }

    /// Create a request object for generating random decimal fractions
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     let random_data = r.request_decimal_fractions().limit(5)
    ///                                                    .decimal_places(4)
    ///                                                    .collect::<Vec<f32>>();
    ///     println!("Random decimal fractions: {:?}", random_data);
    /// }
    /// ```
    pub fn request_decimal_fractions(&self) -> RequestDecimalFractions {
        RequestDecimalFractions::new(self)
    }

    /// Create a request object for generating random gaussians
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     let random_data = r.request_gaussians().limit(5)
    ///                                            .collect::<Vec<f32>>();
    ///     println!("Random gaussians: {:?}", random_data);
    /// }
    /// ```
    pub fn request_gaussians(&self) -> RequestGaussians {
        RequestGaussians::new(self)
    }

    /// Create a request object for generating random strings
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     let random_data = r.request_strings().limit(5)
    ///                                          .collect::<Vec<String>>();
    ///     println!("Random strings: {:?}", random_data);
    /// }
    /// ```
    pub fn request_strings(&self) -> RequestStrings {
        RequestStrings::new(self)
    }

    /// Create a request object for generating random UUIDs
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     let random_data = r.request_uuids().limit(5)
    ///                                        .collect::<Vec<String>>();
    ///     println!("Random strings: {:?}", random_data);
    /// }
    /// ```
    pub fn request_uuids(&self) -> RequestUUIDs {
        RequestUUIDs::new(self)
    }

    /// Create a request object for generating random blobs
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     let random_data = r.request_blobs().limit(5)
    ///                                        .collect::<Vec<String>>();
    ///     println!("Random strings: {:?}", random_data);
    /// }
    /// ```
    pub fn request_blobs(&self) -> RequestBlobs {
        RequestBlobs::new(self)
    }

    /// This method generates true random integers within a user-defined range.
    ///
    /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateIntegers)
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     println!("Result: {:?}", r.generate_integers(-100, 100, 15, true));
    /// }
    /// ```
    ///
    /// # Constraints
    /// * `min` must be within [-1e9; 1e9] range
    /// * `max` must be within [-1e9; 1e9] range
    /// * `limit` must be within [1; 1e4] range
    pub fn generate_integers(&self, min: i32, max: i32, limit: u16, replacement: bool)
        -> Result<Response<GenerateIntegersResult>> {
        let request = GenerateIntegersRequest::new(self.api_key.clone(),
                                                   min,
                                                   max,
                                                   limit,
                                                   replacement);
        let body = serde_json::to_string(&request)?;
        Ok(request!(self, body.as_str())?.json()?)
    }

    /// This method generates true random decimal fractions from a uniform distribution across
    /// the [0,1] interval with a user-defined number of decimal places.
    ///
    /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateDecimalFractions)
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     println!("Result: {:?}", r.generate_decimal_fractions(10, 8));
    /// }
    /// ```
    ///
    /// # Constraints
    /// * `limit` must be within [1; 1e4] range
    /// * `decimal_places` must be within [1; 20] range
    pub fn generate_decimal_fractions(&self, limit: u16, decimal_places: u8)
        -> Result<Response<GenerateDecimalFractionsResult>> {
        let request = GenerateDecimalFractionsRequest::new(self.api_key.clone(),
                                                           limit,
                                                           decimal_places);
        let body = serde_json::to_string(&request)?;
        Ok(request!(self, body.as_str())?.json()?)
    }

    /// This method generates true random numbers from a Gaussian distribution (also known as a
    /// normal distribution). The form uses a Box-Muller Transform to generate the Gaussian
    /// distribution from uniformly distributed numbers.
    ///
    /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateGaussians)
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     println!("Result: {:?}", r.generate_gaussians(2000, 1100, 100, 4));
    /// }
    /// ```
    ///
    /// # Constraints
    /// * `limit` must be within [1; 1e4] range
    /// * `mean` must be within [-1e6; 1e6] range
    /// * `standard_deviation` must be within [-1e6; 1e6] range
    /// * `significant_digits` must be within [2; 20] range
    pub fn generate_gaussians(&self,
                              limit: u16,
                              mean: i32,
                              standard_deviation: i32,
                              significant_digits: u8)
        -> Result<Response<GenerateGaussiansResult>> {
        let request = GenerateGaussiansRequest::new(self.api_key.clone(),
                                                    limit,
                                                    mean,
                                                    standard_deviation,
                                                    significant_digits);
        let body = serde_json::to_string(&request)?;
        Ok(request!(self, body.as_str())?.json()?)
    }

    /// This method generates true random strings.
    ///
    /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateStrings)
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::{ Random, AllowedCharacters };
    ///     use std::collections::BTreeSet;
    ///     let chars = "abcde".chars().collect::<BTreeSet<char>>();
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     println!("Result: {:?}", r.generate_strings(5, 10, AllowedCharacters(chars)));
    /// }
    /// ```
    ///
    /// # Constraints
    /// * `limit` must be within [1; 1e4] range
    /// * `length` must be within [1; 20] range
    /// * `characters` must contain maximum 80 characters.
    pub fn generate_strings(&self, limit: u16, length: u8, characters: AllowedCharacters)
        -> Result<Response<GenerateStringsResult>> {
        let request = GenerateStringsRequest::new(self.api_key.clone(),
                                                  limit,
                                                  length,
                                                  characters);
        let body = serde_json::to_string(&request)?;
        Ok(request!(self, body.as_str())?.json()?)
    }

    /// This method generates version 4 true random Universally Unique IDentifiers (UUIDs) in
    /// accordance with section 4.4 of RFC 4122.
    ///
    /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateUUIDs)
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     println!("Result: {:?}", r.generate_uuids(5));
    /// }
    /// ```
    ///
    /// # Constraints
    /// * `limit` must be within [1; 1e3] range
    pub fn generate_uuids(&self, limit: u16) -> Result<Response<GenerateUUIDsResult>> {
        let request = GenerateUUIDsRequest::new(self.api_key.clone(), limit);
        let body = serde_json::to_string(&request)?;
        Ok(request!(self, body.as_str())?.json()?)
    }

    /// This method generates Binary Large OBjects (BLOBs) containing true random data.
    ///
    /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateBlobs)
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     println!("Result: {:?}", r.generate_blobs(5, 16));
    /// }
    /// ```
    ///
    /// # Constraints
    /// * `limit` must be within [1; 100] range
    /// * `size` must be within [1, 1048576] range
    pub fn generate_blobs(&self, limit: u16, size: u32) -> Result<Response<GenerateBlobsResult>> {
        let request = GenerateBlobsRequest::new(self.api_key.clone(), limit, size);
        let body = serde_json::to_string(&request)?;
        Ok(request!(self, body.as_str())?.json()?)
    }

    /// Returns information related to the usage of a given API key.
    ///
    /// * [Official documentation](https://api.random.org/json-rpc/2/basic#getUsage)
    ///
    /// # Usage
    ///
    /// ```rust,no_run
    /// extern crate randomorg;
    ///
    /// fn main() {
    ///     use randomorg::Random;
    ///     let r = Random::new("API KEY HERE").unwrap();
    ///     println!("Result: {:?}", r.get_usage());
    /// }
    /// ```
    pub fn get_usage(&self) -> Result<Response<GetUsageResult>> {
        let request = EmptyRequest::new(Method::GetUsage, self.api_key.clone());
        let body = serde_json::to_string(&request)?;
        Ok(request!(self, body.as_str())?.json()?)
    }
}

#[cfg(test)]
mod tests {
    fn assert_sync_and_send<T: Sync + Send>() {}

    #[test]
    fn test_sync_and_send() {
        assert_sync_and_send::<::Random>();
    }
}
<|endoftext|>


<commit_before>#![feature(plugin, collections, str_char)]
#![plugin(peg_syntax_ext)]

extern crate rustc_serialize;

use gdl::description;

peg_file! gdl("grammar.rustpeg");

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Description {
    pub clauses: Vec<Clause>
}

impl Description {
    pub fn new(clauses: Vec<Clause>) -> Description {
        Description { clauses: clauses }
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub enum Clause {
    RuleClause(Rule),
    SentenceClause(Sentence)
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Rule {
    pub head: Sentence,
    pub body: Vec<Literal>
}

impl Rule {
    pub fn new(head: Sentence, body: Vec<Literal>) -> Rule {
        Rule { head: head, body: body }
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub enum Sentence {
    PropSentence(Proposition),
    RelSentence(Relation)
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub enum Literal {
    NotLit(Not),
    OrLit(Or),
    DistinctLit(Distinct),
    PropLit(Proposition),
    RelLit(Relation)
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub enum Term {
    VarTerm(Variable),
    FuncTerm(Function),
    ConstTerm(Constant)
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Proposition {
    pub name: Constant
}

impl Proposition {
    pub fn new(name: Constant) -> Proposition {
        Proposition { name: name}
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Relation {
    pub name: Constant,
    pub args: Vec<Term>
}

impl Relation {
    pub fn new(name: Constant, args: Vec<Term>) -> Relation {
        Relation { name: name, args: args }
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Not {
    pub lit: Box<Literal>
}

impl Not {
    pub fn new(lit: Box<Literal>) -> Not {
        Not { lit: lit }
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Or {
    pub lits: Vec<Literal>
}

impl Or {
    pub fn new(lits: Vec<Literal>) -> Or {
        Or { lits: lits }
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Distinct {
    pub term1: Term,
    pub term2: Term
}

impl Distinct {
    pub fn new(term1: Term, term2: Term) -> Distinct {
        Distinct { term1: term1, term2: term2 }
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Variable {
    pub name: Constant
}

impl Variable {
    pub fn new(name: Constant) -> Variable {
        Variable { name: name }
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Function {
    pub name: Constant,
    pub args: Vec<Term>
}

impl Function {
    pub fn new(name: Constant, args: Vec<Term>) -> Function {
        Function { name: name, args: args }
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Constant {
    pub name: String
}

impl Constant {
    pub fn new(name: String) -> Constant {
        Constant { name: name }
    }
}

pub fn parse(s: &str) -> Description {
    match description(s) {
        Ok(d) => d,
        Err(e) => panic!("{}", e)
    }
}
<commit_msg>Implemented `Into` trait<commit_after>#![feature(plugin, collections, str_char)]
#![plugin(peg_syntax_ext)]

extern crate rustc_serialize;

use gdl::description;
use self::Sentence::{PropSentence, RelSentence};
use self::Literal::{NotLit, DistinctLit, OrLit, PropLit, RelLit};
use self::Term::{VarTerm, FuncTerm, ConstTerm};

peg_file! gdl("grammar.rustpeg");

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Description {
    pub clauses: Vec<Clause>
}

impl Description {
    pub fn new(clauses: Vec<Clause>) -> Description {
        Description { clauses: clauses }
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub enum Clause {
    RuleClause(Rule),
    SentenceClause(Sentence)
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Rule {
    pub head: Sentence,
    pub body: Vec<Literal>
}

impl Rule {
    pub fn new(head: Sentence, body: Vec<Literal>) -> Rule {
        Rule { head: head, body: body }
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub enum Sentence {
    PropSentence(Proposition),
    RelSentence(Relation)
}

impl Into<Literal> for Sentence {
    fn into(self) -> Literal {
        match self {
            PropSentence(p) => PropLit(p),
            RelSentence(r) => RelLit(r)
        }
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub enum Literal {
    NotLit(Not),
    OrLit(Or),
    DistinctLit(Distinct),
    PropLit(Proposition),
    RelLit(Relation)
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub enum Term {
    VarTerm(Variable),
    FuncTerm(Function),
    ConstTerm(Constant)
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Proposition {
    pub name: Constant
}

impl Proposition {
    pub fn new(name: Constant) -> Proposition {
        Proposition { name: name }
    }
}

impl Into<Literal> for Proposition {
    fn into(self) -> Literal {
        PropLit(self)
    }
}

impl Into<Sentence> for Proposition {
    fn into(self) -> Sentence {
        PropSentence(self)
    }
}

impl Into<Relation> for Proposition {
    fn into(self) -> Relation {
        Relation::new(self.name, Vec::new())
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Relation {
    pub name: Constant,
    pub args: Vec<Term>
}

impl Relation {
    pub fn new(name: Constant, args: Vec<Term>) -> Relation {
        Relation { name: name, args: args }
    }
}

impl Into<Literal> for Relation {
    fn into(self) -> Literal {
        RelLit(self)
    }
}

impl Into<Sentence> for Relation {
    fn into(self) -> Sentence {
        RelSentence(self)
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Not {
    pub lit: Box<Literal>
}

impl Not {
    pub fn new(lit: Box<Literal>) -> Not {
        Not { lit: lit }
    }
}

impl Into<Literal> for Not {
    fn into(self) -> Literal {
        NotLit(self)
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Or {
    pub lits: Vec<Literal>
}

impl Or {
    pub fn new(lits: Vec<Literal>) -> Or {
        Or { lits: lits }
    }
}

impl Into<Literal> for Or {
    fn into(self) -> Literal {
        OrLit(self)
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Distinct {
    pub term1: Term,
    pub term2: Term
}

impl Distinct {
    pub fn new(term1: Term, term2: Term) -> Distinct {
        Distinct { term1: term1, term2: term2 }
    }
}

impl Into<Literal> for Distinct {
    fn into(self) -> Literal {
        DistinctLit(self)
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Variable {
    pub name: Constant
}

impl Variable {
    pub fn new(name: Constant) -> Variable {
        Variable { name: name }
    }
}

impl Into<Term> for Variable {
    fn into(self) -> Term {
        VarTerm(self)
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Function {
    pub name: Constant,
    pub args: Vec<Term>
}

impl Function {
    pub fn new(name: Constant, args: Vec<Term>) -> Function {
        Function { name: name, args: args }
    }
}

impl Into<Term> for Function {
    fn into(self) -> Term {
        FuncTerm(self)
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Constant {
    pub name: String
}

impl Constant {
    pub fn new(name: String) -> Constant {
        Constant { name: name }
    }
}

impl Into<Term> for Constant {
    fn into(self) -> Term {
        ConstTerm(self)
    }
}

pub fn parse(s: &str) -> Description {
    match description(s) {
        Ok(d) => d,
        Err(e) => panic!("{}", e)
    }
}
<|endoftext|>


<commit_before>#[test]
fn it_works() {
}
<commit_msg>Import existing work on Russet.<commit_after>//! # Russet
//!
//! __Russet__ is a simple string tokenising library for Rust.  It supports
//! POSIX shell-style separation of a line of _words_ into a vector of
//! strings.
#![experimental]

use std::char::is_whitespace;

#[deriving(Clone)]
struct TokeniserState {
    vec:       Vec<String>,
    in_word:   bool,
    in_quoted: bool,
    in_escape: bool
}

/// A tokeniser error.
#[deriving(Eq, PartialEq, Show)]
pub enum Error {
    /// A quotation was opened, but not closed.
    UnmatchedQuote,

    /// An escape sequence was started, but not finished.
    UnfinishedEscape
}

impl TokeniserState {
    /// Creates a new, blank TokeniserState.
    fn new() -> TokeniserState {
        TokeniserState {
            vec:       vec![ String::new() ],
            in_word:   false,
            in_quoted: false,
            in_escape: false
        }
    }

    // Performs one step of the tokeniser.
    fn step(self, chr: char) -> TokeniserState {
        let mut new = self.clone();

        match (chr, self) {
            // Escape character while not escaped
            // -> Begin escape (and word if not in one already)
            ( '\\', TokeniserState { in_escape: false, .. } ) => {
                new.in_escape = true;
                new.in_word   = true;
            },
            // Unescaped quote character
            // -> Toggle quoting
            ( '"', TokeniserState { in_escape: false, .. } ) => {
                new.in_quoted = !new.in_quoted;
                new.in_word   = true;
            },
            // Unescaped whitespace, while not in a word
            // -> Ignore
            ( a, TokeniserState { in_escape: false, in_word: false, .. } )
                if is_whitespace(a) => (),
            // Unescaped whitespace, while in a non-quoted word
            // -> End word
            ( a, TokeniserState {
                in_escape: false,
                in_word:   true,
                in_quoted: false,
                ..
            } ) if is_whitespace(a) => {
                new.in_word = false;
                new.vec.push(String::new());
            },
            // Escaped n
            // -> Newline
            ( 'n', TokeniserState { in_escape: true, .. } ) => {
                new.in_word   = true;
                new.in_escape = false;
                new.vec.mut_last().mutate(|s| { s.push_char('\n'); s });
            },
            // Anything else
            // -> Echo
            ( a, _ ) => {
                new.in_word   = true;
                new.in_escape = false;
                new.vec.mut_last().mutate(|s| { s.push_char(a); s });
            }
        }

        new
    }

    /// Destroys the tokeniser, extracting the string vector.
    fn unwrap(mut self) -> Result<Vec<String>, Error> {
        if self.in_word && self.in_quoted {
            Err(UnmatchedQuote)
        } else if self.in_escape {
            Err(UnfinishedEscape)
        } else {
            if self.vec.last().map(|s| s.len() == 0).unwrap_or(false) {
                self.vec.pop();
            }

            Ok(self.vec)
        }
    }
}

/// Unpacks a line into its constituent words.
#[experimental]
pub fn unpack(line: &str) -> Result<Vec<String>, Error> {
    line.trim().chars().fold(
        TokeniserState::new(), |s, chr| s.step(chr)
    ).unwrap()
}

#[cfg(test)]
mod test {
    use super::{
        unpack,
        UnmatchedQuote,
        UnfinishedEscape
    };

    #[test]
    fn unpack_unmatched_quote() {
        assert_eq!(unpack("\"abcde"), Err(UnmatchedQuote));
    }

    #[test]
    fn unpack_unfinished_escape() {
        assert_eq!(unpack("zxcvbn m\\"), Err(UnfinishedEscape));
    }

    #[test]
    fn unpack_empty_string() {
        assert_eq!(unpack(""), Ok(vec![]));
    }

    #[test]
    fn unpack_leading_whitespace() {
        let rhs = vec![ "abc".into_string(), "def".into_string() ];
        assert_eq!(unpack("     abc def"), Ok(rhs));
    }

    #[test]
    fn unpack_trailing_whitespace() {
        let rhs = vec![ "ghi".into_string(), "jkl".into_string() ];
        assert_eq!(unpack("ghi jkl     \n"), Ok(rhs));
    }

    #[test]
    fn unpack_enqueue_command() {
        let lhs =
            "enqueue file \"C:\\\\Users\\\\Test\\\\Artist - Title.mp3\" 1";
        let rhs = vec![ "enqueue".into_string(),
                        "file".into_string(),
                        "C:\\Users\\Test\\Artist - Title.mp3".into_string(),
                        "1".into_string() ];
        assert_eq!(unpack(lhs), Ok(rhs));
    }

    #[test]
    fn unpack_escaped_newline() {
        assert_eq!(unpack("abc\\nde"),     Ok(vec![ "abc\nde".into_string() ]));
        assert_eq!(unpack("\"abc\\nde\""), Ok(vec![ "abc\nde".into_string() ]));
    }
}
<|endoftext|>


<commit_before>#![crate_name = "bindgen"]
#![crate_type = "dylib"]

extern crate syntex_syntax as syntax;
extern crate libc;
#[macro_use] extern crate log;

use std::collections::HashSet;
use std::default::Default;
use std::io::{Write, self};
use std::fs::OpenOptions;
use std::path::{Path, self};
use std::{env, fs};

use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::print::pprust;
use syntax::print::pp::eof;
use syntax::ptr::P;

use types::Global;

mod types;
mod clangll;
mod clang;
mod gen;
mod parser;

#[derive(Clone)]
pub struct Builder<'a> {
    options: BindgenOptions,
    logger: Option<&'a Logger>
}

pub fn builder<'a>() -> Builder<'a> {
    Default::default()
}

impl<'a> Builder<'a> {
    pub fn header<T: Into<String>>(&mut self, header: T) -> &mut Self {
        self.options.clang_args.push(header.into());
        self
    }

    pub fn link<T: Into<String>>(&mut self, library: T) -> &mut Self {
        self.options.links.push((library.into(), LinkType::Default));
        self
    }

    pub fn link_static<T: Into<String>>(&mut self, library: T) -> &mut Self {
        self.options.links.push((library.into(), LinkType::Static));
        self
    }

    pub fn link_framework<T: Into<String>>(&mut self, library: T) -> &mut Self {
        self.options.links.push((library.into(), LinkType::Framework));
        self
    }

    pub fn forbid_unknown_types(&mut self) -> &mut Self {
        self.options.fail_on_unknown_type = true;
        self
    }

    pub fn emit_builtins(&mut self) -> &mut Self {
        self.options.builtins = true;
        self
    }

    pub fn log(&mut self, logger: &'a Logger) -> &mut Self {
        self.logger = Some(logger);
        self
    }

    pub fn generate(&self) -> Result<Bindings, ()> {
        Bindings::generate(&self.options, self.logger, None)
    }
}

impl<'a> Default for Builder<'a> {
    fn default() -> Builder<'a> {
        Builder {
            logger: None,
            options: Default::default()
        }
    }
}

#[derive(Clone)]
/// Deprecated - use a `Builder` instead
pub struct BindgenOptions {
    pub match_pat: Vec<String>,
    pub builtins: bool,
    pub links: Vec<(String, LinkType)>,
    pub emit_ast: bool,
    pub fail_on_unknown_type: bool,
    pub override_enum_ty: String,
    pub clang_args: Vec<String>,
}

impl Default for BindgenOptions {
    fn default() -> BindgenOptions {
        BindgenOptions {
            match_pat: Vec::new(),
            builtins: false,
            links: Vec::new(),
            emit_ast: false,
            fail_on_unknown_type: false,
            override_enum_ty: "".to_string(),
            clang_args: Vec::new()
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LinkType {
    Default,
    Static,
    Framework
}

pub trait Logger {
    fn error(&self, msg: &str);
    fn warn(&self, msg: &str);
}

#[derive(Clone)]
pub struct Bindings {
    module: ast::Mod
}

impl Bindings {
    /// Deprecated - use a `Builder` instead
    pub fn generate(options: &BindgenOptions, logger: Option<&Logger>, span: Option<Span>) -> Result<Bindings, ()> {
        let l = DummyLogger;
        let logger = match logger {
            Some(l) => l,
            None => &l as &Logger
        };

        let span = match span {
            Some(s) => s,
            None => DUMMY_SP
        };

        let globals = try!(parse_headers(options, logger));

        let module = ast::Mod {
            inner: span,
            items: gen::gen_mod(&options.links[..], globals, span)
        };

        Ok(Bindings {
            module: module
        })
    }

    pub fn into_ast(self) -> Vec<P<ast::Item>> {
        self.module.items
    }

    pub fn to_string(&self) -> String {
        let mut mod_str = Vec::new();
        {
            let ref_writer = Box::new(mod_str.by_ref()) as Box<Write>;
            self.write(ref_writer).ok().expect("Could not write bindings to string");
        }
        String::from_utf8(mod_str).unwrap()
    }

    pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
        let file = try!(OpenOptions::new().write(true).truncate(true).create(true).open(path));
        self.write(Box::new(file))
    }

    pub fn write<'a, 'b>(&'a self, mut writer: Box<Write + 'b>) -> io::Result<()> {
        try!(writer.write("/* automatically generated by rust-bindgen */\n\n".as_bytes()));
        let mut ps = pprust::rust_printer(writer);
        try!(ps.print_mod(&self.module, &[]));
        try!(ps.print_remaining_comments());
        try!(eof(&mut ps.s));
        ps.s.out.flush()
    }
}

struct DummyLogger;

impl Logger for DummyLogger {
    fn error(&self, _msg: &str) { }
    fn warn(&self, _msg: &str) { }
}

fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<Vec<Global>, ()> {
    fn str_to_ikind(s: &str) -> Option<types::IKind> {
        match s {
            "uchar"     => Some(types::IUChar),
            "schar"     => Some(types::ISChar),
            "ushort"    => Some(types::IUShort),
            "sshort"    => Some(types::IShort),
            "uint"      => Some(types::IUInt),
            "sint"      => Some(types::IInt),
            "ulong"     => Some(types::IULong),
            "slong"     => Some(types::ILong),
            "ulonglong" => Some(types::IULongLong),
            "slonglong" => Some(types::ILongLong),
            _           => None,
        }
    }

    let clang_opts = parser::ClangParserOptions {
        builtin_names: builtin_names(),
        builtins: options.builtins,
        match_pat: options.match_pat.clone(),
        emit_ast: options.emit_ast,
        fail_on_unknown_type: options.fail_on_unknown_type,
        override_enum_ty: str_to_ikind(&options.override_enum_ty[..]),
        clang_args: options.clang_args.clone(),
    };

    parser::parse(clang_opts, logger)
}

fn builtin_names() -> HashSet<String> {
    let mut names = HashSet::new();
    let keys = [
        "__va_list_tag",
        "__va_list",
        "__builtin_va_list",
    ];

    keys.iter().all(|s| {
        names.insert(s.to_string());
        true
    });

    return names;
}

#[test]
fn builder_state()
{
    let logger = DummyLogger;
    let mut build = builder();
    {
        build.header("example.h");
        build.link_static("m");
        build.log(&logger);
    }
    assert!(build.logger.is_some());
    assert!(build.options.clang_args.binary_search(&"example.h".to_string()).is_ok());
    assert!(build.options.links.binary_search(&("m".to_string(), LinkType::Static)).is_ok());
}

// Get the first directory in PATH that contains a file named "clang".
fn get_clang_dir() -> Option<path::PathBuf>{
    match env::var_os("PATH") {
        Some(paths) => {
            for p in env::split_paths(&paths) {
                let mut bin_path = p.clone();
                bin_path.push("clang");
                match fs::metadata(bin_path) {
                    Ok(m) => {
                        if m.is_file() {
                            return Some(p);
                        }
                    }
                    _ => (),
                }
            }
            None
        }
        None => None,
    }
}

// Try to find the directory that contains clang's bundled headers. Clang itself does something
// very similar: it takes the parent directory of the current executable, appends
// "../lib/clang/<VERSIONSTRING>/include". We have two problems emulating this behaviour:
// * We don't have a very good way of finding the clang executable, but can fake this by
//   searching $PATH and take one directory that contains "clang".
// * We don't have access to <VERSIONSTRING>. There is clang_getClangVersion(), but it returns
//   a human-readable description string which is not guaranteed to be stable and a pain to parse.
//   We work around that by just taking the first directory in ../lib/clang and hope it's the
//   current version.
// TODO: test if this works on Windows at all.
#[doc(hidden)]
pub fn get_include_dir() -> Option<String> {
    match get_clang_dir() {
        Some(mut p) => {
            p.push("..");
            p.push("lib");
            p.push("clang");

            let dir_iter = match fs::read_dir(p) {
                Ok(dir_iter) => dir_iter,
                _ => return None
            };
            for dir in dir_iter {
                match dir {
                    Ok(dir) => {
                        // Let's take the first dir. In my case, there's only one directory
                        // there anyway.
                        let mut p = dir.path();
                        p.push("include");
                        match p.into_os_string().into_string() {
                            Ok(s) => return Some(s),
                            // We found the directory, but can't access it as it contains
                            // invalid unicode.
                            _ => return None,
                        }
                    }
                    _ => return None,
                }
            }
            None
        }
        None => None,
    }
}
<commit_msg>Add Builder::clang_arg<commit_after>#![crate_name = "bindgen"]
#![crate_type = "dylib"]

extern crate syntex_syntax as syntax;
extern crate libc;
#[macro_use] extern crate log;

use std::collections::HashSet;
use std::default::Default;
use std::io::{Write, self};
use std::fs::OpenOptions;
use std::path::{Path, self};
use std::{env, fs};

use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::print::pprust;
use syntax::print::pp::eof;
use syntax::ptr::P;

use types::Global;

mod types;
mod clangll;
mod clang;
mod gen;
mod parser;

#[derive(Clone)]
pub struct Builder<'a> {
    options: BindgenOptions,
    logger: Option<&'a Logger>
}

pub fn builder<'a>() -> Builder<'a> {
    Default::default()
}

impl<'a> Builder<'a> {
    pub fn header<T: Into<String>>(&mut self, header: T) -> &mut Self {
        self.clang_arg(header)
    }

    pub fn clang_arg<T: Into<String>>(&mut self, arg: T) -> &mut Self {
        self.options.clang_args.push(arg.into());
        self
    }

    pub fn link<T: Into<String>>(&mut self, library: T) -> &mut Self {
        self.options.links.push((library.into(), LinkType::Default));
        self
    }

    pub fn link_static<T: Into<String>>(&mut self, library: T) -> &mut Self {
        self.options.links.push((library.into(), LinkType::Static));
        self
    }

    pub fn link_framework<T: Into<String>>(&mut self, library: T) -> &mut Self {
        self.options.links.push((library.into(), LinkType::Framework));
        self
    }

    pub fn forbid_unknown_types(&mut self) -> &mut Self {
        self.options.fail_on_unknown_type = true;
        self
    }

    pub fn emit_builtins(&mut self) -> &mut Self {
        self.options.builtins = true;
        self
    }

    pub fn log(&mut self, logger: &'a Logger) -> &mut Self {
        self.logger = Some(logger);
        self
    }

    pub fn generate(&self) -> Result<Bindings, ()> {
        Bindings::generate(&self.options, self.logger, None)
    }
}

impl<'a> Default for Builder<'a> {
    fn default() -> Builder<'a> {
        Builder {
            logger: None,
            options: Default::default()
        }
    }
}

#[derive(Clone)]
/// Deprecated - use a `Builder` instead
pub struct BindgenOptions {
    pub match_pat: Vec<String>,
    pub builtins: bool,
    pub links: Vec<(String, LinkType)>,
    pub emit_ast: bool,
    pub fail_on_unknown_type: bool,
    pub override_enum_ty: String,
    pub clang_args: Vec<String>,
}

impl Default for BindgenOptions {
    fn default() -> BindgenOptions {
        BindgenOptions {
            match_pat: Vec::new(),
            builtins: false,
            links: Vec::new(),
            emit_ast: false,
            fail_on_unknown_type: false,
            override_enum_ty: "".to_string(),
            clang_args: Vec::new()
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LinkType {
    Default,
    Static,
    Framework
}

pub trait Logger {
    fn error(&self, msg: &str);
    fn warn(&self, msg: &str);
}

#[derive(Clone)]
pub struct Bindings {
    module: ast::Mod
}

impl Bindings {
    /// Deprecated - use a `Builder` instead
    pub fn generate(options: &BindgenOptions, logger: Option<&Logger>, span: Option<Span>) -> Result<Bindings, ()> {
        let l = DummyLogger;
        let logger = match logger {
            Some(l) => l,
            None => &l as &Logger
        };

        let span = match span {
            Some(s) => s,
            None => DUMMY_SP
        };

        let globals = try!(parse_headers(options, logger));

        let module = ast::Mod {
            inner: span,
            items: gen::gen_mod(&options.links[..], globals, span)
        };

        Ok(Bindings {
            module: module
        })
    }

    pub fn into_ast(self) -> Vec<P<ast::Item>> {
        self.module.items
    }

    pub fn to_string(&self) -> String {
        let mut mod_str = Vec::new();
        {
            let ref_writer = Box::new(mod_str.by_ref()) as Box<Write>;
            self.write(ref_writer).ok().expect("Could not write bindings to string");
        }
        String::from_utf8(mod_str).unwrap()
    }

    pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
        let file = try!(OpenOptions::new().write(true).truncate(true).create(true).open(path));
        self.write(Box::new(file))
    }

    pub fn write<'a, 'b>(&'a self, mut writer: Box<Write + 'b>) -> io::Result<()> {
        try!(writer.write("/* automatically generated by rust-bindgen */\n\n".as_bytes()));
        let mut ps = pprust::rust_printer(writer);
        try!(ps.print_mod(&self.module, &[]));
        try!(ps.print_remaining_comments());
        try!(eof(&mut ps.s));
        ps.s.out.flush()
    }
}

struct DummyLogger;

impl Logger for DummyLogger {
    fn error(&self, _msg: &str) { }
    fn warn(&self, _msg: &str) { }
}

fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<Vec<Global>, ()> {
    fn str_to_ikind(s: &str) -> Option<types::IKind> {
        match s {
            "uchar"     => Some(types::IUChar),
            "schar"     => Some(types::ISChar),
            "ushort"    => Some(types::IUShort),
            "sshort"    => Some(types::IShort),
            "uint"      => Some(types::IUInt),
            "sint"      => Some(types::IInt),
            "ulong"     => Some(types::IULong),
            "slong"     => Some(types::ILong),
            "ulonglong" => Some(types::IULongLong),
            "slonglong" => Some(types::ILongLong),
            _           => None,
        }
    }

    let clang_opts = parser::ClangParserOptions {
        builtin_names: builtin_names(),
        builtins: options.builtins,
        match_pat: options.match_pat.clone(),
        emit_ast: options.emit_ast,
        fail_on_unknown_type: options.fail_on_unknown_type,
        override_enum_ty: str_to_ikind(&options.override_enum_ty[..]),
        clang_args: options.clang_args.clone(),
    };

    parser::parse(clang_opts, logger)
}

fn builtin_names() -> HashSet<String> {
    let mut names = HashSet::new();
    let keys = [
        "__va_list_tag",
        "__va_list",
        "__builtin_va_list",
    ];

    keys.iter().all(|s| {
        names.insert(s.to_string());
        true
    });

    return names;
}

#[test]
fn builder_state()
{
    let logger = DummyLogger;
    let mut build = builder();
    {
        build.header("example.h");
        build.link_static("m");
        build.log(&logger);
    }
    assert!(build.logger.is_some());
    assert!(build.options.clang_args.binary_search(&"example.h".to_string()).is_ok());
    assert!(build.options.links.binary_search(&("m".to_string(), LinkType::Static)).is_ok());
}

// Get the first directory in PATH that contains a file named "clang".
fn get_clang_dir() -> Option<path::PathBuf>{
    match env::var_os("PATH") {
        Some(paths) => {
            for p in env::split_paths(&paths) {
                let mut bin_path = p.clone();
                bin_path.push("clang");
                match fs::metadata(bin_path) {
                    Ok(m) => {
                        if m.is_file() {
                            return Some(p);
                        }
                    }
                    _ => (),
                }
            }
            None
        }
        None => None,
    }
}

// Try to find the directory that contains clang's bundled headers. Clang itself does something
// very similar: it takes the parent directory of the current executable, appends
// "../lib/clang/<VERSIONSTRING>/include". We have two problems emulating this behaviour:
// * We don't have a very good way of finding the clang executable, but can fake this by
//   searching $PATH and take one directory that contains "clang".
// * We don't have access to <VERSIONSTRING>. There is clang_getClangVersion(), but it returns
//   a human-readable description string which is not guaranteed to be stable and a pain to parse.
//   We work around that by just taking the first directory in ../lib/clang and hope it's the
//   current version.
// TODO: test if this works on Windows at all.
#[doc(hidden)]
pub fn get_include_dir() -> Option<String> {
    match get_clang_dir() {
        Some(mut p) => {
            p.push("..");
            p.push("lib");
            p.push("clang");

            let dir_iter = match fs::read_dir(p) {
                Ok(dir_iter) => dir_iter,
                _ => return None
            };
            for dir in dir_iter {
                match dir {
                    Ok(dir) => {
                        // Let's take the first dir. In my case, there's only one directory
                        // there anyway.
                        let mut p = dir.path();
                        p.push("include");
                        match p.into_os_string().into_string() {
                            Ok(s) => return Some(s),
                            // We found the directory, but can't access it as it contains
                            // invalid unicode.
                            _ => return None,
                        }
                    }
                    _ => return None,
                }
            }
            None
        }
        None => None,
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/fern/0.5.8")]
//! Efficient, configurable logging in Rust.
//!
//! # Depending on fern
//!
//! Ensure you require both fern and log in your project's `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! log = "0.4"
//! fern = "0.5"
//! ```
//!
//! Then declare both in `main.rs` or `lib.rs`:
//!
//! ```
//! #[macro_use]
//! extern crate log;
//! extern crate fern;
//! # fn main() {}
//! ```
//!
//! # Example setup
//!
//! With fern, all logger configuration is done via builder-like methods on
//! instances of the [`Dispatch`] structure.
//!
//! Here's an example logger which formats messages, and sends everything Debug
//! and above to both stdout and an output.log file:
//!
//! ```no_run
//! extern crate fern;
//! #[macro_use]
//! extern crate log;
//!
//! extern crate chrono;
//!
//! fn setup_logger() -> Result<(), fern::InitError> {
//!     fern::Dispatch::new()
//!         .format(|out, message, record| {
//!             out.finish(format_args!(
//!                 "{}[{}][{}] {}",
//!                 chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
//!                 record.target(),
//!                 record.level(),
//!                 message
//!             ))
//!         })
//!         .level(log::LevelFilter::Debug)
//!         .chain(std::io::stdout())
//!         .chain(fern::log_file("output.log")?)
//!         .apply()?;
//!     Ok(())
//! }
//! # fn main() {
//! #     setup_logger().expect("failed to set up logger")
//! # }
//! ```
//!
//! Let's unwrap this:
//!
//! ---
//!
//! [`fern::Dispatch::new()`]
//!
//! Create an empty configuration.
//!
//! ---
//!
//! [`.format(|...| ...)`]
//!
//! Add a formatter to the logger, modifying all messages sent through.
//!
//! ___
//!
//! [`chrono::Local::now()`]
//!
//! Get the current time in the local timezone using the [`chrono`] library.
//! See the [time-and-date docs].
//!
//! ___
//!
//! [`.format("[%Y-%m-%d][%H:%M:%S]")`][chrono-format]
//!
//! Use chrono's lazy format specifier to turn the time into a readable string.
//!
//! ---
//!
//! [`out.finish(format_args!(...))`]
//!
//! Call the `fern::FormattingCallback` to submit the formatted message.
//!
//! This roundabout way is slightly odd, but it allows for very fast logging.
//! No string allocation required!
//!
//! [`format_args!()`] has the same format as [`println!()`] \(and every other
//! [`std::fmt`]-based macro).
//!
//! ---
//!
//! [`.level(log::LevelFilter::Debug)`]
//!
//! Set the minimum level needed to output to `Debug`.
//!
//! ---
//!
//! [`.chain(std::io::stdout())`]
//!
//! Add a child to the logger. All messages which pass the filters will be sent
//! to stdout.
//!
//! [`Dispatch::chain`] accepts [`Stdout`], [`Stderr`], [`File`] and other
//! [`Dispatch`] instances.
//!
//! ---
//!
//! [`.chain(fern::log_file(...)?)`]
//!
//! Add a second child sending messages to the file "output.log".
//!
//! See [`fern::log_file()`] for more info on file output.
//!
//! ---
//!
//! [`.apply()`][`.apply`]
//!
//! Consume the configuration and instantiate it as the current runtime global
//! logger.
//!
//! This will fail if and only if `.apply()` or equivalent form another crate
//! has already been used this runtime.
//!
//! Since the binary crate is the only one ever setting up logging, the
//! [`apply`] result can be reasonably unwrapped: it's a bug if any crate is
//! calling this method more than once.
//!
//! ---
//!
//! The final output will look like:
//!
//! ```text
//! [2017-01-20][12:55:04][crate-name][INFO] Hello, world!
//! [2017-01-20][12:56:21][crate-name][WARN] Ahhh!
//! [2017-01-20][12:58:00][crate-name][DEBUG] Something less important happened.
//! ```
//!
//! # Logging
//!
//! Once the logger has been set, it will pick up all logging calls from your
//! crate and all libraries you depend on.
//!
//! ```rust
//! # #[macro_use]
//! # extern crate log;
//! # extern crate fern;
//!
//! # fn setup_logger() -> Result<(), fern::InitError> {
//! fern::Dispatch::new()
//!     // ...
//!     .apply()?;
//! # Ok(())
//! # }
//!
//! # fn main() {
//! # setup_logger().ok(); // we're ok with this not succeeding.
//! trace!("Trace message");
//! debug!("Debug message");
//! info!("Info message");
//! warn!("Warning message");
//! error!("Error message");
//! # }
//! ```
//!
//! # More
//!
//! The [`Dispatch` documentation] has example usages of each method, and the
//! [full example program] might be useful for using fern in a larger
//! application context.
//!
//! See the [colors] module for examples using ANSI terminal coloring.
//!
//! See the [syslog] module for examples outputting to the unix syslog, or the
//! [syslog full example program] for a more realistic sample.
//!
//! See the [meta] module for information on getting logging-within-logging
//! working correctly.
//!
//! [`fern::Dispatch::new()`]: struct.Dispatch.html#method.new
//! [`.format(|...| ...)`]: struct.Dispatch.html#method.format
//! [`chrono::Local::now()`]: https://docs.rs/chrono/0.4/chrono/offset/local/struct.Local.html#method.now
//! [chrono-format]: https://docs.rs/chrono/0.4/chrono/datetime/struct.DateTime.html#method.format
//! [`out.finish(format_args!(...))`]: struct.FormatCallback.html#method.finish
//! [`.level(log::LevelFilter::Debug)`]: struct.Dispatch.html#method.level
//! [`Dispatch::chain`]: struct.Dispatch.html#method.chain
//! [`.chain(std::io::stdout())`]: struct.Dispatch.html#method.chain
//! [`Stdout`]: https://doc.rust-lang.org/std/io/struct.Stdout.html
//! [`Stderr`]: https://doc.rust-lang.org/std/io/struct.Stderr.html
//! [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html
//! [`Dispatch`]: struct.Dispatch.html
//! [`.chain(fern::log_file(...)?)`]: struct.Dispatch.html#method.chain
//! [`fern::log_file()`]: fn.log_file.html
//! [`.apply`]: struct.Dispatch.html#method.apply
//! [`format_args!()`]: https://doc.rust-lang.org/std/macro.format_args.html
//! [`println!()`]: https://doc.rust-lang.org/std/macro.println.html
//! [`std::fmt`]: https://doc.rust-lang.org/std/fmt/
//! [`chrono`]: https://github.com/chronotope/chrono
//! [time-and-date docs]: https://docs.rs/chrono/0.4/chrono/index.html#date-and-time
//! [the format specifier docs]: https://docs.rs/chrono/0.4/chrono/format/strftime/index.html#specifiers
//! [`Dispatch` documentation]: struct.Dispatch.html
//! [full example program]: https://github.com/daboross/fern/tree/master/examples/cmd-program.rs
//! [syslog full example program]: https://github.com/daboross/fern/tree/master/examples/syslog.rs
//! [`apply`]: struct.Dispatch.html#method.apply
//! [colors]: colors/index.html
//! [syslog]: syslog/index.html
//! [meta]: meta/index.html
#[cfg(feature = "colored")]
extern crate colored;
extern crate log;
#[cfg(all(not(windows), feature = "syslog-4"))]
extern crate syslog as syslog_4;
#[cfg(all(not(windows), feature = "syslog-3"))]
extern crate syslog3 as syslog_3;
#[cfg(all(not(windows), feature = "reopen-03"))]
extern crate reopen;

use std::convert::AsRef;
use std::fs::{File, OpenOptions};
use std::path::Path;
use std::{fmt, io};

#[cfg(all(not(windows), feature = "syslog-4"))]
use std::collections::HashMap;

pub use builders::{Dispatch, Output, Panic};
pub use errors::InitError;
pub use log_impl::FormatCallback;

mod builders;
mod errors;
mod log_impl;

#[cfg(feature = "colored")]
pub mod colors;
#[cfg(all(not(windows), feature = "syslog-3", feature = "syslog-4"))]
pub mod syslog;

pub mod meta;

/// A type alias for a log formatter.
///
/// As of fern `0.5`, the passed `fmt::Arguments` will always be the same as
/// the given `log::Record`'s `.args()`.
pub type Formatter = Fn(FormatCallback, &fmt::Arguments, &log::Record) + Sync + Send + 'static;

/// A type alias for a log filter. Returning true means the record should
/// succeed - false means it should fail.
pub type Filter = Fn(&log::Metadata) -> bool + Send + Sync + 'static;

pub use builders::DateBasedLogFile;

#[cfg(all(not(windows), feature = "syslog-4"))]
type Syslog4Rfc3164Logger =
    syslog_4::Logger<syslog_4::LoggerBackend, String, syslog_4::Formatter3164>;

#[cfg(all(not(windows), feature = "syslog-4"))]
type Syslog4Rfc5424Logger = syslog_4::Logger<
    syslog_4::LoggerBackend,
    (i32, HashMap<String, HashMap<String, String>>, String),
    syslog_4::Formatter5424,
>;

/// Convenience method for opening a log file with common options.
///
/// Equivalent to:
///
/// ```no_run
/// std::fs::OpenOptions::new()
///     .write(true)
///     .create(true)
///     .append(true)
///     .open("filename")
/// # ;
/// ```
///
/// See [`OpenOptions`] for more information.
///
/// [`OpenOptions`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html
#[inline]
pub fn log_file<P: AsRef<Path>>(path: P) -> io::Result<File> {
    OpenOptions::new()
        .write(true)
        .create(true)
        .append(true)
        .open(path)
}

/// Convenience method for opening a re-openable log file with common options.
///
/// The file opening is equivalent to:
///
/// ```no_run
/// std::fs::OpenOptions::new()
///     .write(true)
///     .create(true)
///     .append(true)
///     .open("filename")
/// # ;
/// ```
///
/// See [`OpenOptions`] for more information.
///
/// [`OpenOptions`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html
#[cfg(all(not(windows), feature = "reopen-03"))]
#[inline]
pub fn log_reopen(path: &Path) -> io::Result<reopen::Reopen<File>> {
    let p = path.to_owned();
    reopen::Reopen::new(Box::new(move || {
        OpenOptions::new()
            .create(true)
            .write(true)
            .append(true)
            .open(&p)
    }))
}
<commit_msg>Allow setting a signal in the reopen wrapper<commit_after>#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/fern/0.5.8")]
//! Efficient, configurable logging in Rust.
//!
//! # Depending on fern
//!
//! Ensure you require both fern and log in your project's `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! log = "0.4"
//! fern = "0.5"
//! ```
//!
//! Then declare both in `main.rs` or `lib.rs`:
//!
//! ```
//! #[macro_use]
//! extern crate log;
//! extern crate fern;
//! # fn main() {}
//! ```
//!
//! # Example setup
//!
//! With fern, all logger configuration is done via builder-like methods on
//! instances of the [`Dispatch`] structure.
//!
//! Here's an example logger which formats messages, and sends everything Debug
//! and above to both stdout and an output.log file:
//!
//! ```no_run
//! extern crate fern;
//! #[macro_use]
//! extern crate log;
//!
//! extern crate chrono;
//!
//! fn setup_logger() -> Result<(), fern::InitError> {
//!     fern::Dispatch::new()
//!         .format(|out, message, record| {
//!             out.finish(format_args!(
//!                 "{}[{}][{}] {}",
//!                 chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
//!                 record.target(),
//!                 record.level(),
//!                 message
//!             ))
//!         })
//!         .level(log::LevelFilter::Debug)
//!         .chain(std::io::stdout())
//!         .chain(fern::log_file("output.log")?)
//!         .apply()?;
//!     Ok(())
//! }
//! # fn main() {
//! #     setup_logger().expect("failed to set up logger")
//! # }
//! ```
//!
//! Let's unwrap this:
//!
//! ---
//!
//! [`fern::Dispatch::new()`]
//!
//! Create an empty configuration.
//!
//! ---
//!
//! [`.format(|...| ...)`]
//!
//! Add a formatter to the logger, modifying all messages sent through.
//!
//! ___
//!
//! [`chrono::Local::now()`]
//!
//! Get the current time in the local timezone using the [`chrono`] library.
//! See the [time-and-date docs].
//!
//! ___
//!
//! [`.format("[%Y-%m-%d][%H:%M:%S]")`][chrono-format]
//!
//! Use chrono's lazy format specifier to turn the time into a readable string.
//!
//! ---
//!
//! [`out.finish(format_args!(...))`]
//!
//! Call the `fern::FormattingCallback` to submit the formatted message.
//!
//! This roundabout way is slightly odd, but it allows for very fast logging.
//! No string allocation required!
//!
//! [`format_args!()`] has the same format as [`println!()`] \(and every other
//! [`std::fmt`]-based macro).
//!
//! ---
//!
//! [`.level(log::LevelFilter::Debug)`]
//!
//! Set the minimum level needed to output to `Debug`.
//!
//! ---
//!
//! [`.chain(std::io::stdout())`]
//!
//! Add a child to the logger. All messages which pass the filters will be sent
//! to stdout.
//!
//! [`Dispatch::chain`] accepts [`Stdout`], [`Stderr`], [`File`] and other
//! [`Dispatch`] instances.
//!
//! ---
//!
//! [`.chain(fern::log_file(...)?)`]
//!
//! Add a second child sending messages to the file "output.log".
//!
//! See [`fern::log_file()`] for more info on file output.
//!
//! ---
//!
//! [`.apply()`][`.apply`]
//!
//! Consume the configuration and instantiate it as the current runtime global
//! logger.
//!
//! This will fail if and only if `.apply()` or equivalent form another crate
//! has already been used this runtime.
//!
//! Since the binary crate is the only one ever setting up logging, the
//! [`apply`] result can be reasonably unwrapped: it's a bug if any crate is
//! calling this method more than once.
//!
//! ---
//!
//! The final output will look like:
//!
//! ```text
//! [2017-01-20][12:55:04][crate-name][INFO] Hello, world!
//! [2017-01-20][12:56:21][crate-name][WARN] Ahhh!
//! [2017-01-20][12:58:00][crate-name][DEBUG] Something less important happened.
//! ```
//!
//! # Logging
//!
//! Once the logger has been set, it will pick up all logging calls from your
//! crate and all libraries you depend on.
//!
//! ```rust
//! # #[macro_use]
//! # extern crate log;
//! # extern crate fern;
//!
//! # fn setup_logger() -> Result<(), fern::InitError> {
//! fern::Dispatch::new()
//!     // ...
//!     .apply()?;
//! # Ok(())
//! # }
//!
//! # fn main() {
//! # setup_logger().ok(); // we're ok with this not succeeding.
//! trace!("Trace message");
//! debug!("Debug message");
//! info!("Info message");
//! warn!("Warning message");
//! error!("Error message");
//! # }
//! ```
//!
//! # More
//!
//! The [`Dispatch` documentation] has example usages of each method, and the
//! [full example program] might be useful for using fern in a larger
//! application context.
//!
//! See the [colors] module for examples using ANSI terminal coloring.
//!
//! See the [syslog] module for examples outputting to the unix syslog, or the
//! [syslog full example program] for a more realistic sample.
//!
//! See the [meta] module for information on getting logging-within-logging
//! working correctly.
//!
//! [`fern::Dispatch::new()`]: struct.Dispatch.html#method.new
//! [`.format(|...| ...)`]: struct.Dispatch.html#method.format
//! [`chrono::Local::now()`]: https://docs.rs/chrono/0.4/chrono/offset/local/struct.Local.html#method.now
//! [chrono-format]: https://docs.rs/chrono/0.4/chrono/datetime/struct.DateTime.html#method.format
//! [`out.finish(format_args!(...))`]: struct.FormatCallback.html#method.finish
//! [`.level(log::LevelFilter::Debug)`]: struct.Dispatch.html#method.level
//! [`Dispatch::chain`]: struct.Dispatch.html#method.chain
//! [`.chain(std::io::stdout())`]: struct.Dispatch.html#method.chain
//! [`Stdout`]: https://doc.rust-lang.org/std/io/struct.Stdout.html
//! [`Stderr`]: https://doc.rust-lang.org/std/io/struct.Stderr.html
//! [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html
//! [`Dispatch`]: struct.Dispatch.html
//! [`.chain(fern::log_file(...)?)`]: struct.Dispatch.html#method.chain
//! [`fern::log_file()`]: fn.log_file.html
//! [`.apply`]: struct.Dispatch.html#method.apply
//! [`format_args!()`]: https://doc.rust-lang.org/std/macro.format_args.html
//! [`println!()`]: https://doc.rust-lang.org/std/macro.println.html
//! [`std::fmt`]: https://doc.rust-lang.org/std/fmt/
//! [`chrono`]: https://github.com/chronotope/chrono
//! [time-and-date docs]: https://docs.rs/chrono/0.4/chrono/index.html#date-and-time
//! [the format specifier docs]: https://docs.rs/chrono/0.4/chrono/format/strftime/index.html#specifiers
//! [`Dispatch` documentation]: struct.Dispatch.html
//! [full example program]: https://github.com/daboross/fern/tree/master/examples/cmd-program.rs
//! [syslog full example program]: https://github.com/daboross/fern/tree/master/examples/syslog.rs
//! [`apply`]: struct.Dispatch.html#method.apply
//! [colors]: colors/index.html
//! [syslog]: syslog/index.html
//! [meta]: meta/index.html
#[cfg(feature = "colored")]
extern crate colored;
#[cfg(all(not(windows), feature = "reopen-03"))]
extern crate libc;
extern crate log;
#[cfg(all(not(windows), feature = "syslog-4"))]
extern crate syslog as syslog_4;
#[cfg(all(not(windows), feature = "syslog-3"))]
extern crate syslog3 as syslog_3;
#[cfg(all(not(windows), feature = "reopen-03"))]
extern crate reopen;

use std::convert::AsRef;
use std::fs::{File, OpenOptions};
use std::path::Path;
use std::{fmt, io};

#[cfg(all(not(windows), feature = "syslog-4"))]
use std::collections::HashMap;

pub use builders::{Dispatch, Output, Panic};
pub use errors::InitError;
pub use log_impl::FormatCallback;

mod builders;
mod errors;
mod log_impl;

#[cfg(feature = "colored")]
pub mod colors;
#[cfg(all(not(windows), feature = "syslog-3", feature = "syslog-4"))]
pub mod syslog;

pub mod meta;

/// A type alias for a log formatter.
///
/// As of fern `0.5`, the passed `fmt::Arguments` will always be the same as
/// the given `log::Record`'s `.args()`.
pub type Formatter = Fn(FormatCallback, &fmt::Arguments, &log::Record) + Sync + Send + 'static;

/// A type alias for a log filter. Returning true means the record should
/// succeed - false means it should fail.
pub type Filter = Fn(&log::Metadata) -> bool + Send + Sync + 'static;

pub use builders::DateBasedLogFile;

#[cfg(all(not(windows), feature = "syslog-4"))]
type Syslog4Rfc3164Logger =
    syslog_4::Logger<syslog_4::LoggerBackend, String, syslog_4::Formatter3164>;

#[cfg(all(not(windows), feature = "syslog-4"))]
type Syslog4Rfc5424Logger = syslog_4::Logger<
    syslog_4::LoggerBackend,
    (i32, HashMap<String, HashMap<String, String>>, String),
    syslog_4::Formatter5424,
>;

/// Convenience method for opening a log file with common options.
///
/// Equivalent to:
///
/// ```no_run
/// std::fs::OpenOptions::new()
///     .write(true)
///     .create(true)
///     .append(true)
///     .open("filename")
/// # ;
/// ```
///
/// See [`OpenOptions`] for more information.
///
/// [`OpenOptions`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html
#[inline]
pub fn log_file<P: AsRef<Path>>(path: P) -> io::Result<File> {
    OpenOptions::new()
        .write(true)
        .create(true)
        .append(true)
        .open(path)
}

/// Convenience method for opening a re-openable log file with common options.
///
/// The file opening is equivalent to:
///
/// ```no_run
/// std::fs::OpenOptions::new()
///     .write(true)
///     .create(true)
///     .append(true)
///     .open("filename")
/// # ;
/// ```
///
/// See [`OpenOptions`] for more information.
///
/// [`OpenOptions`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html
#[cfg(all(not(windows), feature = "reopen-03"))]
#[inline]
pub fn log_reopen(path: &Path, signal: Option<libc::c_int>) -> io::Result<reopen::Reopen<File>> {
    let p = path.to_owned();
    let r = reopen::Reopen::new(Box::new(move || {
        OpenOptions::new()
            .create(true)
            .write(true)
            .append(true)
            .open(&p)
    }))?;

    if let Some(s) = signal {
        if let Err(e) = r.handle().register_signal(s) {
            return Err(e)
        }
    }
    Ok(r)
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

#[macro_use] extern crate bitflags;
extern crate libc;

use std::io::{self, Error};
use std::os::unix::io::RawFd;

bitflags! {
    pub struct ControlOptions: i32 {
        /// Indicates an addition to the interest list.
        const EPOLL_CTL_ADD = libc::EPOLL_CTL_ADD;
        /// Indicates a modification of flags for an interest already in list.
        const EPOLL_CTL_MOD = libc::EPOLL_CTL_MOD;
        /// Indicates a removal of an interest from the list.
        const EPOLL_CTL_DEL = libc::EPOLL_CTL_DEL;
    }
}

bitflags! {
    pub struct Events: u32 {
        /// Sets the Edge Triggered behavior for the associated file descriptor.
        ///
        /// The default behavior for epoll is Level Triggered.
        const EPOLLET      = libc::EPOLLET as u32;
        /// The associated file is available for read operations.
        const EPOLLIN      = libc::EPOLLIN as u32;
        /// Error condition happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; is not necessary to set it in events.
        const EPOLLERR     = libc::EPOLLERR as u32;
        /// Hang up happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; it is not necessary to set it in events.
        /// Note that when reading from a channel such as a pipe or a stream socket, this event
        /// merely indicates that the peer closed its end of the channel. Subsequent reads from
        /// the channel will return 0 (end of file) only after all outstanding data in the
        /// channel has been consumed.
        const EPOLLHUP     = libc::EPOLLHUP as u32;
        /// The associated file is available for write operations.
        const EPOLLOUT     = libc::EPOLLOUT as u32;
        /// There is urgent data available for read operations.
        const EPOLLPRI     = libc::EPOLLPRI as u32;
        /// Stream socket peer closed connection, or shut down writing half of connection.
        ///
        /// This flag is especially useful for writing simple code to detect peer shutdown when
        /// using Edge Triggered monitoring.
        const EPOLLRDHUP   = libc::EPOLLRDHUP as u32;
        /// If `EPOLLONESHOT` and `EPOLLET` are clear and the process has the `CAP_BLOCK_SUSPEND`
        /// capability, ensure that the system does not enter "suspend" or "hibernate" while this
        /// event is pending or being processed.
        ///
        /// The event is considered as being "processed" from the time when it is returned by
        /// a call to `wait` until the next call to `wait` on the same `EpollInstance`
        /// descriptor, the closure of that file descriptor, the removal of the event file
        /// descriptor with `EPOLL_CTL_DEL`, or the clearing of `EPOLLWAKEUP` for the event file
        /// descriptor with `EPOLL_CTL_MOD`.
        const EPOLLWAKEUP  = libc::EPOLLWAKEUP as u32;
        /// Sets the one-shot behavior for the associated file descriptor.
        ///
        /// This means that after an event is pulled out with `wait` the associated file
        /// descriptor is internally disabled and no other events will be reported by the epoll
        /// interface.  The user must call `ctl` with `EPOLL_CTL_MOD` to rearm the file
        /// descriptor with a new event mask.
        const EPOLLONESHOT = libc::EPOLLONESHOT as u32;
    }
}

/// 'libc::epoll_event' equivalent.
#[repr(C)]
#[repr(packed)]
#[derive(Clone, Copy)]
pub struct Event {
    pub events: u32,
    pub data: u64
}

impl Event {
    pub fn new(events: Events, data: u64) -> Event {
        Event { events: events.bits(), data: data }
    }
}

/// Creates a new epoll file descriptor.
///
/// If `cloexec` is true, `FD_CLOEXEC` will be set on the returned file descriptor.
///
/// ## Notes
///
/// * `epoll_create(1)` is the underlying syscall.
pub fn create(cloexec: bool) -> io::Result<RawFd> {
    let epfd = unsafe {
        let fd = try!(cvt(libc::epoll_create(1)));
        if cloexec {
            let mut flags = try!(cvt(libc::fcntl(fd, libc::F_GETFD)));
            flags |= libc::FD_CLOEXEC;
            try!(cvt(libc::fcntl(fd, libc::F_SETFD, flags)));
        }
        fd
    };
    Ok(epfd)
}

/// Safe wrapper for `libc::epoll_ctl`
pub fn ctl(epfd: RawFd,
           op: ControlOptions,
           fd: RawFd,
           mut event: Event)
           -> io::Result<()>
{
    let e = &mut event as *mut _ as *mut libc::epoll_event;
    unsafe { try!(cvt(libc::epoll_ctl(epfd, op.bits, fd, e))) };
    Ok(())
}

/// Safe wrapper for `libc::epoll_wait`
///
/// ## Notes
///
/// * If `timeout` is negative, it will block until an event is received.
pub fn wait(epfd: RawFd,
            timeout: i32,
            buf: &mut [Event])
            -> io::Result<usize>
{
    let timeout = if timeout < -1 { -1 } else { timeout };
    let num_events = unsafe {
        try!(cvt(libc::epoll_wait(epfd,
                                  buf.as_mut_ptr() as *mut libc::epoll_event,
                                  buf.len() as i32,
                                  timeout))) as usize
    };
    Ok(num_events)
}

fn cvt(result: libc::c_int) -> io::Result<libc::c_int> {
    if result < 0 { Err(Error::last_os_error()) } else { Ok(result) }
}
<commit_msg>replace obsolete epoll_create by epoll_create1, reduce number of syscall<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

#[macro_use] extern crate bitflags;
extern crate libc;

use std::io::{self, Error};
use std::os::unix::io::RawFd;

bitflags! {
    pub struct ControlOptions: i32 {
        /// Indicates an addition to the interest list.
        const EPOLL_CTL_ADD = libc::EPOLL_CTL_ADD;
        /// Indicates a modification of flags for an interest already in list.
        const EPOLL_CTL_MOD = libc::EPOLL_CTL_MOD;
        /// Indicates a removal of an interest from the list.
        const EPOLL_CTL_DEL = libc::EPOLL_CTL_DEL;
    }
}

bitflags! {
    pub struct Events: u32 {
        /// Sets the Edge Triggered behavior for the associated file descriptor.
        ///
        /// The default behavior for epoll is Level Triggered.
        const EPOLLET      = libc::EPOLLET as u32;
        /// The associated file is available for read operations.
        const EPOLLIN      = libc::EPOLLIN as u32;
        /// Error condition happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; is not necessary to set it in events.
        const EPOLLERR     = libc::EPOLLERR as u32;
        /// Hang up happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; it is not necessary to set it in events.
        /// Note that when reading from a channel such as a pipe or a stream socket, this event
        /// merely indicates that the peer closed its end of the channel. Subsequent reads from
        /// the channel will return 0 (end of file) only after all outstanding data in the
        /// channel has been consumed.
        const EPOLLHUP     = libc::EPOLLHUP as u32;
        /// The associated file is available for write operations.
        const EPOLLOUT     = libc::EPOLLOUT as u32;
        /// There is urgent data available for read operations.
        const EPOLLPRI     = libc::EPOLLPRI as u32;
        /// Stream socket peer closed connection, or shut down writing half of connection.
        ///
        /// This flag is especially useful for writing simple code to detect peer shutdown when
        /// using Edge Triggered monitoring.
        const EPOLLRDHUP   = libc::EPOLLRDHUP as u32;
        /// If `EPOLLONESHOT` and `EPOLLET` are clear and the process has the `CAP_BLOCK_SUSPEND`
        /// capability, ensure that the system does not enter "suspend" or "hibernate" while this
        /// event is pending or being processed.
        ///
        /// The event is considered as being "processed" from the time when it is returned by
        /// a call to `wait` until the next call to `wait` on the same `EpollInstance`
        /// descriptor, the closure of that file descriptor, the removal of the event file
        /// descriptor with `EPOLL_CTL_DEL`, or the clearing of `EPOLLWAKEUP` for the event file
        /// descriptor with `EPOLL_CTL_MOD`.
        const EPOLLWAKEUP  = libc::EPOLLWAKEUP as u32;
        /// Sets the one-shot behavior for the associated file descriptor.
        ///
        /// This means that after an event is pulled out with `wait` the associated file
        /// descriptor is internally disabled and no other events will be reported by the epoll
        /// interface.  The user must call `ctl` with `EPOLL_CTL_MOD` to rearm the file
        /// descriptor with a new event mask.
        const EPOLLONESHOT = libc::EPOLLONESHOT as u32;
    }
}

/// 'libc::epoll_event' equivalent.
#[repr(C)]
#[repr(packed)]
#[derive(Clone, Copy)]
pub struct Event {
    pub events: u32,
    pub data: u64
}

impl Event {
    pub fn new(events: Events, data: u64) -> Event {
        Event { events: events.bits(), data: data }
    }
}

/// Creates a new epoll file descriptor.
///
/// If `cloexec` is true, `FD_CLOEXEC` will be set on the returned file descriptor.
///
/// ## Notes
///
/// * `epoll_create1()` is the underlying syscall.
pub fn create(cloexec: bool) -> io::Result<RawFd> {
    let flags = if cloexec { libc::FD_CLOEXEC } else { 0 };
    unsafe { cvt(libc::epoll_create1(flags)) }
}

/// Safe wrapper for `libc::epoll_ctl`
pub fn ctl(epfd: RawFd,
           op: ControlOptions,
           fd: RawFd,
           mut event: Event)
           -> io::Result<()>
{
    let e = &mut event as *mut _ as *mut libc::epoll_event;
    unsafe { try!(cvt(libc::epoll_ctl(epfd, op.bits, fd, e))) };
    Ok(())
}

/// Safe wrapper for `libc::epoll_wait`
///
/// ## Notes
///
/// * If `timeout` is negative, it will block until an event is received.
pub fn wait(epfd: RawFd,
            timeout: i32,
            buf: &mut [Event])
            -> io::Result<usize>
{
    let timeout = if timeout < -1 { -1 } else { timeout };
    let num_events = unsafe {
        try!(cvt(libc::epoll_wait(epfd,
                                  buf.as_mut_ptr() as *mut libc::epoll_event,
                                  buf.len() as i32,
                                  timeout))) as usize
    };
    Ok(num_events)
}

fn cvt(result: libc::c_int) -> io::Result<libc::c_int> {
    if result < 0 { Err(Error::last_os_error()) } else { Ok(result) }
}
<|endoftext|>