<commit_before>#![feature(globs)]

extern crate conduit;

use std::fmt::Show;

use conduit::{Request, Response, Handler};

pub trait Middleware: Send + Sync {
    fn before(&self, _: &mut Request) -> Result<(), Box<Show>> {
        Ok(())
    }

    fn after(&self, _: &mut Request, res: Result<Response, Box<Show>>)
             -> Result<Response, Box<Show>>
    {
        res
    }
}

pub trait AroundMiddleware: Handler {
    fn with_handler(&mut self, handler: Box<Handler + Send + Sync>);
}

pub struct MiddlewareBuilder {
    middlewares: Vec<Box<Middleware + Send + Sync>>,
    handler: Option<Box<Handler + Send + Sync>>
}

impl MiddlewareBuilder {
    pub fn new<H: Handler>(handler: H) -> MiddlewareBuilder {
        MiddlewareBuilder {
            middlewares: vec!(),
            handler: Some(box handler as Box<Handler + Send + Sync>)
        }
    }

    pub fn add<M: Middleware>(&mut self, middleware: M) {
        self.middlewares.push(box middleware as Box<Middleware + Send + Sync>);
    }

    pub fn around<M: AroundMiddleware>(&mut self, mut middleware: M) {
        let handler = self.handler.take_unwrap();
        middleware.with_handler(handler);
        self.handler = Some(box middleware as Box<Handler + Send + Sync>);
    }
}

impl Handler for MiddlewareBuilder {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Show>> {
        let mut error = None;

        for (i, middleware) in self.middlewares.iter().enumerate() {
            match middleware.before(req) {
                Ok(_) => (),
                Err(err) => {
                    error = Some((err, i));
                    break;
                }
            }
        }

        match error {
            Some((err, i)) => {
                let middlewares = self.middlewares.slice_to(i);
                run_afters(middlewares, req, Err(err))
            },
            None => {
                let res = { self.handler.get_ref().call(req) };
                let middlewares = self.middlewares.as_slice();

                run_afters(middlewares, req, res)
            }
        }
    }
}

fn run_afters(middleware: &[Box<Middleware>],
                  req: &mut Request,
                  res: Result<Response, Box<Show>>)
                  -> Result<Response, Box<Show>>
{
    middleware.iter().rev().fold(res, |res, m| m.after(req, res))
}

#[cfg(test)]
mod tests {
    extern crate semver;

    use {MiddlewareBuilder, Middleware, AroundMiddleware};

    use std::io::net::ip::IpAddr;
    use std::io::MemReader;
    use std::fmt;
    use std::fmt::{Show, Formatter};
    use std::collections::HashMap;

    use conduit;
    use conduit::{Request, Response, Host, Headers, Method, Scheme, Extensions};
    use conduit::{Handler, TypeMap};

    struct RequestSentinel {
        path: String,
        extensions: TypeMap,
        method: Method
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: TypeMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    struct MyMiddleware;

    impl Middleware for MyMiddleware {
        fn before<'a>(&self, req: &'a mut Request) -> Result<(), Box<Show>> {
            req.mut_extensions().insert("hello".to_string());
            Ok(())
        }
    }

    struct ErrorRecovery;

    impl Middleware for ErrorRecovery {
        fn after(&self, _: &mut Request, res: Result<Response, Box<Show>>)
                     -> Result<Response, Box<Show>>
        {
            res.or_else(|e| {
                Ok(Response {
                    status: (500, "Internal Server Error"),
                    headers: HashMap::new(),
                    body: box MemReader::new(show(e).to_string().into_bytes())
                })
            })
        }
    }

    struct ProducesError;

    impl Middleware for ProducesError {
        fn before(&self, _: &mut Request) -> Result<(), Box<Show>> {
            Err(box "Nope".to_string() as Box<Show>)
        }
    }

    struct NotReached;

    impl Middleware for NotReached {
        fn after(&self, _: &mut Request, _: Result<Response, Box<Show>>)
                     -> Result<Response, Box<Show>>
        {
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(vec!())
            })
        }
    }

    struct MyAroundMiddleware {
        handler: Option<Box<Handler + Send + Sync>>
    }

    impl MyAroundMiddleware {
        fn new() -> MyAroundMiddleware {
            MyAroundMiddleware { handler: None }
        }
    }

    impl Middleware for MyAroundMiddleware {}

    impl AroundMiddleware for MyAroundMiddleware {
        fn with_handler(&mut self, handler: Box<Handler + Send + Sync>) {
            self.handler = Some(handler)
        }
    }

    impl Handler for MyAroundMiddleware {
        fn call(&self, req: &mut Request) -> Result<Response, Box<Show>> {
            req.mut_extensions().insert("hello".to_string());
            self.handler.get_ref().call(req)
        }
    }

    struct Shower<'a> {
        inner: &'a Show
    }

    impl<'a> Show for Shower<'a> {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
            self.inner.fmt(f)
        }
    }

    fn show<'a>(s: &'a Show) -> Shower<'a> {
        Shower { inner: s }
    }

    fn get_extension<'a, T: 'static>(req: &'a Request) -> &'a T {
        req.extensions().find::<T>().unwrap()
    }

    fn response(string: String) -> Response {
        Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(string.into_bytes())
        }
    }

    fn handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req);
        Ok(response(hello.clone()))
    }

    fn error_handler(_: &mut Request) -> Result<Response, String> {
        Err("Error in handler".to_string())
    }

    fn middle_handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req);
        let middle = get_extension::<String>(req);

        Ok(response(format!("{} {}", hello, middle)))
    }

    #[test]
    fn test_simple_middleware() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(MyMiddleware);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_string().ok().expect("No body"), "hello".to_string());
    }

    #[test]
    fn test_error_recovery() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(ErrorRecovery);
        builder.add(ProducesError);
        // the error bubbles up from ProducesError and shouldn't reach here
        builder.add(NotReached);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
    }

    #[test]
    fn test_error_recovery_in_handlers() {
        let mut builder = MiddlewareBuilder::new(error_handler);
        builder.add(ErrorRecovery);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
        assert_eq!(res.body.read_to_string().ok().expect("No body"), "Error in handler".to_string());
    }

    #[test]
    fn test_around_middleware() {
        let mut builder = MiddlewareBuilder::new(middle_handler);
        builder.add(MyMiddleware);
        builder.around(MyAroundMiddleware::new());

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_string().ok().expect("No body"), "hello hello".to_string());
    }
}
<commit_msg>Update to master<commit_after>#![feature(globs)]

extern crate conduit;

use std::fmt::Show;

use conduit::{Request, Response, Handler};

pub trait Middleware: Send + Sync {
    fn before(&self, _: &mut Request) -> Result<(), Box<Show + 'static>> {
        Ok(())
    }

    fn after(&self, _: &mut Request, res: Result<Response, Box<Show + 'static>>)
             -> Result<Response, Box<Show + 'static>>
    {
        res
    }
}

pub trait AroundMiddleware: Handler {
    fn with_handler(&mut self, handler: Box<Handler + Send + Sync>);
}

pub struct MiddlewareBuilder {
    middlewares: Vec<Box<Middleware + Send + Sync>>,
    handler: Option<Box<Handler + Send + Sync>>
}

impl MiddlewareBuilder {
    pub fn new<H: Handler>(handler: H) -> MiddlewareBuilder {
        MiddlewareBuilder {
            middlewares: vec!(),
            handler: Some(box handler as Box<Handler + Send + Sync>)
        }
    }

    pub fn add<M: Middleware>(&mut self, middleware: M) {
        self.middlewares.push(box middleware as Box<Middleware + Send + Sync>);
    }

    pub fn around<M: AroundMiddleware>(&mut self, mut middleware: M) {
        let handler = self.handler.take().unwrap();
        middleware.with_handler(handler);
        self.handler = Some(box middleware as Box<Handler + Send + Sync>);
    }
}

impl Handler for MiddlewareBuilder {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Show + 'static>> {
        let mut error = None;

        for (i, middleware) in self.middlewares.iter().enumerate() {
            match middleware.before(req) {
                Ok(_) => (),
                Err(err) => {
                    error = Some((err, i));
                    break;
                }
            }
        }

        match error {
            Some((err, i)) => {
                let middlewares = self.middlewares.slice_to(i);
                run_afters(middlewares, req, Err(err))
            },
            None => {
                let res = { self.handler.as_ref().unwrap().call(req) };
                let middlewares = self.middlewares.as_slice();

                run_afters(middlewares, req, res)
            }
        }
    }
}

fn run_afters(middleware: &[Box<Middleware>],
                  req: &mut Request,
                  res: Result<Response, Box<Show + 'static>>)
                  -> Result<Response, Box<Show + 'static>>
{
    middleware.iter().rev().fold(res, |res, m| m.after(req, res))
}

#[cfg(test)]
mod tests {
    extern crate semver;

    use {MiddlewareBuilder, Middleware, AroundMiddleware};

    use std::io::net::ip::IpAddr;
    use std::io::MemReader;
    use std::fmt;
    use std::fmt::{Show, Formatter};
    use std::collections::HashMap;

    use conduit;
    use conduit::{Request, Response, Host, Headers, Method, Scheme, Extensions};
    use conduit::{Handler, TypeMap};

    struct RequestSentinel {
        path: String,
        extensions: TypeMap,
        method: Method
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: TypeMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    struct MyMiddleware;

    impl Middleware for MyMiddleware {
        fn before<'a>(&self, req: &'a mut Request) -> Result<(), Box<Show + 'static>> {
            req.mut_extensions().insert("hello".to_string());
            Ok(())
        }
    }

    struct ErrorRecovery;

    impl Middleware for ErrorRecovery {
        fn after(&self, _: &mut Request, res: Result<Response, Box<Show + 'static>>)
                     -> Result<Response, Box<Show + 'static>>
        {
            res.or_else(|e| {
                Ok(Response {
                    status: (500, "Internal Server Error"),
                    headers: HashMap::new(),
                    body: box MemReader::new(show(e).to_string().into_bytes())
                })
            })
        }
    }

    struct ProducesError;

    impl Middleware for ProducesError {
        fn before(&self, _: &mut Request) -> Result<(), Box<Show + 'static>> {
            Err(box "Nope".to_string() as Box<Show + 'static>)
        }
    }

    struct NotReached;

    impl Middleware for NotReached {
        fn after(&self, _: &mut Request, _: Result<Response, Box<Show + 'static>>)
                     -> Result<Response, Box<Show + 'static>>
        {
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(vec!())
            })
        }
    }

    struct MyAroundMiddleware {
        handler: Option<Box<Handler + Send + Sync>>
    }

    impl MyAroundMiddleware {
        fn new() -> MyAroundMiddleware {
            MyAroundMiddleware { handler: None }
        }
    }

    impl Middleware for MyAroundMiddleware {}

    impl AroundMiddleware for MyAroundMiddleware {
        fn with_handler(&mut self, handler: Box<Handler + Send + Sync>) {
            self.handler = Some(handler)
        }
    }

    impl Handler for MyAroundMiddleware {
        fn call(&self, req: &mut Request) -> Result<Response, Box<Show + 'static>> {
            req.mut_extensions().insert("hello".to_string());
            self.handler.as_ref().unwrap().call(req)
        }
    }

    struct Shower<'a> {
        inner: &'a Show + 'a
    }

    impl<'a> Show for Shower<'a> {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
            self.inner.fmt(f)
        }
    }

    fn show<'a>(s: &'a Show) -> Shower<'a> {
        Shower { inner: s }
    }

    fn get_extension<'a, T: 'static>(req: &'a Request) -> &'a T {
        req.extensions().find::<T>().unwrap()
    }

    fn response(string: String) -> Response {
        Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(string.into_bytes())
        }
    }

    fn handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req);
        Ok(response(hello.clone()))
    }

    fn error_handler(_: &mut Request) -> Result<Response, String> {
        Err("Error in handler".to_string())
    }

    fn middle_handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req);
        let middle = get_extension::<String>(req);

        Ok(response(format!("{} {}", hello, middle)))
    }

    #[test]
    fn test_simple_middleware() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(MyMiddleware);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_string().ok().expect("No body"), "hello".to_string());
    }

    #[test]
    fn test_error_recovery() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(ErrorRecovery);
        builder.add(ProducesError);
        // the error bubbles up from ProducesError and shouldn't reach here
        builder.add(NotReached);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
    }

    #[test]
    fn test_error_recovery_in_handlers() {
        let mut builder = MiddlewareBuilder::new(error_handler);
        builder.add(ErrorRecovery);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
        assert_eq!(res.body.read_to_string().ok().expect("No body"), "Error in handler".to_string());
    }

    #[test]
    fn test_around_middleware() {
        let mut builder = MiddlewareBuilder::new(middle_handler);
        builder.add(MyMiddleware);
        builder.around(MyAroundMiddleware::new());

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_string().ok().expect("No body"), "hello hello".to_string());
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "serde-serialization", feature(custom_derive, plugin))]
#![cfg_attr(feature = "serde-serialization", plugin(serde_macros))]

//! # Configuring your dependency
//! `toml-config` can be configured to use `rustc_serialize` or `serde`
//!
//! ### Using `toml-config` with `rustc_serialize`
//! By default `toml-config` uses `rustc_serialize`, so just add the dependency in Cargo.toml normally:
//!
//! ```toml
//! [dependencies]
//! toml-config = "0.2"
//! ```
//! ### Using `toml-config` with `serde`
//! To use toml-config with `serde`, opt out from the default features and enable the `serde-serialization`
//! feature:
//!
//! ```toml
//! [dependencies.toml-config]
//! version = "0.2"
//! default-features = false
//! features = ["serde-serialization"]
//! ```

#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
#[cfg(feature = "serde-serialization")] extern crate serde;

#[macro_use] extern crate log;

extern crate toml;

#[cfg(feature = "rustc-serialize")] use rustc_serialize::{Encodable, Decodable};
#[cfg(feature = "serde-serialization")] use serde::{Serialize, Deserialize};

use std::io::Read;
use std::fs::File;
use std::path::Path;

/// Implements helper functions for loading TOML files into a structure
///
/// # Examples
/// To load a file into a Config struct, use `ConfigFactory`.
///
/// Either `rustc_serialize` or `serde` can be used for serialization.
///
/// ### Example using rustc_serialize
/// ```no_run
/// # #[cfg(feature = "rustc-serialize")]
/// extern crate rustc_serialize;
/// extern crate toml_config;
///
/// # #[cfg(feature = "rustc-serialize")]
/// # fn main() {
/// use rustc_serialize::{Encodable, Decodable};
/// use std::path::Path;
/// use toml_config::ConfigFactory;
///
/// #[derive(RustcEncodable, RustcDecodable)]
/// struct Config  {
///     nested: NestedConfig
/// }
///
/// // Defaults will be used for missing/invalid configurations in the TOML config file
/// impl Default for Config {
///     fn default() -> Config {
///         Config {
///             nested: NestedConfig::default()
///         }
///     }
/// }
///
/// #[derive(RustcEncodable, RustcDecodable)]
/// struct NestedConfig  {
///     value: String,
///     values: Vec<u16>
/// }
///
/// impl Default for NestedConfig {
///     fn default() -> NestedConfig {
///         NestedConfig {
///             value: "default".to_owned(),
///             values: vec![0, 0, 0]
///         }
///     }
/// }
///
/// /* config.toml:
///  * [nested]
///  * value = "test"
///  * values = [1, 2, 3]
///  */
///
/// let config: Config = ConfigFactory::load(Path::new("config.toml"));
/// assert_eq!(config.nested.value, "test");
/// assert_eq!(config.nested.values, vec![1, 2, 3]);
/// # }
/// # #[cfg(feature = "serde-serialization")] fn main() { }
/// ```
/// ## Example using serde
/// ```no_run
/// # #![cfg_attr(feature = "serde-serialization", feature(custom_derive, plugin))]
/// # #![cfg_attr(feature = "serde-serialization", plugin(serde_macros))]
/// # #[cfg(feature = "serde-serialization")]
/// extern crate serde;
/// extern crate toml_config;
///
/// # #[cfg(feature = "serde-serialization")]
/// # fn main() {
/// use serde::{Serialize, Deserialize};
/// use std::path::Path;
/// use toml_config::ConfigFactory;
///
/// #[derive(Serialize, Deserialize)]
/// struct Config  {
///     nested: NestedConfig
/// }
///
/// // Defaults will be used for missing/invalid configurations in the TOML config file
/// impl Default for Config {
///     fn default() -> Config {
///         Config {
///             nested: NestedConfig::default()
///         }
///     }
/// }
///
/// #[derive(Serialize, Deserialize)]
/// struct NestedConfig  {
///     value: String,
///     values: Vec<u16>
/// }
///
/// impl Default for NestedConfig {
///     fn default() -> NestedConfig {
///         NestedConfig {
///             value: "default".to_owned(),
///             values: vec![0, 0, 0]
///         }
///     }
/// }
///
/// /* config.toml:
///  * [nested]
///  * value = "test"
///  * values = [1, 2, 3]
///  */
///
/// let config: Config = ConfigFactory::load(Path::new("config.toml"));
/// assert_eq!(config.nested.value, "test");
/// assert_eq!(config.nested.values, vec![1, 2, 3]);
/// # }
/// # #[cfg(feature = "rustc-serialize")] fn main() { }
/// ```
pub struct ConfigFactory;

impl ConfigFactory {
    /// Loads a TOML file and decodes it into a target structure, using default values
    /// for missing or invalid file configurations
    #[cfg(feature = "rustc-serialize")]
    pub fn load<T>(path: &Path) -> T where T: Encodable + Decodable + Default {
        match ConfigFactory::parse_toml_file(path) {
            Some(toml_table) => {
                let default_table = toml::encode(&T::default()).as_table().unwrap().clone();
                let table_with_overrides = ConfigFactory::apply_overrides(default_table, toml_table);
                toml::decode(toml::Value::Table(table_with_overrides)).unwrap()
            },
            None => T::default()
        }
    }

    /// Loads a TOML file and decodes it into a target structure, using default values
    /// for missing or invalid file configurations
    #[cfg(feature = "serde-serialization")]
    pub fn load<T>(path: &Path) -> T where T: Serialize + Deserialize + Default {
        match ConfigFactory::parse_toml_file(path) {
            Some(toml_table) => {
                let default_table = toml::encode(&T::default()).as_table().unwrap().clone();
                let table_with_overrides = ConfigFactory::apply_overrides(default_table, toml_table);
                toml::decode(toml::Value::Table(table_with_overrides)).unwrap()
            },
            None => T::default()
        }
    }

    fn parse_toml_file(path: &Path) -> Option<toml::Table> {
        let mut toml_config = String::new();

        let mut file = match File::open(path) {
            Ok(file) => file,
            Err(_)  => {

                warn!("Config file not found: {}, using defaults..", path.display());
                return None;
            }
        };

        file.read_to_string(&mut toml_config)
            .unwrap_or_else(|err| panic!("Unable to read config file: {}", err));

        let mut parser = toml::Parser::new(&toml_config);
        let toml_table = parser.parse();

        if toml_table.is_none() {
            for err in &parser.errors {
                let (line, col) = parser.to_linecol(err.lo);
                error!("Parsing of {} failed [{}:{}] - {}", path.display(), line + 1, col + 1, err.desc);
            }
            error!("Unable to parse config file: {}, using defaults..", path.display());
            return None;
        }

        toml_table
    }

    fn apply_overrides(defaults: toml::Table, overrides: toml::Table) -> toml::Table {
        let mut merged = defaults.clone();
        for (k, v) in overrides.into_iter() {
            match defaults.get(&k) {
                Some(default_value) =>
                    if v.type_str() == default_value.type_str() {
                        match v {
                            toml::Value::Table(overrides_table) => {
                                let defaults_table = default_value.as_table().unwrap().clone();
                                let merged_table = ConfigFactory::apply_overrides(defaults_table, overrides_table);
                                merged.insert(k, toml::Value::Table(merged_table))
                            },
                            any => merged.insert(k, any)
                        };
                    } else {
                        warn!("Wrong type for config: {}. Expected: {}, found: {}, using default value..",
                            k, default_value.type_str(), v.type_str());
                    },
                None => {
                    merged.insert(k, v);
                }
            }
        }
        merged
    }
}

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

    extern crate tempfile;
    use std::io::Write;

    macro_rules! tempfile {
        ($content:expr) => {
            {
                let mut f = tempfile::NamedTempFile::new().unwrap();
                f.write_all($content.as_bytes()).unwrap();
                f.flush().unwrap();
                f
            }
        }
    }

    #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
    #[cfg_attr(feature = "serde-serialization", derive(Serialize, Deserialize))]
    pub struct Config  {
        pub nested: NestedConfig,
        pub optional: Option<String>
    }

    impl Default for Config {
        fn default() -> Config {
            Config {
                nested: NestedConfig::default(),
                optional: None
            }
        }
    }

    #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
    #[cfg_attr(feature = "serde-serialization", derive(Serialize, Deserialize))]
    pub struct NestedConfig  {
        pub value: String,
        pub values: Vec<u16>
    }

    impl Default for NestedConfig {
        fn default() -> NestedConfig {
            NestedConfig {
                value: "default".to_owned(),
                values: vec![0, 0, 0]
            }
        }
    }

    #[test]
    fn it_should_parse_and_decode_a_valid_toml_file() {
        let toml_file = tempfile!(r#"
            optional = "override"
            [nested]
            value = "test"
            values = [1, 2, 3]
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![1, 2, 3]);
        assert_eq!(config.optional, Some("override".to_owned()));
    }

    #[test]
    fn it_should_use_the_default_for_missing_config() {
        let toml_file = tempfile!("");
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "default");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }

    #[test]
    fn it_should_use_the_default_values_for_missing_config_values() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test"
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }

    #[test]
    fn it_should_return_the_default_config_value_for_misconfigured_properties() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test"
            values = "wrong-type"
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }

    #[test]
    fn it_should_ignore_unexpected_config() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test"
            values = [1, 2, 3]
            unexpected = "ignore-me"
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![1, 2, 3]);
    }

    #[test]
    fn it_should_return_the_default_config_when_parsing_fails() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test
            values = [1, 2, 3]
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "default");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }
}
<commit_msg>useless newline<commit_after>#![cfg_attr(feature = "serde-serialization", feature(custom_derive, plugin))]
#![cfg_attr(feature = "serde-serialization", plugin(serde_macros))]

//! # Configuring your dependency
//! `toml-config` can be configured to use `rustc_serialize` or `serde`
//!
//! ### Using `toml-config` with `rustc_serialize`
//! By default `toml-config` uses `rustc_serialize`, so just add the dependency in Cargo.toml normally:
//!
//! ```toml
//! [dependencies]
//! toml-config = "0.2"
//! ```
//! ### Using `toml-config` with `serde`
//! To use toml-config with `serde`, opt out from the default features and enable the `serde-serialization`
//! feature:
//!
//! ```toml
//! [dependencies.toml-config]
//! version = "0.2"
//! default-features = false
//! features = ["serde-serialization"]
//! ```

#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
#[cfg(feature = "serde-serialization")] extern crate serde;

#[macro_use] extern crate log;

extern crate toml;

#[cfg(feature = "rustc-serialize")] use rustc_serialize::{Encodable, Decodable};
#[cfg(feature = "serde-serialization")] use serde::{Serialize, Deserialize};

use std::io::Read;
use std::fs::File;
use std::path::Path;

/// Implements helper functions for loading TOML files into a structure
///
/// # Examples
/// To load a file into a Config struct, use `ConfigFactory`.
///
/// Either `rustc_serialize` or `serde` can be used for serialization.
///
/// ### Example using rustc_serialize
/// ```no_run
/// # #[cfg(feature = "rustc-serialize")]
/// extern crate rustc_serialize;
/// extern crate toml_config;
///
/// # #[cfg(feature = "rustc-serialize")]
/// # fn main() {
/// use rustc_serialize::{Encodable, Decodable};
/// use std::path::Path;
/// use toml_config::ConfigFactory;
///
/// #[derive(RustcEncodable, RustcDecodable)]
/// struct Config  {
///     nested: NestedConfig
/// }
///
/// // Defaults will be used for missing/invalid configurations in the TOML config file
/// impl Default for Config {
///     fn default() -> Config {
///         Config {
///             nested: NestedConfig::default()
///         }
///     }
/// }
///
/// #[derive(RustcEncodable, RustcDecodable)]
/// struct NestedConfig  {
///     value: String,
///     values: Vec<u16>
/// }
///
/// impl Default for NestedConfig {
///     fn default() -> NestedConfig {
///         NestedConfig {
///             value: "default".to_owned(),
///             values: vec![0, 0, 0]
///         }
///     }
/// }
///
/// /* config.toml:
///  * [nested]
///  * value = "test"
///  * values = [1, 2, 3]
///  */
///
/// let config: Config = ConfigFactory::load(Path::new("config.toml"));
/// assert_eq!(config.nested.value, "test");
/// assert_eq!(config.nested.values, vec![1, 2, 3]);
/// # }
/// # #[cfg(feature = "serde-serialization")] fn main() { }
/// ```
/// ## Example using serde
/// ```no_run
/// # #![cfg_attr(feature = "serde-serialization", feature(custom_derive, plugin))]
/// # #![cfg_attr(feature = "serde-serialization", plugin(serde_macros))]
/// # #[cfg(feature = "serde-serialization")]
/// extern crate serde;
/// extern crate toml_config;
///
/// # #[cfg(feature = "serde-serialization")]
/// # fn main() {
/// use serde::{Serialize, Deserialize};
/// use std::path::Path;
/// use toml_config::ConfigFactory;
///
/// #[derive(Serialize, Deserialize)]
/// struct Config  {
///     nested: NestedConfig
/// }
///
/// // Defaults will be used for missing/invalid configurations in the TOML config file
/// impl Default for Config {
///     fn default() -> Config {
///         Config {
///             nested: NestedConfig::default()
///         }
///     }
/// }
///
/// #[derive(Serialize, Deserialize)]
/// struct NestedConfig  {
///     value: String,
///     values: Vec<u16>
/// }
///
/// impl Default for NestedConfig {
///     fn default() -> NestedConfig {
///         NestedConfig {
///             value: "default".to_owned(),
///             values: vec![0, 0, 0]
///         }
///     }
/// }
///
/// /* config.toml:
///  * [nested]
///  * value = "test"
///  * values = [1, 2, 3]
///  */
///
/// let config: Config = ConfigFactory::load(Path::new("config.toml"));
/// assert_eq!(config.nested.value, "test");
/// assert_eq!(config.nested.values, vec![1, 2, 3]);
/// # }
/// # #[cfg(feature = "rustc-serialize")] fn main() { }
/// ```
pub struct ConfigFactory;

impl ConfigFactory {
    /// Loads a TOML file and decodes it into a target structure, using default values
    /// for missing or invalid file configurations
    #[cfg(feature = "rustc-serialize")]
    pub fn load<T>(path: &Path) -> T where T: Encodable + Decodable + Default {
        match ConfigFactory::parse_toml_file(path) {
            Some(toml_table) => {
                let default_table = toml::encode(&T::default()).as_table().unwrap().clone();
                let table_with_overrides = ConfigFactory::apply_overrides(default_table, toml_table);
                toml::decode(toml::Value::Table(table_with_overrides)).unwrap()
            },
            None => T::default()
        }
    }

    /// Loads a TOML file and decodes it into a target structure, using default values
    /// for missing or invalid file configurations
    #[cfg(feature = "serde-serialization")]
    pub fn load<T>(path: &Path) -> T where T: Serialize + Deserialize + Default {
        match ConfigFactory::parse_toml_file(path) {
            Some(toml_table) => {
                let default_table = toml::encode(&T::default()).as_table().unwrap().clone();
                let table_with_overrides = ConfigFactory::apply_overrides(default_table, toml_table);
                toml::decode(toml::Value::Table(table_with_overrides)).unwrap()
            },
            None => T::default()
        }
    }

    fn parse_toml_file(path: &Path) -> Option<toml::Table> {
        let mut toml_config = String::new();

        let mut file = match File::open(path) {
            Ok(file) => file,
            Err(_)  => {
                warn!("Config file not found: {}, using defaults..", path.display());
                return None;
            }
        };

        file.read_to_string(&mut toml_config)
            .unwrap_or_else(|err| panic!("Unable to read config file: {}", err));

        let mut parser = toml::Parser::new(&toml_config);
        let toml_table = parser.parse();

        if toml_table.is_none() {
            for err in &parser.errors {
                let (line, col) = parser.to_linecol(err.lo);
                error!("Parsing of {} failed [{}:{}] - {}", path.display(), line + 1, col + 1, err.desc);
            }
            error!("Unable to parse config file: {}, using defaults..", path.display());
            return None;
        }

        toml_table
    }

    fn apply_overrides(defaults: toml::Table, overrides: toml::Table) -> toml::Table {
        let mut merged = defaults.clone();
        for (k, v) in overrides.into_iter() {
            match defaults.get(&k) {
                Some(default_value) =>
                    if v.type_str() == default_value.type_str() {
                        match v {
                            toml::Value::Table(overrides_table) => {
                                let defaults_table = default_value.as_table().unwrap().clone();
                                let merged_table = ConfigFactory::apply_overrides(defaults_table, overrides_table);
                                merged.insert(k, toml::Value::Table(merged_table))
                            },
                            any => merged.insert(k, any)
                        };
                    } else {
                        warn!("Wrong type for config: {}. Expected: {}, found: {}, using default value..",
                            k, default_value.type_str(), v.type_str());
                    },
                None => {
                    merged.insert(k, v);
                }
            }
        }
        merged
    }
}

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

    extern crate tempfile;
    use std::io::Write;

    macro_rules! tempfile {
        ($content:expr) => {
            {
                let mut f = tempfile::NamedTempFile::new().unwrap();
                f.write_all($content.as_bytes()).unwrap();
                f.flush().unwrap();
                f
            }
        }
    }

    #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
    #[cfg_attr(feature = "serde-serialization", derive(Serialize, Deserialize))]
    pub struct Config  {
        pub nested: NestedConfig,
        pub optional: Option<String>
    }

    impl Default for Config {
        fn default() -> Config {
            Config {
                nested: NestedConfig::default(),
                optional: None
            }
        }
    }

    #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
    #[cfg_attr(feature = "serde-serialization", derive(Serialize, Deserialize))]
    pub struct NestedConfig  {
        pub value: String,
        pub values: Vec<u16>
    }

    impl Default for NestedConfig {
        fn default() -> NestedConfig {
            NestedConfig {
                value: "default".to_owned(),
                values: vec![0, 0, 0]
            }
        }
    }

    #[test]
    fn it_should_parse_and_decode_a_valid_toml_file() {
        let toml_file = tempfile!(r#"
            optional = "override"
            [nested]
            value = "test"
            values = [1, 2, 3]
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![1, 2, 3]);
        assert_eq!(config.optional, Some("override".to_owned()));
    }

    #[test]
    fn it_should_use_the_default_for_missing_config() {
        let toml_file = tempfile!("");
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "default");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }

    #[test]
    fn it_should_use_the_default_values_for_missing_config_values() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test"
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }

    #[test]
    fn it_should_return_the_default_config_value_for_misconfigured_properties() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test"
            values = "wrong-type"
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }

    #[test]
    fn it_should_ignore_unexpected_config() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test"
            values = [1, 2, 3]
            unexpected = "ignore-me"
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![1, 2, 3]);
    }

    #[test]
    fn it_should_return_the_default_config_when_parsing_fails() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test
            values = [1, 2, 3]
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "default");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(phf_macros)]

extern crate phf;

mod tld;

pub use tld::TLD;

pub fn exist(s: &str) -> bool {
    TLD.contains_key(s)
}

#[test]
fn test_tld() {
    use tld::TLD;
    assert!(TLD.get("aaa").is_some());
    assert!(TLD.get("#33dawaaa").is_none());
    assert!(TLD.get("aco").is_some());
    assert!(TLD.get("uk").is_some());
    assert!(TLD.get("ye").is_some());
    assert!(TLD.get("com").is_some());
    assert!(TLD.get("de").is_some());
    assert!(TLD.get("fr").is_some());
    assert!(TLD.get("ag").is_some());
    assert!(TLD.get("ru").is_some());
    assert!(TLD.get("nl").is_some());
    assert!(TLD.get("lt").is_some());
    assert!(TLD.get("amex").is_some());
    assert!(TLD.get("zw").is_some());
}

#[test]
fn test_exist() {
    assert!(exist("fr"));
    assert!(exist("de"));
    assert!(exist("zw"));
    assert!(!exist("a9292zw"));
}
<commit_msg>Document exist function<commit_after>#![feature(plugin)]
#![plugin(phf_macros)]

extern crate phf;

mod tld;

pub use tld::TLD;

/// Convenience function to check if given TLD exists in
/// IANA official TLD list.
///
/// https://data.iana.org/TLD/tlds-alpha-by-domain.txt
pub fn exist(s: &str) -> bool {
    TLD.contains_key(s)
}

#[test]
fn test_tld() {
    use tld::TLD;
    assert!(TLD.get("aaa").is_some());
    assert!(TLD.get("#33dawaaa").is_none());
    assert!(TLD.get("aco").is_some());
    assert!(TLD.get("uk").is_some());
    assert!(TLD.get("ye").is_some());
    assert!(TLD.get("com").is_some());
    assert!(TLD.get("de").is_some());
    assert!(TLD.get("fr").is_some());
    assert!(TLD.get("ag").is_some());
    assert!(TLD.get("ru").is_some());
    assert!(TLD.get("nl").is_some());
    assert!(TLD.get("lt").is_some());
    assert!(TLD.get("amex").is_some());
    assert!(TLD.get("zw").is_some());
}

#[test]
fn test_exist() {
    assert!(exist("fr"));
    assert!(exist("de"));
    assert!(exist("zw"));
    assert!(!exist("a9292zw"));
}
<|endoftext|>


<commit_before>//! Crate `retry` provides utilities for retrying operations that can fail.
//!
//! # Usage
//!
//! Retry an operation using the `retry` function. `retry` accepts an iterator over `Duration`s and
//! a closure that returns a `Result` (or `OperationResult`; see below). The iterator is used to
//! determine how long to wait after each unsuccessful try and how many times to try before giving
//! up and returning `Result::Err`. The closure determines either the final successful value, or
//! an error value, which can either be returned immediately or used to indicate that the
//! operation should be retried.
//!
//! Any type that implements `Iterator<Item = Duration>` can be used to determine retry behavior,
//! though a few useful implementations are provided in the `delay` module, including a fixed delay
//! and exponential back-off.
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! let mut collection = vec![1, 2, 3].into_iter();
//!
//! let result = retry(Fixed::from_millis(100), || {
//!     match collection.next() {
//!         Some(n) if n == 3 => Ok("n is 3!"),
//!         Some(_) => Err("n must be 3!"),
//!         None => Err("n was never 3!"),
//!     }
//! });
//!
//! assert!(result.is_ok());
//! ```
//!
//! The `Iterator` API can be used to limit or modify the delay strategy. For example, to limit the
//! number of retries to 1:
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! let mut collection = vec![1, 2, 3].into_iter();
//!
//! let result = retry(Fixed::from_millis(100).take(1), || {
//!     match collection.next() {
//!         Some(n) if n == 3 => Ok("n is 3!"),
//!         Some(_) => Err("n must be 3!"),
//!         None => Err("n was never 3!"),
//!     }
//! });
//!
//! assert!(result.is_err());
//! ```
//!
//! To apply random jitter to any delay strategy, the `jitter` function can be used in combination
//! with the `Iterator` API:
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::{Exponential, jitter};
//! let mut collection = vec![1, 2, 3].into_iter();
//!
//! let result = retry(Exponential::from_millis(10).map(jitter).take(3), || {
//!     match collection.next() {
//!         Some(n) if n == 3 => Ok("n is 3!"),
//!         Some(_) => Err("n must be 3!"),
//!         None => Err("n was never 3!"),
//!     }
//! });
//!
//! assert!(result.is_ok());
//! ```
//!
//! To deal with fatal errors, return `retry::OperationResult`, which is like std's `Result`, but
//! with a third case to distinguish between errors that should cause a retry and errors that
//! should immediately return, halting retry behavior. (Internally, `OperationResult` is always
//! used, and closures passed to `retry` that return plain `Result` are converted into
//! `OperationResult`.)
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! use retry::OperationResult;
//! let mut collection = vec![1, 2].into_iter();
//! let value = retry(Fixed::from_millis(1), || {
//!     match collection.next() {
//!         Some(n) if n == 2 => OperationResult::Ok(n),
//!         Some(_) => OperationResult::Retry("not 2"),
//!         None => OperationResult::Err("not found"),
//!     }
//! }).unwrap();
//!
//! assert_eq!(value, 2);
//! ```

#![deny(missing_debug_implementations, missing_docs, warnings)]

use std::{
    error::Error as StdError,
    fmt::{Display, Error as FmtError, Formatter},
    thread::sleep,
    time::Duration,
};

pub mod delay;
mod opresult;

#[doc(inline)]
pub use opresult::OperationResult;

/// Retry the given operation synchronously until it succeeds, or until the given `Duration`
/// iterator ends.
pub fn retry<I, O, R, E, OR>(iterable: I, mut operation: O) -> Result<R, Error<E>>
where
    I: IntoIterator<Item = Duration>,
    O: FnMut() -> OR,
    OR: Into<OperationResult<R, E>>,
{
    let mut iterator = iterable.into_iter();
    let mut current_try = 1;
    let mut total_delay = Duration::default();

    loop {
        match operation().into() {
            OperationResult::Ok(value) => return Ok(value),
            OperationResult::Retry(error) => {
                if let Some(delay) = iterator.next() {
                    sleep(delay);
                    current_try += 1;
                    total_delay += delay;
                } else {
                    return Err(Error::Operation {
                        error,
                        total_delay,
                        tries: current_try,
                    });
                }
            }
            OperationResult::Err(error) => {
                return Err(Error::Operation {
                    error,
                    total_delay,
                    tries: current_try,
                });
            }
        }
    }
}

/// An error with a retryable operation.
#[derive(Debug, PartialEq, Eq)]
pub enum Error<E> {
    /// The operation's last error, plus the number of times the operation was tried and the
    /// duration spent waiting between tries.
    Operation {
        /// The error returned by the operation on the last try.
        error: E,
        /// The duration spent waiting between retries of the operation.
        ///
        /// Note that this does not include the time spent running the operation itself.
        total_delay: Duration,
        /// The total number of times the operation was tried.
        tries: u64,
    },
    /// Something went wrong in the internal logic.
    Internal(String),
}

impl<E> Display for Error<E>
where
    E: StdError,
{
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
        write!(formatter, "{}", self.description())
    }
}

impl<E> StdError for Error<E>
where
    E: StdError,
{
    fn description(&self) -> &str {
        match *self {
            Error::Operation { ref error, .. } => error.description(),
            Error::Internal(ref description) => description,
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Error::Operation { ref error, .. } => Some(error),
            Error::Internal(_) => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::time::Duration;

    use super::delay::{Exponential, Fixed, NoDelay, Range};
    use super::opresult::OperationResult;
    use super::{retry, Error};

    #[test]
    fn succeeds_with_infinite_retries() {
        let mut collection = vec![1, 2, 3, 4, 5].into_iter();

        let value = retry(NoDelay, || match collection.next() {
            Some(n) if n == 5 => Ok(n),
            Some(_) => Err("not 5"),
            None => Err("not 5"),
        })
        .unwrap();

        assert_eq!(value, 5);
    }

    #[test]
    fn succeeds_with_maximum_retries() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(NoDelay.take(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        })
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fails_after_last_try() {
        let mut collection = vec![1].into_iter();

        let res = retry(NoDelay.take(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        });

        assert_eq!(
            res,
            Err(Error::Operation {
                error: "not 2",
                tries: 2,
                total_delay: Duration::from_millis(0)
            })
        );
    }

    #[test]
    fn fatal_errors() {
        let mut collection = vec![1].into_iter();

        let res = retry(NoDelay.take(2), || match collection.next() {
            Some(n) if n == 2 => OperationResult::Ok(n),
            Some(_) => OperationResult::Err("no retry"),
            None => OperationResult::Err("not 2"),
        });

        assert_eq!(
            res,
            Err(Error::Operation {
                error: "no retry",
                tries: 1,
                total_delay: Duration::from_millis(0)
            })
        );
    }

    #[test]
    fn succeeds_with_fixed_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Fixed::from_millis(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        })
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fixed_delay_from_duration() {
        assert_eq!(
            Fixed::from_millis(1_000).next(),
            Fixed::from(Duration::from_secs(1)).next(),
        );
    }

    #[test]
    fn succeeds_with_exponential_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Exponential::from_millis(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        })
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn succeeds_with_ranged_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Range::from_millis_exclusive(1, 10), || {
            match collection.next() {
                Some(n) if n == 2 => Ok(n),
                Some(_) => Err("not 2"),
                None => Err("not 2"),
            }
        })
        .unwrap();

        assert_eq!(value, 2);
    }
}
<commit_msg>`#![deny(warning)]` considered harmful<commit_after>//! Crate `retry` provides utilities for retrying operations that can fail.
//!
//! # Usage
//!
//! Retry an operation using the `retry` function. `retry` accepts an iterator over `Duration`s and
//! a closure that returns a `Result` (or `OperationResult`; see below). The iterator is used to
//! determine how long to wait after each unsuccessful try and how many times to try before giving
//! up and returning `Result::Err`. The closure determines either the final successful value, or
//! an error value, which can either be returned immediately or used to indicate that the
//! operation should be retried.
//!
//! Any type that implements `Iterator<Item = Duration>` can be used to determine retry behavior,
//! though a few useful implementations are provided in the `delay` module, including a fixed delay
//! and exponential back-off.
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! let mut collection = vec![1, 2, 3].into_iter();
//!
//! let result = retry(Fixed::from_millis(100), || {
//!     match collection.next() {
//!         Some(n) if n == 3 => Ok("n is 3!"),
//!         Some(_) => Err("n must be 3!"),
//!         None => Err("n was never 3!"),
//!     }
//! });
//!
//! assert!(result.is_ok());
//! ```
//!
//! The `Iterator` API can be used to limit or modify the delay strategy. For example, to limit the
//! number of retries to 1:
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! let mut collection = vec![1, 2, 3].into_iter();
//!
//! let result = retry(Fixed::from_millis(100).take(1), || {
//!     match collection.next() {
//!         Some(n) if n == 3 => Ok("n is 3!"),
//!         Some(_) => Err("n must be 3!"),
//!         None => Err("n was never 3!"),
//!     }
//! });
//!
//! assert!(result.is_err());
//! ```
//!
//! To apply random jitter to any delay strategy, the `jitter` function can be used in combination
//! with the `Iterator` API:
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::{Exponential, jitter};
//! let mut collection = vec![1, 2, 3].into_iter();
//!
//! let result = retry(Exponential::from_millis(10).map(jitter).take(3), || {
//!     match collection.next() {
//!         Some(n) if n == 3 => Ok("n is 3!"),
//!         Some(_) => Err("n must be 3!"),
//!         None => Err("n was never 3!"),
//!     }
//! });
//!
//! assert!(result.is_ok());
//! ```
//!
//! To deal with fatal errors, return `retry::OperationResult`, which is like std's `Result`, but
//! with a third case to distinguish between errors that should cause a retry and errors that
//! should immediately return, halting retry behavior. (Internally, `OperationResult` is always
//! used, and closures passed to `retry` that return plain `Result` are converted into
//! `OperationResult`.)
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! use retry::OperationResult;
//! let mut collection = vec![1, 2].into_iter();
//! let value = retry(Fixed::from_millis(1), || {
//!     match collection.next() {
//!         Some(n) if n == 2 => OperationResult::Ok(n),
//!         Some(_) => OperationResult::Retry("not 2"),
//!         None => OperationResult::Err("not found"),
//!     }
//! }).unwrap();
//!
//! assert_eq!(value, 2);
//! ```

#![deny(missing_debug_implementations, missing_docs)]

use std::{
    error::Error as StdError,
    fmt::{Display, Error as FmtError, Formatter},
    thread::sleep,
    time::Duration,
};

pub mod delay;
mod opresult;

#[doc(inline)]
pub use opresult::OperationResult;

/// Retry the given operation synchronously until it succeeds, or until the given `Duration`
/// iterator ends.
pub fn retry<I, O, R, E, OR>(iterable: I, mut operation: O) -> Result<R, Error<E>>
where
    I: IntoIterator<Item = Duration>,
    O: FnMut() -> OR,
    OR: Into<OperationResult<R, E>>,
{
    let mut iterator = iterable.into_iter();
    let mut current_try = 1;
    let mut total_delay = Duration::default();

    loop {
        match operation().into() {
            OperationResult::Ok(value) => return Ok(value),
            OperationResult::Retry(error) => {
                if let Some(delay) = iterator.next() {
                    sleep(delay);
                    current_try += 1;
                    total_delay += delay;
                } else {
                    return Err(Error::Operation {
                        error,
                        total_delay,
                        tries: current_try,
                    });
                }
            }
            OperationResult::Err(error) => {
                return Err(Error::Operation {
                    error,
                    total_delay,
                    tries: current_try,
                });
            }
        }
    }
}

/// An error with a retryable operation.
#[derive(Debug, PartialEq, Eq)]
pub enum Error<E> {
    /// The operation's last error, plus the number of times the operation was tried and the
    /// duration spent waiting between tries.
    Operation {
        /// The error returned by the operation on the last try.
        error: E,
        /// The duration spent waiting between retries of the operation.
        ///
        /// Note that this does not include the time spent running the operation itself.
        total_delay: Duration,
        /// The total number of times the operation was tried.
        tries: u64,
    },
    /// Something went wrong in the internal logic.
    Internal(String),
}

impl<E> Display for Error<E>
where
    E: StdError,
{
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
        write!(formatter, "{}", self.description())
    }
}

impl<E> StdError for Error<E>
where
    E: StdError,
{
    fn description(&self) -> &str {
        match *self {
            Error::Operation { ref error, .. } => error.description(),
            Error::Internal(ref description) => description,
        }
    }

    fn cause(&self) -> Option<&dyn StdError> {
        match *self {
            Error::Operation { ref error, .. } => Some(error),
            Error::Internal(_) => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::time::Duration;

    use super::delay::{Exponential, Fixed, NoDelay, Range};
    use super::opresult::OperationResult;
    use super::{retry, Error};

    #[test]
    fn succeeds_with_infinite_retries() {
        let mut collection = vec![1, 2, 3, 4, 5].into_iter();

        let value = retry(NoDelay, || match collection.next() {
            Some(n) if n == 5 => Ok(n),
            Some(_) => Err("not 5"),
            None => Err("not 5"),
        })
        .unwrap();

        assert_eq!(value, 5);
    }

    #[test]
    fn succeeds_with_maximum_retries() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(NoDelay.take(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        })
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fails_after_last_try() {
        let mut collection = vec![1].into_iter();

        let res = retry(NoDelay.take(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        });

        assert_eq!(
            res,
            Err(Error::Operation {
                error: "not 2",
                tries: 2,
                total_delay: Duration::from_millis(0)
            })
        );
    }

    #[test]
    fn fatal_errors() {
        let mut collection = vec![1].into_iter();

        let res = retry(NoDelay.take(2), || match collection.next() {
            Some(n) if n == 2 => OperationResult::Ok(n),
            Some(_) => OperationResult::Err("no retry"),
            None => OperationResult::Err("not 2"),
        });

        assert_eq!(
            res,
            Err(Error::Operation {
                error: "no retry",
                tries: 1,
                total_delay: Duration::from_millis(0)
            })
        );
    }

    #[test]
    fn succeeds_with_fixed_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Fixed::from_millis(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        })
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fixed_delay_from_duration() {
        assert_eq!(
            Fixed::from_millis(1_000).next(),
            Fixed::from(Duration::from_secs(1)).next(),
        );
    }

    #[test]
    fn succeeds_with_exponential_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Exponential::from_millis(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        })
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn succeeds_with_ranged_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Range::from_millis_exclusive(1, 10), || {
            match collection.next() {
                Some(n) if n == 2 => Ok(n),
                Some(_) => Err("not 2"),
                None => Err("not 2"),
            }
        })
        .unwrap();

        assert_eq!(value, 2);
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::iter::FromIterator;

pub fn puzzle(input: &str) -> u32 {
    0
}

#[derive(Debug, PartialEq)]
pub struct Screen {
    display: Vec<Vec<char>>,
}

impl Screen {
    pub fn new(width: usize, height: usize) -> Screen {
        Screen {
            display: vec![vec!['.'; width]; height],
        }
    }

    pub fn rect(&mut self, rect_width: usize, rect_height: usize) {
        for h in 0..rect_height {
            for w in 0..rect_width {
                self.display[h][w] = '#';
            }
        }
    }

    pub fn rotate_column(&mut self, col_index: usize, how_many: usize) {
        let col: Vec<_> = self.display.iter()
            .map(|row| row[col_index] ).collect();

        for i in 0..self.display.len() {
            let from_index = (i + self.display.len() - how_many) % self.display.len();
            self.display[i][col_index] = col[from_index];
        }
    }

    pub fn rotate_row(&mut self, row_index: usize, how_many: usize) {
        let row = self.display[row_index].clone();

        for i in 0..row.len() {
            let from_index = (i + row.len() - how_many) % row.len();
            self.display[row_index][i] = row[from_index];
        }
    }
}

impl fmt::Display for Screen {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for row in self.display.iter() {
            write!(f, "{}\n", String::from_iter(row.iter().cloned()))?;
        }
        Ok(())
    }
}

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

    #[test]
    fn new_screen(){
        let s = Screen::new(1, 2);
        assert_eq!(s, Screen {
            display: vec![vec!['.'], vec!['.']],
        });
        assert_eq!(s.to_string(), ".\n.\n");
    }

    #[test]
    fn rect_drawing() {
        let mut s = Screen::new(7, 3);
        s.rect(3, 2);
        assert_eq!(s.to_string(), "###....\n###....\n.......\n");
    }

    #[test]
    fn rotate_column() {
        let mut s = Screen::new(7, 3);
        s.rect(3, 2);
        s.rotate_column(1, 1);
        assert_eq!(s.to_string(), "#.#....\n###....\n.#.....\n");
    }

    #[test]
    fn rotate_row() {
        let mut s = Screen::new(7, 3);
        s.rect(3, 2);
        s.rotate_column(1, 1);
        s.rotate_row(0, 4);
        assert_eq!(s.to_string(), "....#.#\n###....\n.#.....\n");
    }
}
<commit_msg>Implement counting lit pixels<commit_after>use std::fmt;
use std::iter::FromIterator;

pub fn puzzle(input: &str) -> u32 {
    0
}

#[derive(Debug, PartialEq)]
pub struct Screen {
    display: Vec<Vec<char>>,
}

impl Screen {
    pub fn new(width: usize, height: usize) -> Screen {
        Screen {
            display: vec![vec!['.'; width]; height],
        }
    }

    pub fn rect(&mut self, rect_width: usize, rect_height: usize) {
        for h in 0..rect_height {
            for w in 0..rect_width {
                self.display[h][w] = '#';
            }
        }
    }

    pub fn rotate_column(&mut self, col_index: usize, how_many: usize) {
        let col: Vec<_> = self.display.iter()
            .map(|row| row[col_index] ).collect();

        for i in 0..self.display.len() {
            let from_index = (i + self.display.len() - how_many) % self.display.len();
            self.display[i][col_index] = col[from_index];
        }
    }

    pub fn rotate_row(&mut self, row_index: usize, how_many: usize) {
        let row = self.display[row_index].clone();

        for i in 0..row.len() {
            let from_index = (i + row.len() - how_many) % row.len();
            self.display[row_index][i] = row[from_index];
        }
    }

    pub fn num_lit_pixels(&self) -> usize {
        self.display.iter().map(|row| {
            row.iter().filter(|&&c| c == '#').count()
        }).sum()
    }
}

impl fmt::Display for Screen {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for row in self.display.iter() {
            write!(f, "{}\n", String::from_iter(row.iter().cloned()))?;
        }
        Ok(())
    }
}

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

    #[test]
    fn new_screen(){
        let s = Screen::new(1, 2);
        assert_eq!(s, Screen {
            display: vec![vec!['.'], vec!['.']],
        });
        assert_eq!(s.to_string(), ".\n.\n");
    }

    #[test]
    fn rect_drawing() {
        let mut s = Screen::new(7, 3);
        s.rect(3, 2);
        assert_eq!(s.to_string(), "###....\n###....\n.......\n");
    }

    #[test]
    fn rotate_column() {
        let mut s = Screen::new(7, 3);
        s.rect(3, 2);
        s.rotate_column(1, 1);
        assert_eq!(s.to_string(), "#.#....\n###....\n.#.....\n");
    }

    #[test]
    fn rotate_row() {
        let mut s = Screen::new(7, 3);
        s.rect(3, 2);
        s.rotate_column(1, 1);
        s.rotate_row(0, 4);
        assert_eq!(s.to_string(), "....#.#\n###....\n.#.....\n");
    }

    #[test]
    fn count_pixels() {
        let mut s = Screen::new(7, 3);
        s.rect(3, 2);
        s.rotate_column(1, 1);
        s.rotate_row(0, 4);
        assert_eq!(s.num_lit_pixels(), 6);
    }
}
<|endoftext|>


<commit_before>#![crate_id = "logger"]
#![license = "MIT"]

//! Request logging middleware for Iron

extern crate debug;
extern crate iron;

use iron::{Ingot, Alloy, Request, Response};
use iron::ingot::{Status, Continue};

#[deriving(Clone)]
pub struct Logger;

impl Logger {
    pub fn new() -> Logger {
        Logger
    }
}

impl<Rq: Request, Rs: Response> Ingot<Rq, Rs> for Logger {
    fn enter(&mut self, _req: &mut Rq, _res: &mut Rs, _alloy: &mut Alloy) -> Status {
        Continue
    }
    fn exit(&mut self, req: &mut Rq, _res: &mut Rs, _al: &mut Alloy) -> Status {
        println!("{:?}", req);
        Continue
    }
}
<commit_msg>(feat) Added clean logging of non-header fields.<commit_after>#![crate_id = "logger"]
#![license = "MIT"]

//! Request logging middleware for Iron

extern crate iron;
extern crate time;

use iron::{Ingot, Alloy, Request, Response};
use iron::ingot::{Status, Continue};

use time::precise_time_ns;

#[deriving(Clone)]
pub struct Logger {
    entry_time: u64
}

impl Logger {
    pub fn new() -> Logger {
        Logger { entry_time: 0u64 }
    }
}

impl<Rq: Request, Rs: Response> Ingot<Rq, Rs> for Logger {
    fn enter(&mut self, _req: &mut Rq, _res: &mut Rs, _alloy: &mut Alloy) -> Status {
        self.entry_time = precise_time_ns();
        Continue
    }
    fn exit(&mut self, req: &mut Rq, res: &mut Rs, _al: &mut Alloy) -> Status {
        let response_time_ms = (precise_time_ns() - self.entry_time) as f64 / 1000000.0;
        println!("Request body: {}\nMethod: {}\nURI: {}\nStatus: {}\nResponse time: {} ms\n",
                 req.body(), req.method(), req.uri(), res.status(), response_time_ms);
        Continue
    }
}
<|endoftext|>


<commit_before>#![crate_name = "love2d"]
#![warn(missing_docs)]

/*!
love2d is a glium port of the [simple](https://crates.io/crates/simple)
crate which is a port of the [Love2D](https://love2d.org/) lua graphics
library. This library was developed as a 2D graphics prototyping library and
is not ment for high-performance.

# Example

```rust,no_run
extern crate love2d;
use love2d::{Window, Event};

fn main() {
	let mut app = Window::new("Window Example", 640, 480);

	'main: loop {
        // Note rust requires this code to be in a closure to please the borrow checker
		{
			let mut frame = app.next_frame();
			frame.clear();

			frame.set_color(1.0, 1.0, 1.0, 1.0);
			frame.draw_rect(0.0, 0.0, 1.0, 1.0);

			frame.finish();
		}

		for ev in app.poll_events() {
			match ev {
				Event::Closed => break 'main,
				_ => (),
			}
		}
	}
}
```

Current renderable objects are:

 * Line (soon to be depricated)
 * Polygon (TrianglFan)
 * Rectangle
 * Circle (really an oval)
 * Image (with cropping)
 * Color (HTML / RGBA)
 * Alpha Blend Transparency

Planned features include:

 - Rotation
 - Text (ttf fonts)
 - Text (char-map)
 - Audio
*/

#[macro_use]
extern crate glium;
extern crate image as img;

pub mod support;
mod events;
mod frame;
mod window;
mod image;

pub use window::Window;
pub use frame::Frame;
pub use events::Event;
pub use image::Image;
pub use image::LoadImageError;
pub use image::ImageParameters;
/// Re-export of `glium::glutin::ElementState`
pub use glium::glutin::ElementState;
/// Re-export of `glium::glutin::VirtualKeyCode`
pub use glium::glutin::VirtualKeyCode;
<commit_msg>Added deny for missing_docs and warnings<commit_after>#![crate_name = "love2d"]
#![deny(missing_docs)]
#![deny(warnings)]

/*!
love2d is a glium port of the [simple](https://crates.io/crates/simple)
crate which is a port of the [Love2D](https://love2d.org/) lua graphics
library. This library was developed as a 2D graphics prototyping library and
is not ment for high-performance.

# Example

```rust,no_run
extern crate love2d;
use love2d::{Window, Event};

fn main() {
	let mut app = Window::new("Window Example", 640, 480);

	'main: loop {
        // Note rust requires this code to be in a closure to please the borrow checker
		{
			let mut frame = app.next_frame();
			frame.clear();

			frame.set_color(1.0, 1.0, 1.0, 1.0);
			frame.draw_rect(0.0, 0.0, 1.0, 1.0);

			frame.finish();
		}

		for ev in app.poll_events() {
			match ev {
				Event::Closed => break 'main,
				_ => (),
			}
		}
	}
}
```

Current renderable objects are:

 * Line (soon to be depricated)
 * Polygon (TrianglFan)
 * Rectangle
 * Circle (really an oval)
 * Image (with cropping)
 * Color (HTML / RGBA)
 * Alpha Blend Transparency

Planned features include:

 - Rotation
 - Text (ttf fonts)
 - Text (char-map)
 - Audio
*/

#[macro_use]
extern crate glium;
extern crate image as img;

pub mod support;
mod events;
mod frame;
mod window;
mod image;

pub use window::Window;
pub use frame::Frame;
pub use events::Event;
pub use image::Image;
pub use image::LoadImageError;
pub use image::ImageParameters;
/// Re-export of `glium::glutin::ElementState`
pub use glium::glutin::ElementState;
/// Re-export of `glium::glutin::VirtualKeyCode`
pub use glium::glutin::VirtualKeyCode;
<|endoftext|>


<commit_before>//! An implementation of [FLAC](https://xiph.org/flac), free lossless audio
//! codec, written in Rust.

#[macro_use]
extern crate nom;

#[macro_use]
mod utility;
pub mod metadata;
pub mod frame;
pub mod subframe;
mod stream;

pub use metadata::{metadata_parser, Metadata};
pub use frame::{frame_parser, Frame};
pub use subframe::{subframe_parser, Subframe};
pub use stream::{stream_parser, Stream};
<commit_msg>Export `Iter` inside of the stream module<commit_after>//! An implementation of [FLAC](https://xiph.org/flac), free lossless audio
//! codec, written in Rust.

#[macro_use]
extern crate nom;

#[macro_use]
mod utility;
pub mod metadata;
pub mod frame;
pub mod subframe;
pub mod stream;

pub use metadata::{metadata_parser, Metadata};
pub use frame::{frame_parser, Frame};
pub use subframe::{subframe_parser, Subframe};
pub use stream::{stream_parser, Stream};
<|endoftext|>


<commit_before>//! Rust bindings to the libcurl C library
//!
//! This crate contains bindings for an HTTP/HTTPS client which is powered by
//! [libcurl], the same library behind the `curl` command line tool. The API
//! currently closely matches that of libcurl itself, except that a Rustic layer
//! of safety is applied on top.
//!
//! [libcurl]: https://curl.haxx.se/libcurl/
//!
//! # The "Easy" API
//!
//! The easiest way to send a request is to use the `Easy` api which corresponds
//! to `CURL` in libcurl. This handle supports a wide variety of options and can
//! be used to make a single blocking request in a thread. Callbacks can be
//! specified to deal with data as it arrives and a handle can be reused to
//! cache connections and such.
//!
//! ```rust,no_run
//! use std::io::{stdout, Write};
//!
//! use curl::easy::Easy;
//!
//! // Write the contents of rust-lang.org to stdout
//! let mut easy = Easy::new();
//! easy.url("https://www.rust-lang.org/").unwrap();
//! easy.write_function(|data| {
//!     stdout().write_all(data).unwrap();
//!     Ok(data.len())
//! }).unwrap();
//! easy.perform().unwrap();
//! ```
//!
//! # What about multiple concurrent HTTP requests?
//!
//! One option you have currently is to send multiple requests in multiple
//! threads, but otherwise libcurl has a "multi" interface for doing this
//! operation. Initial bindings of this interface can be found in the `multi`
//! module, but feedback is welcome!
//!
//! # Where does libcurl come from?
//!
//! This crate links to the `curl-sys` crate which is in turn responsible for
//! acquiring and linking to the libcurl library. Currently this crate will
//! build libcurl from source if one is not already detected on the system.
//!
//! There is a large number of releases for libcurl, all with different sets of
//! capabilities. Robust programs may wish to inspect `Version::get()` to test
//! what features are implemented in the linked build of libcurl at runtime.

#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/curl/0.4")]

extern crate curl_sys;
extern crate libc;
extern crate socket2;

#[cfg(need_openssl_probe)]
extern crate openssl_probe;
#[cfg(need_openssl_init)]
extern crate openssl_sys;

#[cfg(target_env = "msvc")]
extern crate schannel;

use std::ffi::CStr;
use std::str;
use std::sync::Once;

pub use error::{Error, FormError, MultiError, ShareError};
mod error;

pub use version::{Protocols, Version};
mod version;

pub mod easy;
pub mod multi;
mod panic;

/// Initializes the underlying libcurl library.
///
/// It's not required to call this before the library is used, but it's
/// recommended to do so as soon as the program starts.
pub fn init() {
    static INIT: Once = Once::new();
    INIT.call_once(|| {
        platform_init();
        unsafe {
            assert_eq!(curl_sys::curl_global_init(curl_sys::CURL_GLOBAL_ALL), 0);
        }

        // Note that we explicitly don't schedule a call to
        // `curl_global_cleanup`. The documentation for that function says
        //
        // > You must not call it when any other thread in the program (i.e. a
        // > thread sharing the same memory) is running. This doesn't just mean
        // > no other thread that is using libcurl.
        //
        // We can't ever be sure of that, so unfortunately we can't call the
        // function.
    });

    #[cfg(need_openssl_init)]
    fn platform_init() {
        openssl_sys::init();
    }

    #[cfg(not(need_openssl_init))]
    fn platform_init() {}
}

unsafe fn opt_str<'a>(ptr: *const libc::c_char) -> Option<&'a str> {
    if ptr.is_null() {
        None
    } else {
        Some(str::from_utf8(CStr::from_ptr(ptr).to_bytes()).unwrap())
    }
}

fn cvt(r: curl_sys::CURLcode) -> Result<(), Error> {
    if r == curl_sys::CURLE_OK {
        Ok(())
    } else {
        Err(Error::new(r))
    }
}
<commit_msg>Experimental use of constructor functions to call init (#334)<commit_after>//! Rust bindings to the libcurl C library
//!
//! This crate contains bindings for an HTTP/HTTPS client which is powered by
//! [libcurl], the same library behind the `curl` command line tool. The API
//! currently closely matches that of libcurl itself, except that a Rustic layer
//! of safety is applied on top.
//!
//! [libcurl]: https://curl.haxx.se/libcurl/
//!
//! # The "Easy" API
//!
//! The easiest way to send a request is to use the `Easy` api which corresponds
//! to `CURL` in libcurl. This handle supports a wide variety of options and can
//! be used to make a single blocking request in a thread. Callbacks can be
//! specified to deal with data as it arrives and a handle can be reused to
//! cache connections and such.
//!
//! ```rust,no_run
//! use std::io::{stdout, Write};
//!
//! use curl::easy::Easy;
//!
//! // Write the contents of rust-lang.org to stdout
//! let mut easy = Easy::new();
//! easy.url("https://www.rust-lang.org/").unwrap();
//! easy.write_function(|data| {
//!     stdout().write_all(data).unwrap();
//!     Ok(data.len())
//! }).unwrap();
//! easy.perform().unwrap();
//! ```
//!
//! # What about multiple concurrent HTTP requests?
//!
//! One option you have currently is to send multiple requests in multiple
//! threads, but otherwise libcurl has a "multi" interface for doing this
//! operation. Initial bindings of this interface can be found in the `multi`
//! module, but feedback is welcome!
//!
//! # Where does libcurl come from?
//!
//! This crate links to the `curl-sys` crate which is in turn responsible for
//! acquiring and linking to the libcurl library. Currently this crate will
//! build libcurl from source if one is not already detected on the system.
//!
//! There is a large number of releases for libcurl, all with different sets of
//! capabilities. Robust programs may wish to inspect `Version::get()` to test
//! what features are implemented in the linked build of libcurl at runtime.
//!
//! # Initialization
//!
//! The underlying libcurl library must be initialized before use and has
//! certain requirements on how this is done. Check the documentation for
//! [`init`] for more details.

#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/curl/0.4")]

extern crate curl_sys;
extern crate libc;
extern crate socket2;

#[cfg(need_openssl_probe)]
extern crate openssl_probe;
#[cfg(need_openssl_init)]
extern crate openssl_sys;

#[cfg(target_env = "msvc")]
extern crate schannel;

use std::ffi::CStr;
use std::str;
use std::sync::Once;

pub use error::{Error, FormError, MultiError, ShareError};
mod error;

pub use version::{Protocols, Version};
mod version;

pub mod easy;
pub mod multi;
mod panic;

/// Initializes the underlying libcurl library.
///
/// The underlying libcurl library must be initialized before use, and must be
/// done so on the main thread before any other threads are created by the
/// program. This crate will do this for you automatically in the following
/// scenarios:
///
/// - Creating a new [`Easy`][easy::Easy] or [`Multi`][multi::Multi] handle
/// - At program startup on Windows, macOS, Linux, Android, or FreeBSD systems
///
/// This should be sufficient for most applications and scenarios, but in any
/// other case, it is strongly recommended that you call this function manually
/// as soon as your program starts.
///
/// Calling this function more than once is harmless and has no effect.
#[inline]
pub fn init() {
    /// Used to prevent concurrent or duplicate initialization.
    static INIT: Once = Once::new();

    /// An exported constructor function. On supported platforms, this will be
    /// invoked automatically before the program's `main` is called.
    #[cfg_attr(
        any(target_os = "linux", target_os = "freebsd", target_os = "android"),
        link_section = ".init_array"
    )]
    #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
    #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
    static INIT_CTOR: extern "C" fn() = init_inner;

    /// This is the body of our constructor function.
    #[cfg_attr(
        any(target_os = "linux", target_os = "android"),
        link_section = ".text.startup"
    )]
    extern "C" fn init_inner() {
        INIT.call_once(|| {
            #[cfg(need_openssl_init)]
            openssl_sys::init();

            unsafe {
                assert_eq!(curl_sys::curl_global_init(curl_sys::CURL_GLOBAL_ALL), 0);
            }

            // Note that we explicitly don't schedule a call to
            // `curl_global_cleanup`. The documentation for that function says
            //
            // > You must not call it when any other thread in the program (i.e.
            // > a thread sharing the same memory) is running. This doesn't just
            // > mean no other thread that is using libcurl.
            //
            // We can't ever be sure of that, so unfortunately we can't call the
            // function.
        });
    }

    // We invoke our init function through our static to ensure the symbol isn't
    // optimized away by a bug: https://github.com/rust-lang/rust/issues/47384
    INIT_CTOR();
}

unsafe fn opt_str<'a>(ptr: *const libc::c_char) -> Option<&'a str> {
    if ptr.is_null() {
        None
    } else {
        Some(str::from_utf8(CStr::from_ptr(ptr).to_bytes()).unwrap())
    }
}

fn cvt(r: curl_sys::CURLcode) -> Result<(), Error> {
    if r == curl_sys::CURLE_OK {
        Ok(())
    } else {
        Err(Error::new(r))
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! A library to localize strings, translating them according to runtime options.
//!
//! Basically, this library allows your project to generate a `lformat!` macro, that behaves
//! similarly to `format!`, except the message string (the first argument) might get translated
//! (if you can find the appropriate string for the language).
//!
//! # Usage
//!
//! First, you'll need to add the following to your `Cargo.toml` file:
//!
//! ```toml
//! build = "build.rs"
//!
//! [build-dependencies]
//! crowbook-localize = "0.0.7"
//!
//! [dependencies]
//! lazy_static = "0.2" # the generated file needs `lazy_static!`
//! ```
//!
//! You'll then need to create the `build.rs` file, which can look like this:
//!
//! ```rust,ignore
//! extern crate crowbook_localize;
//! use crowbook_localize::{Localizer, Extractor};
//!
//! fn main() {
//!     // Generate the `localize_macros.rs` file
//!     let mut localizer = Localizer::new();
//!     localizer.write_macro_file(concat!(env!("CARGO_MANIFEST_DIR"), "/src/lib/localize_macros.rs")).unwrap();
//!
//!     // Generate a `lang/default.pot` containing strings used to call `lformat!`
//!     let mut extractor = Extractor::new();
//!     extractor.add_messages_from_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/src")).unwrap();
//!     extractor.write_pot_file(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/default.pot")).unwrap();
//! }
//! ```
//!
//! This way, a `localize_macros.rs` file will be created at build time in `src/lib`.
//! To use it, the last step is to modify your `src/lib/lib.rs` file:
//!
//! ```rust,ignore
//! #[macro_use] extern crate lazy_static;
//! #[macro_use] mod localize_macros;
//! ```
//!
//! Once this is done, you can start replacing your calls to `format!` with calls to `lformat!`.
//!
//! In order to get translation, you'll need to actually translate the strings in separate
//! files, and set your `build.rs` to load them.
//!
//! E.g., if you have the following code:
//!
//! ```rust,ignore
//! println!("{}", lformat!("Hello, world!"));
//! ```
//! and you want it translated in french, you'll have to create a `lang/fr.po` file
//! from the `lang/default.pot` file containing:
//!
//! ```text
//! msgid "Hello, world!";
//! msgstr "Bonjour le monde !";
//! ```
//!
//! And load it in your `build.rs` file:
//!
//! ```rust,ignore
//! let mut localizer = Localizer::new();
//! localizer.add_lang("fr", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/fr.mp"))).unwrap();
//! localizer.write_macro_file("...");
//! ```
//!
//! Once *this* is done, you can use the `localize_macros::set_lang` function
//! to switch the language at runtime:
//!
//! ```rust,ignore
//! use localize_macros::set_lang;
//! set_lang("en");
//! println!("{}", lformat!("Hello, world!")); // prints "Hello, world!"
//! set_lang("fr");
//! println!("{}", lformat!("Hello, world!")); // prints "Bonjour le monde !"
//! ```
//!
//! # Updating your translation
//!
//! When you add new strings that need to be translated (by more calls to `lformat!`),
//! or when you change the content of existing strings, you can use [Gettext's `msgmerge`](https://www.gnu.org/software/gettext/manual/html_node/msgmerge-Invocation.html)
//! command to update your translation. While it is not guaranteed that the formats are
//! strictly identicals, it should work. (That is, it is a bug if it doesn't; but at this
//! stage, this library is absolutely not guaranteed to be bug-free.)
//!
//! # Warning
//!
//! In case the complexity of the operation didn't discourage you, I should warn you
//! that this library is highly experimental at this time.

extern crate regex;
#[macro_use] extern crate lazy_static;
extern crate walkdir;

mod common;
mod macrogen;
mod lang;
mod error;
mod localizer;
mod message;
mod extractor;

pub use error::{Result, Error};
pub use localizer::Localizer;
pub use extractor::Extractor;
<commit_msg>Update doc to reflect changes<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! A library to localize strings, translating them according to runtime options.
//!
//! Basically, this library allows your project to generate a `lformat!` macro, that behaves
//! similarly to `format!`, except the message string (the first argument) might get translated
//! (if you can find the appropriate string for the language).
//!
//! # Usage
//!
//! First, you'll need to add the following to your `Cargo.toml` file:
//!
//! ```toml
//! build = "build.rs"
//!
//! [build-dependencies]
//! crowbook-localize = "0.0.7"
//!
//! [dependencies]
//! lazy_static = "0.2" # the generated file needs `lazy_static!`
//! ```
//!
//! You'll then need to create the `build.rs` file, which can look like this:
//!
//! ```rust,ignore
//! extern crate crowbook_localize;
//! use crowbook_localize::{Localizer, Extractor};
//!
//! fn main() {
//!     // Generate a `lang/default.pot` containing strings used to call `lformat!`
//!     let mut extractor = Extractor::new();
//!     extractor.add_messages_from_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/src")).unwrap();
//!     extractor.write_pot_file(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/default.pot")).unwrap();
//!
//!     // Generate the `localize_macros.rs` file
//!     let mut localizer = Localizer::new(&extractor);
//!     localizer.write_macro_file(concat!(env!("CARGO_MANIFEST_DIR"), "/src/lib/localize_macros.rs")).unwrap();
//! }
//! ```
//!
//! This way, a `localize_macros.rs` file will be created at build time in `src/lib`.
//! To use it, the last step is to modify your `src/lib/lib.rs` file:
//!
//! ```rust,ignore
//! #[macro_use] extern crate lazy_static;
//! #[macro_use] mod localize_macros;
//! ```
//!
//! Once this is done, you can start replacing your calls to `format!` with calls to `lformat!`.
//!
//! In order to get translation, you'll need to actually translate the strings in separate
//! files, and set your `build.rs` to load them.
//!
//! E.g., if you have the following code:
//!
//! ```rust,ignore
//! println!("{}", lformat!("Hello, world!"));
//! ```
//! and you want it translated in french, you'll have to create a `lang/fr.po` file
//! from the `lang/default.pot` file containing:
//!
//! ```text
//! msgid "Hello, world!";
//! msgstr "Bonjour le monde !";
//! ```
//!
//! And load it in your `build.rs` file:
//!
//! ```rust,ignore
//! let mut localizer = Localizer::new();
//! localizer.add_lang("fr", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/fr.mp"))).unwrap();
//! localizer.write_macro_file("...");
//! ```
//!
//! Once *this* is done, you can use the `localize_macros::set_lang` function
//! to switch the language at runtime:
//!
//! ```rust,ignore
//! use localize_macros::set_lang;
//! set_lang("en");
//! println!("{}", lformat!("Hello, world!")); // prints "Hello, world!"
//! set_lang("fr");
//! println!("{}", lformat!("Hello, world!")); // prints "Bonjour le monde !"
//! ```
//!
//! # Updating your translation
//!
//! When you add new strings that need to be translated (by more calls to `lformat!`),
//! or when you change the content of existing strings, you can use [Gettext's `msgmerge`](https://www.gnu.org/software/gettext/manual/html_node/msgmerge-Invocation.html)
//! command to update your translation. While it is not guaranteed that the formats are
//! strictly identicals, it should work. (That is, it is a bug if it doesn't; but at this
//! stage, this library is absolutely not guaranteed to be bug-free.)
//!
//! # Warning
//!
//! In case the complexity of the operation didn't discourage you, I should warn you
//! that this library is highly experimental at this time.

extern crate regex;
#[macro_use] extern crate lazy_static;
extern crate walkdir;

mod common;
mod macrogen;
mod lang;
mod error;
mod localizer;
mod message;
mod extractor;

pub use error::{Result, Error};
pub use localizer::Localizer;
pub use extractor::Extractor;
<|endoftext|>


<commit_before>//! Actix web is a small, pragmatic, and extremely fast web framework
//! for Rust.
//!
//! ```rust,ignore
//! use actix_web::{server, App, Path, Responder};
//! # use std::thread;
//!
//! fn index(info: Path<(String, u32)>) -> impl Responder {
//!     format!("Hello {}! id:{}", info.0, info.1)
//! }
//!
//! fn main() {
//!     # thread::spawn(|| {
//!     server::new(|| {
//!         App::new().resource("/{name}/{id}/index.html", |r| r.with(index))
//!     }).bind("127.0.0.1:8080")
//!         .unwrap()
//!         .run();
//!     # });
//! }
//! ```
//!
//! ## Documentation & community resources
//!
//! Besides the API documentation (which you are currently looking
//! at!), several other resources are available:
//!
//! * [User Guide](https://actix.rs/docs/)
//! * [Chat on gitter](https://gitter.im/actix/actix)
//! * [GitHub repository](https://github.com/actix/actix-web)
//! * [Cargo package](https://crates.io/crates/actix-web)
//!
//! To get started navigating the API documentation you may want to
//! consider looking at the following pages:
//!
//! * [App](struct.App.html): This struct represents an actix-web
//!   application and is used to configure routes and other common
//!   settings.
//!
//! * [HttpServer](server/struct.HttpServer.html): This struct
//!   represents an HTTP server instance and is used to instantiate and
//!   configure servers.
//!
//! * [Request](struct.Request.html) and
//!   [Response](struct.Response.html): These structs
//!   represent HTTP requests and responses and expose various methods
//!   for inspecting, creating and otherwise utilizing them.
//!
//! ## Features
//!
//! * Supported *HTTP/1.x* protocol
//! * Streaming and pipelining
//! * Keep-alive and slow requests handling
//! * `WebSockets` server/client
//! * Supported Rust version: 1.26 or later
//!
//! ## Package feature
//!
//! * `session` - enables session support, includes `ring` crate as
//!   dependency
//!
#![allow(
    clippy::type_complexity,
    clippy::new_without_default,
    clippy::new_without_default_derive
)]

#[macro_use]
extern crate log;

pub mod body;
pub mod client;
mod config;
mod extensions;
mod header;
mod helpers;
mod httpcodes;
pub mod httpmessage;
mod json;
mod message;
mod payload;
mod request;
mod response;
mod service;

pub mod error;
pub mod h1;
pub mod h2;
pub mod test;
pub mod ws;

pub use self::body::{Body, MessageBody};
pub use self::config::{KeepAlive, ServiceConfig, ServiceConfigBuilder};
pub use self::error::{Error, ResponseError, Result};
pub use self::extensions::Extensions;
pub use self::httpmessage::HttpMessage;
pub use self::message::{Message, RequestHead, ResponseHead};
pub use self::payload::Payload;
pub use self::request::Request;
pub use self::response::Response;
pub use self::service::{SendError, SendResponse};

pub mod dev {
    //! The `actix-web` prelude for library developers
    //!
    //! The purpose of this module is to alleviate imports of many common actix
    //! traits by adding a glob import to the top of actix heavy modules:
    //!
    //! ```
    //! # #![allow(unused_imports)]
    //! use actix_http::dev::*;
    //! ```

    pub use crate::httpmessage::{MessageBody, Readlines, UrlEncoded};
    pub use crate::json::JsonBody;
    pub use crate::response::ResponseBuilder;
}

pub mod http {
    //! Various HTTP related types

    // re-exports
    pub use http::header::{HeaderName, HeaderValue};
    pub use http::{Method, StatusCode, Version};

    #[doc(hidden)]
    pub use http::{uri, Error, HeaderMap, HttpTryFrom, Uri};

    #[doc(hidden)]
    pub use http::uri::PathAndQuery;

    pub use cookie::{Cookie, CookieBuilder};

    /// Various http headers
    pub mod header {
        pub use crate::header::*;
    }
    pub use crate::header::ContentEncoding;
    pub use crate::message::ConnectionType;
}
<commit_msg>export PayloadStream<commit_after>//! Actix web is a small, pragmatic, and extremely fast web framework
//! for Rust.
//!
//! ```rust,ignore
//! use actix_web::{server, App, Path, Responder};
//! # use std::thread;
//!
//! fn index(info: Path<(String, u32)>) -> impl Responder {
//!     format!("Hello {}! id:{}", info.0, info.1)
//! }
//!
//! fn main() {
//!     # thread::spawn(|| {
//!     server::new(|| {
//!         App::new().resource("/{name}/{id}/index.html", |r| r.with(index))
//!     }).bind("127.0.0.1:8080")
//!         .unwrap()
//!         .run();
//!     # });
//! }
//! ```
//!
//! ## Documentation & community resources
//!
//! Besides the API documentation (which you are currently looking
//! at!), several other resources are available:
//!
//! * [User Guide](https://actix.rs/docs/)
//! * [Chat on gitter](https://gitter.im/actix/actix)
//! * [GitHub repository](https://github.com/actix/actix-web)
//! * [Cargo package](https://crates.io/crates/actix-web)
//!
//! To get started navigating the API documentation you may want to
//! consider looking at the following pages:
//!
//! * [App](struct.App.html): This struct represents an actix-web
//!   application and is used to configure routes and other common
//!   settings.
//!
//! * [HttpServer](server/struct.HttpServer.html): This struct
//!   represents an HTTP server instance and is used to instantiate and
//!   configure servers.
//!
//! * [Request](struct.Request.html) and
//!   [Response](struct.Response.html): These structs
//!   represent HTTP requests and responses and expose various methods
//!   for inspecting, creating and otherwise utilizing them.
//!
//! ## Features
//!
//! * Supported *HTTP/1.x* protocol
//! * Streaming and pipelining
//! * Keep-alive and slow requests handling
//! * `WebSockets` server/client
//! * Supported Rust version: 1.26 or later
//!
//! ## Package feature
//!
//! * `session` - enables session support, includes `ring` crate as
//!   dependency
//!
#![allow(
    clippy::type_complexity,
    clippy::new_without_default,
    clippy::new_without_default_derive
)]

#[macro_use]
extern crate log;

pub mod body;
pub mod client;
mod config;
mod extensions;
mod header;
mod helpers;
mod httpcodes;
pub mod httpmessage;
mod json;
mod message;
mod payload;
mod request;
mod response;
mod service;

pub mod error;
pub mod h1;
pub mod h2;
pub mod test;
pub mod ws;

pub use self::body::{Body, MessageBody};
pub use self::config::{KeepAlive, ServiceConfig, ServiceConfigBuilder};
pub use self::error::{Error, ResponseError, Result};
pub use self::extensions::Extensions;
pub use self::httpmessage::HttpMessage;
pub use self::message::{Message, RequestHead, ResponseHead};
pub use self::payload::{Payload, PayloadStream};
pub use self::request::Request;
pub use self::response::Response;
pub use self::service::{SendError, SendResponse};

pub mod dev {
    //! The `actix-web` prelude for library developers
    //!
    //! The purpose of this module is to alleviate imports of many common actix
    //! traits by adding a glob import to the top of actix heavy modules:
    //!
    //! ```
    //! # #![allow(unused_imports)]
    //! use actix_http::dev::*;
    //! ```

    pub use crate::httpmessage::{MessageBody, Readlines, UrlEncoded};
    pub use crate::json::JsonBody;
    pub use crate::response::ResponseBuilder;
}

pub mod http {
    //! Various HTTP related types

    // re-exports
    pub use http::header::{HeaderName, HeaderValue};
    pub use http::{Method, StatusCode, Version};

    #[doc(hidden)]
    pub use http::{uri, Error, HeaderMap, HttpTryFrom, Uri};

    #[doc(hidden)]
    pub use http::uri::PathAndQuery;

    pub use cookie::{Cookie, CookieBuilder};

    /// Various http headers
    pub mod header {
        pub use crate::header::*;
    }
    pub use crate::header::ContentEncoding;
    pub use crate::message::ConnectionType;
}
<|endoftext|>