<commit_before>// Copyright 2016 Victor Brekenfeld
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//!
//! `simplelog` provides a series of logging facilities, that can be easily combined.
//!
//! - `SimpleLogger` (very basic logger that logs to stdout)
//! - `TermLogger` (advanced terminal logger, that splits to stdout/err and has color support) (can be excluded on unsupported platforms)
//! - `WriteLogger` (logs to a given struct implementing `Write`, e.g. a file)
//! - `CombinedLogger` (can be used to form combinations of the above loggers)
//!
//! Only one Logger should be initialized of the start of your program
//! through the `Logger::init(...)` method. For the actual calling syntax
//! take a look at the documentation of the specific implementation(s) you wanna use.
//!

#![deny(missing_docs)]

#[macro_use] extern crate log;
#[cfg(feature = "term")]
extern crate term;
extern crate chrono;

mod config;
mod loggers;

pub use self::config::Config;
pub use self::loggers::{SimpleLogger, WriteLogger, CombinedLogger};
#[cfg(feature = "term")]
pub use self::loggers::{TermLogger, TermLogError};

pub use log::{Level, LevelFilter};

use log::Log;

/// Trait to have a common interface to obtain the Level of Loggers
///
/// Necessary for CombinedLogger to calculate
/// the lowest used Level.
///
pub trait SharedLogger: Log {
    /// Returns the set Level for this Logger
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// let logger = SimpleLogger::new(LevelFilter::Info, Config::default());
    /// println!("{}", logger.level());
    /// # }
    /// ```
    fn level(&self) -> LevelFilter;

    /// Inspect the config of a running Logger
    ///
    /// An Option is returned, because some Logger may not contain a Config
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// let logger = SimpleLogger::new(LevelFilter::Info, Config::default());
    /// println!("{:?}", logger.config());
    /// # }
    /// ```
    fn config(&self) -> Option<&Config>;

    /// Returns the logger as a Log trait object
    fn as_log(self: Box<Self>) -> Box<Log>;
}

#[cfg(test)]
mod tests {
    use std::io::Read;
    use std::fs::File;

    use super::*;

    #[test]
    fn test() {
        let mut i = 0;

        CombinedLogger::init(
            {
                let mut vec = Vec::new();
                let mut conf = Config {
                    time: None,
                    level: None,
                    target: None,
                    location: None,
                    time_format: None,
                };

                for elem in vec![None, Some(Level::Trace), Some(Level::Debug), Some(Level::Info), Some(Level::Warn), Some(Level::Error)]
                {
                    conf.location = elem;
                    conf.target = elem;
                    conf.level = elem;
                    conf.time = elem;
                    i += 1;

                    //error
                    vec.push(SimpleLogger::new(LevelFilter::Error, conf) as Box<SharedLogger>);
                    vec.push(TermLogger::new(LevelFilter::Error, conf).unwrap() as Box<SharedLogger>);
                    vec.push(WriteLogger::new(LevelFilter::Error, conf, File::create(&format!("error_{}.log", i)).unwrap()) as Box<SharedLogger>);

                    //warn
                    vec.push(SimpleLogger::new(LevelFilter::Warn, conf) as Box<SharedLogger>);
                    vec.push(TermLogger::new(LevelFilter::Warn, conf).unwrap() as Box<SharedLogger>);
                    vec.push(WriteLogger::new(LevelFilter::Warn, conf, File::create(&format!("warn_{}.log", i)).unwrap()) as Box<SharedLogger>);

                    //info
                    vec.push(SimpleLogger::new(LevelFilter::Info, conf) as Box<SharedLogger>);
                    vec.push(TermLogger::new(LevelFilter::Info, conf).unwrap() as Box<SharedLogger>);
                    vec.push(WriteLogger::new(LevelFilter::Info, conf, File::create(&format!("info_{}.log", i)).unwrap()) as Box<SharedLogger>);

                    //debug
                    vec.push(SimpleLogger::new(LevelFilter::Debug, conf) as Box<SharedLogger>);
                    vec.push(TermLogger::new(LevelFilter::Debug, conf).unwrap() as Box<SharedLogger>);
                    vec.push(WriteLogger::new(LevelFilter::Debug, conf, File::create(&format!("debug_{}.log", i)).unwrap()) as Box<SharedLogger>);

                    //trace
                    vec.push(SimpleLogger::new(LevelFilter::Trace, conf) as Box<SharedLogger>);
                    vec.push(TermLogger::new(LevelFilter::Trace, conf).unwrap() as Box<SharedLogger>);
                    vec.push(WriteLogger::new(LevelFilter::Trace, conf, File::create(&format!("trace_{}.log", i)).unwrap()) as Box<SharedLogger>);
                }

                vec
            }
        ).unwrap();

        error!("Test Error");
        warn!("Test Warning");
        info!("Test Information");
        debug!("Test Debug");
        trace!("Test Trace");

        for j in 1..i
        {
            let mut error = String::new();
            File::open(&format!("error_{}.log", j)).unwrap().read_to_string(&mut error).unwrap();
            let mut warn = String::new();
            File::open(&format!("warn_{}.log", j)).unwrap().read_to_string(&mut warn).unwrap();
            let mut info = String::new();
            File::open(&format!("info_{}.log", j)).unwrap().read_to_string(&mut info).unwrap();
            let mut debug = String::new();
            File::open(&format!("debug_{}.log", j)).unwrap().read_to_string(&mut debug).unwrap();
            let mut trace = String::new();
            File::open(&format!("trace_{}.log", j)).unwrap().read_to_string(&mut trace).unwrap();

            assert!(error.contains("Test Error"));
            assert!(!error.contains("Test Warning"));
            assert!(!error.contains("Test Information"));
            assert!(!error.contains("Test Debug"));
            assert!(!error.contains("Test Trace"));

            assert!(warn.contains("Test Error"));
            assert!(warn.contains("Test Warning"));
            assert!(!warn.contains("Test Information"));
            assert!(!warn.contains("Test Debug"));
            assert!(!warn.contains("Test Trace"));

            assert!(info.contains("Test Error"));
            assert!(info.contains("Test Warning"));
            assert!(info.contains("Test Information"));
            assert!(!info.contains("Test Debug"));
            assert!(!info.contains("Test Trace"));

            assert!(debug.contains("Test Error"));
            assert!(debug.contains("Test Warning"));
            assert!(debug.contains("Test Information"));
            assert!(debug.contains("Test Debug"));
            assert!(!debug.contains("Test Trace"));

            assert!(trace.contains("Test Error"));
            assert!(trace.contains("Test Warning"));
            assert!(trace.contains("Test Information"));
            assert!(trace.contains("Test Debug"));
            assert!(trace.contains("Test Trace"));
        }
    }
}
<commit_msg>✏ Fix warning about unused macro import<commit_after>// Copyright 2016 Victor Brekenfeld
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//!
//! `simplelog` provides a series of logging facilities, that can be easily combined.
//!
//! - `SimpleLogger` (very basic logger that logs to stdout)
//! - `TermLogger` (advanced terminal logger, that splits to stdout/err and has color support) (can be excluded on unsupported platforms)
//! - `WriteLogger` (logs to a given struct implementing `Write`, e.g. a file)
//! - `CombinedLogger` (can be used to form combinations of the above loggers)
//!
//! Only one Logger should be initialized of the start of your program
//! through the `Logger::init(...)` method. For the actual calling syntax
//! take a look at the documentation of the specific implementation(s) you wanna use.
//!

#![deny(missing_docs)]

#[cfg_attr(test, macro_use)]
extern crate log;
#[cfg(feature = "term")]
extern crate term;
extern crate chrono;

mod config;
mod loggers;

pub use self::config::Config;
pub use self::loggers::{SimpleLogger, WriteLogger, CombinedLogger};
#[cfg(feature = "term")]
pub use self::loggers::{TermLogger, TermLogError};

pub use log::{Level, LevelFilter};

use log::Log;

/// Trait to have a common interface to obtain the Level of Loggers
///
/// Necessary for CombinedLogger to calculate
/// the lowest used Level.
///
pub trait SharedLogger: Log {
    /// Returns the set Level for this Logger
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// let logger = SimpleLogger::new(LevelFilter::Info, Config::default());
    /// println!("{}", logger.level());
    /// # }
    /// ```
    fn level(&self) -> LevelFilter;

    /// Inspect the config of a running Logger
    ///
    /// An Option is returned, because some Logger may not contain a Config
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// let logger = SimpleLogger::new(LevelFilter::Info, Config::default());
    /// println!("{:?}", logger.config());
    /// # }
    /// ```
    fn config(&self) -> Option<&Config>;

    /// Returns the logger as a Log trait object
    fn as_log(self: Box<Self>) -> Box<Log>;
}

#[cfg(test)]
mod tests {
    use std::io::Read;
    use std::fs::File;

    use super::*;

    #[test]
    fn test() {
        let mut i = 0;

        CombinedLogger::init(
            {
                let mut vec = Vec::new();
                let mut conf = Config {
                    time: None,
                    level: None,
                    target: None,
                    location: None,
                    time_format: None,
                };

                for elem in vec![None, Some(Level::Trace), Some(Level::Debug), Some(Level::Info), Some(Level::Warn), Some(Level::Error)]
                {
                    conf.location = elem;
                    conf.target = elem;
                    conf.level = elem;
                    conf.time = elem;
                    i += 1;

                    //error
                    vec.push(SimpleLogger::new(LevelFilter::Error, conf) as Box<SharedLogger>);
                    vec.push(TermLogger::new(LevelFilter::Error, conf).unwrap() as Box<SharedLogger>);
                    vec.push(WriteLogger::new(LevelFilter::Error, conf, File::create(&format!("error_{}.log", i)).unwrap()) as Box<SharedLogger>);

                    //warn
                    vec.push(SimpleLogger::new(LevelFilter::Warn, conf) as Box<SharedLogger>);
                    vec.push(TermLogger::new(LevelFilter::Warn, conf).unwrap() as Box<SharedLogger>);
                    vec.push(WriteLogger::new(LevelFilter::Warn, conf, File::create(&format!("warn_{}.log", i)).unwrap()) as Box<SharedLogger>);

                    //info
                    vec.push(SimpleLogger::new(LevelFilter::Info, conf) as Box<SharedLogger>);
                    vec.push(TermLogger::new(LevelFilter::Info, conf).unwrap() as Box<SharedLogger>);
                    vec.push(WriteLogger::new(LevelFilter::Info, conf, File::create(&format!("info_{}.log", i)).unwrap()) as Box<SharedLogger>);

                    //debug
                    vec.push(SimpleLogger::new(LevelFilter::Debug, conf) as Box<SharedLogger>);
                    vec.push(TermLogger::new(LevelFilter::Debug, conf).unwrap() as Box<SharedLogger>);
                    vec.push(WriteLogger::new(LevelFilter::Debug, conf, File::create(&format!("debug_{}.log", i)).unwrap()) as Box<SharedLogger>);

                    //trace
                    vec.push(SimpleLogger::new(LevelFilter::Trace, conf) as Box<SharedLogger>);
                    vec.push(TermLogger::new(LevelFilter::Trace, conf).unwrap() as Box<SharedLogger>);
                    vec.push(WriteLogger::new(LevelFilter::Trace, conf, File::create(&format!("trace_{}.log", i)).unwrap()) as Box<SharedLogger>);
                }

                vec
            }
        ).unwrap();

        error!("Test Error");
        warn!("Test Warning");
        info!("Test Information");
        debug!("Test Debug");
        trace!("Test Trace");

        for j in 1..i
        {
            let mut error = String::new();
            File::open(&format!("error_{}.log", j)).unwrap().read_to_string(&mut error).unwrap();
            let mut warn = String::new();
            File::open(&format!("warn_{}.log", j)).unwrap().read_to_string(&mut warn).unwrap();
            let mut info = String::new();
            File::open(&format!("info_{}.log", j)).unwrap().read_to_string(&mut info).unwrap();
            let mut debug = String::new();
            File::open(&format!("debug_{}.log", j)).unwrap().read_to_string(&mut debug).unwrap();
            let mut trace = String::new();
            File::open(&format!("trace_{}.log", j)).unwrap().read_to_string(&mut trace).unwrap();

            assert!(error.contains("Test Error"));
            assert!(!error.contains("Test Warning"));
            assert!(!error.contains("Test Information"));
            assert!(!error.contains("Test Debug"));
            assert!(!error.contains("Test Trace"));

            assert!(warn.contains("Test Error"));
            assert!(warn.contains("Test Warning"));
            assert!(!warn.contains("Test Information"));
            assert!(!warn.contains("Test Debug"));
            assert!(!warn.contains("Test Trace"));

            assert!(info.contains("Test Error"));
            assert!(info.contains("Test Warning"));
            assert!(info.contains("Test Information"));
            assert!(!info.contains("Test Debug"));
            assert!(!info.contains("Test Trace"));

            assert!(debug.contains("Test Error"));
            assert!(debug.contains("Test Warning"));
            assert!(debug.contains("Test Information"));
            assert!(debug.contains("Test Debug"));
            assert!(!debug.contains("Test Trace"));

            assert!(trace.contains("Test Error"));
            assert!(trace.contains("Test Warning"));
            assert!(trace.contains("Test Information"));
            assert!(trace.contains("Test Debug"));
            assert!(trace.contains("Test Trace"));
        }
    }
}
<|endoftext|>


<commit_before>//! This crate provides safe bindings to
//! [wlroots](https://github.com/swaywm/wlroots).
//!
//! Start your [Compositor](struct.Compositor.html) by implementing an [input
//! manager](manager/struct.InputManager.html) and an [output
//! manager](manager/struct.OutputManager.html) on two separate structs.
//!
//! # Example
//! ```rust,no_run
//! extern crate wlroots;
//!
//! struct InputManager;
//! struct OutputManager;
//!
//! impl wlroots::manager::OutputManagerHandler for OutputManager {}
//! impl wlroots::manager::InputManagerHandler for InputManager {}
//!
//! fn main() {
//!     wlroots::compositor::Compositor::new(Box::new(InputManager),
//!     Box::new(OutputManager)).run()
//! }
//! ```

#![allow(unused_unsafe)]
#[macro_use]
extern crate bitflags;
extern crate lazy_static;
extern crate libc;
#[macro_use]
extern crate wayland_sys;
pub extern crate wlroots_sys;
pub extern crate xkbcommon;

#[macro_use]
mod macros;
mod manager;
mod compositor;
pub mod events;
pub mod types;
mod utils;

pub type NotifyFunc = unsafe extern "C" fn(*mut wlroots_sys::wl_listener, *mut libc::c_void);

pub use self::compositor::{Compositor, terminate};
pub use self::events::key_events::*;
pub use self::events::pointer_events::*;
pub use self::manager::{InputManagerHandler, KeyboardHandler, OutputHandler, OutputManagerHandler,
                        PointerHandler};
pub use self::types::cursor::*;
pub use self::types::input_device::*;
pub use self::types::keyboard::*;
pub use self::types::output::*;
<commit_msg>Removed NotifyFunc<commit_after>//! This crate provides safe bindings to
//! [wlroots](https://github.com/swaywm/wlroots).
//!
//! Start your [Compositor](struct.Compositor.html) by implementing an [input
//! manager](manager/struct.InputManager.html) and an [output
//! manager](manager/struct.OutputManager.html) on two separate structs.
//!
//! # Example
//! ```rust,no_run
//! extern crate wlroots;
//!
//! struct InputManager;
//! struct OutputManager;
//!
//! impl wlroots::manager::OutputManagerHandler for OutputManager {}
//! impl wlroots::manager::InputManagerHandler for InputManager {}
//!
//! fn main() {
//!     wlroots::compositor::Compositor::new(Box::new(InputManager),
//!     Box::new(OutputManager)).run()
//! }
//! ```

#![allow(unused_unsafe)]
#[macro_use]
extern crate bitflags;
extern crate lazy_static;
extern crate libc;
#[macro_use]
extern crate wayland_sys;
pub extern crate wlroots_sys;
pub extern crate xkbcommon;

#[macro_use]
mod macros;
mod manager;
mod compositor;
pub mod events;
pub mod types;
mod utils;

pub use self::compositor::{Compositor, terminate};
pub use self::events::key_events::*;
pub use self::events::pointer_events::*;
pub use self::manager::{InputManagerHandler, KeyboardHandler, OutputHandler, OutputManagerHandler,
                        PointerHandler};
pub use self::types::cursor::*;
pub use self::types::input_device::*;
pub use self::types::keyboard::*;
pub use self::types::output::*;
<|endoftext|>


<commit_before>//! This library parses a Puppetfile

#![crate_name = "puppetfile"]
#![deny(missing_doc)]
#![feature(slicing_syntax)]
#![feature(globs)]

extern crate http;
extern crate serialize;
extern crate semver;
extern crate url;

use std::fmt;
use serialize::json;
use semver::VersionReq;
use http::client::RequestWriter;
use http::method::Get;
use url::Url;

mod puppetfile_parser;

#[cfg(test)]
mod test;

/// This represents a Puppetfile
#[deriving(PartialEq, Clone)]
#[experimental]
pub struct Puppetfile {
    /// The forge URL
    pub forge: String,
    /// All Modules contained in the Puppetfile
    pub modules: Vec<Module>
}

#[experimental]
impl Puppetfile {
    /// Try parsing the contents of a Puppetfile into a Puppetfile struct
    pub fn parse(contents: &str) -> Result<Puppetfile, String> {
        puppetfile_parser::parse(contents)
    }
}
impl fmt::Show for Puppetfile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let res = write!(f, "forge '{}'\n\n", self.forge);
        self.modules.iter().fold(res, |prev_res, module| { prev_res.and(write!(f, "\n{}\n", module)) })
    }
}

/// The representation of a puppet module
#[deriving(PartialEq, Clone)]
#[experimental]
pub struct Module {
    /// Name of the module
    pub name: String,
    /// More information about the module
    pub info: Vec<PuppetModuleInfo>
}

#[deriving(Decodable)]
struct ForgeVersionResponse {
    version: String
}

/// represents an error while checking the version published on the forge
#[deriving(Clone, Show)]
pub struct ForgeVersionError(String);

#[experimental]
impl Module {
    /// The current version of the module returned from the forge API
    pub fn forge_version(&self, forge_url: &String) -> Result<semver::Version, ForgeVersionError> {
        let url = try!(self.version_url(forge_url));
        let request: RequestWriter = try!(RequestWriter::new(Get, url).map_err(|err|
            ForgeVersionError(format!("{}", err))
        ));
        let mut response = try!(request.read_response().map_err(|(_, err)|
            ForgeVersionError(format!("{}", err))
        ));
        let response_string = try!(response.read_to_string().map_err(|err|
            ForgeVersionError(format!("{}", err))
        ));
        let version_struct: ForgeVersionResponse = try!(json::decode(response_string[]).map_err(|err|
            ForgeVersionError(format!("{}", err))
        ));
        semver::Version::parse(version_struct.version[]).map_err(|err|
            ForgeVersionError(format!("{}", err))
        )
    }

    /// Builds the URL for the forge API for fetching the version
    pub fn version_url(&self, forge_url: &String) -> Result<Url, ForgeVersionError> {
        let stripped_url = match forge_url[].ends_with("/") {
            true => forge_url[..forge_url.len() - 1],
            _    => forge_url[]
        };
        let (user, mod_name) = match self.user_name_pair() {
            Some((user, mod_name)) => (user, mod_name),
            None => return Err(ForgeVersionError("Could not build url".to_string()))
        };
        Url::parse(format!("{}/users/{}/modules/{}/releases/find.json", stripped_url, user, mod_name)[]).map_err(|err|
            ForgeVersionError(format!("{}", err))
        )
    }

    /// Returns user and module name from 'user/mod_name'
    pub fn user_name_pair(&self) -> Option<(&str, &str)> {
        if self.name[].contains("/") {
            let mut parts = self.name[].split('/');
            Some((parts.next().unwrap(), parts.next().unwrap()))
        } else {
            None
        }
    }

    /// Returns the version if specified
    pub fn version(&self) -> Option<&VersionReq> {
        for info in self.info.iter() {
            match *info {
                Version(ref v) => return Some(v),
                ModuleInfo(..) => ()
            }
        }
        None
    }
}
impl fmt::Show for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let res = write!(f, "mod '{}'", self.name);
        self.info.iter().fold(res, |prev_res, mod_info| {
            match *mod_info {
                Version(..) => prev_res.and(write!(f, ", '{}'", mod_info)),
                ModuleInfo(..) => prev_res.and(write!(f, ",\n  {}", mod_info)),
            }
        })
    }
}

/// Further Information on Puppet Modules
#[deriving(PartialEq, Clone)]
pub enum PuppetModuleInfo {
    /// Version as String
    Version(VersionReq),
    /// Key Value based Information
    ModuleInfo(String, String)
}
impl PuppetModuleInfo {
    /// Returns `true` if the option is a `Version` value
    pub fn is_version(&self) -> bool {
        match *self {
            Version(..)    => true,
            ModuleInfo(..) => false
        }
    }
}

impl fmt::Show for PuppetModuleInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Version(ref v) => write!(f, "{}", v),
            ModuleInfo(ref k, ref v) => write!(f, ":{} => '{}'", k, v)
        }
    }
}

<commit_msg>rename deprecated lint<commit_after>//! This library parses a Puppetfile

#![crate_name = "puppetfile"]
#![deny(missing_docs)]
#![feature(slicing_syntax)]
#![feature(globs)]

extern crate http;
extern crate serialize;
extern crate semver;
extern crate url;

use std::fmt;
use serialize::json;
use semver::VersionReq;
use http::client::RequestWriter;
use http::method::Get;
use url::Url;

mod puppetfile_parser;

#[cfg(test)]
mod test;

/// This represents a Puppetfile
#[deriving(PartialEq, Clone)]
#[experimental]
pub struct Puppetfile {
    /// The forge URL
    pub forge: String,
    /// All Modules contained in the Puppetfile
    pub modules: Vec<Module>
}

#[experimental]
impl Puppetfile {
    /// Try parsing the contents of a Puppetfile into a Puppetfile struct
    pub fn parse(contents: &str) -> Result<Puppetfile, String> {
        puppetfile_parser::parse(contents)
    }
}
impl fmt::Show for Puppetfile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let res = write!(f, "forge '{}'\n\n", self.forge);
        self.modules.iter().fold(res, |prev_res, module| { prev_res.and(write!(f, "\n{}\n", module)) })
    }
}

/// The representation of a puppet module
#[deriving(PartialEq, Clone)]
#[experimental]
pub struct Module {
    /// Name of the module
    pub name: String,
    /// More information about the module
    pub info: Vec<PuppetModuleInfo>
}

#[deriving(Decodable)]
struct ForgeVersionResponse {
    version: String
}

/// represents an error while checking the version published on the forge
#[deriving(Clone, Show)]
pub struct ForgeVersionError(String);

#[experimental]
impl Module {
    /// The current version of the module returned from the forge API
    pub fn forge_version(&self, forge_url: &String) -> Result<semver::Version, ForgeVersionError> {
        let url = try!(self.version_url(forge_url));
        let request: RequestWriter = try!(RequestWriter::new(Get, url).map_err(|err|
            ForgeVersionError(format!("{}", err))
        ));
        let mut response = try!(request.read_response().map_err(|(_, err)|
            ForgeVersionError(format!("{}", err))
        ));
        let response_string = try!(response.read_to_string().map_err(|err|
            ForgeVersionError(format!("{}", err))
        ));
        let version_struct: ForgeVersionResponse = try!(json::decode(response_string[]).map_err(|err|
            ForgeVersionError(format!("{}", err))
        ));
        semver::Version::parse(version_struct.version[]).map_err(|err|
            ForgeVersionError(format!("{}", err))
        )
    }

    /// Builds the URL for the forge API for fetching the version
    pub fn version_url(&self, forge_url: &String) -> Result<Url, ForgeVersionError> {
        let stripped_url = match forge_url[].ends_with("/") {
            true => forge_url[..forge_url.len() - 1],
            _    => forge_url[]
        };
        let (user, mod_name) = match self.user_name_pair() {
            Some((user, mod_name)) => (user, mod_name),
            None => return Err(ForgeVersionError("Could not build url".to_string()))
        };
        Url::parse(format!("{}/users/{}/modules/{}/releases/find.json", stripped_url, user, mod_name)[]).map_err(|err|
            ForgeVersionError(format!("{}", err))
        )
    }

    /// Returns user and module name from 'user/mod_name'
    pub fn user_name_pair(&self) -> Option<(&str, &str)> {
        if self.name[].contains("/") {
            let mut parts = self.name[].split('/');
            Some((parts.next().unwrap(), parts.next().unwrap()))
        } else {
            None
        }
    }

    /// Returns the version if specified
    pub fn version(&self) -> Option<&VersionReq> {
        for info in self.info.iter() {
            match *info {
                Version(ref v) => return Some(v),
                ModuleInfo(..) => ()
            }
        }
        None
    }
}
impl fmt::Show for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let res = write!(f, "mod '{}'", self.name);
        self.info.iter().fold(res, |prev_res, mod_info| {
            match *mod_info {
                Version(..) => prev_res.and(write!(f, ", '{}'", mod_info)),
                ModuleInfo(..) => prev_res.and(write!(f, ",\n  {}", mod_info)),
            }
        })
    }
}

/// Further Information on Puppet Modules
#[deriving(PartialEq, Clone)]
pub enum PuppetModuleInfo {
    /// Version as String
    Version(VersionReq),
    /// Key Value based Information
    ModuleInfo(String, String)
}
impl PuppetModuleInfo {
    /// Returns `true` if the option is a `Version` value
    pub fn is_version(&self) -> bool {
        match *self {
            Version(..)    => true,
            ModuleInfo(..) => false
        }
    }
}

impl fmt::Show for PuppetModuleInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Version(ref v) => write!(f, "{}", v),
            ModuleInfo(ref k, ref v) => write!(f, ":{} => '{}'", k, v)
        }
    }
}

<|endoftext|>


<commit_before>#![cfg_attr(all(feature="nightly", test), feature(test))]
#![cfg_attr(feature="nightly", feature(const_fn))]

#[macro_use]
#[cfg(test)]
extern crate lazy_static;

use std::thread::{self, JoinHandle};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::sync::{Arc, Mutex, Barrier};
use std::marker::PhantomData;

enum Message {
    NewJob(Thunk<'static>),
    Join,
}

trait FnBox {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce()> FnBox for F {
    fn call_box(self: Box<F>) {
        (*self)()
    }
}

type Thunk<'a> = Box<FnBox + Send + 'a>;

impl Drop for PoolCache {
    fn drop(&mut self) {
        ::std::mem::replace(&mut self.job_sender, None);
    }
}

pub struct PoolCache {
    threads: Vec<JoinHandle<()>>,
    job_sender: Option<Sender<Message>>,
    join_barrier: Arc<(Mutex<Receiver<Message>>, Barrier)>,
}

impl PoolCache {
    pub fn new(n: u32) -> PoolCache {
        assert!(n >= 1);

        let (job_sender, job_receiver) = channel();
        let job_receiver = Arc::new((Mutex::new(job_receiver),
                                     Barrier::new(n as usize + 1)));

        let mut threads = Vec::with_capacity(n as usize);

        // spawn n threads, put them in waiting mode
        for _ in 0..n {
            let job_receiver = job_receiver.clone();
            threads.push(thread::spawn(move || {
                loop {
                    let message = {
                        // Only lock jobs for the time it takes
                        // to get a job, not run it.
                        let lock = job_receiver.0.lock().unwrap();
                        lock.recv()
                    };

                    match message {
                        Ok(Message::NewJob(job)) => {
                            job.call_box();
                        }
                        Ok(Message::Join) => {
                            job_receiver.1.wait();
                        }
                        // The pool was dropped.
                        Err(..) => break
                    }
                }
            }));
        }

        PoolCache {
            threads: threads,
            job_sender: Some(job_sender),
            join_barrier: job_receiver,
        }
    }

    pub fn scope<'pool, 'scope, F, R>(&'pool mut self, f: F) -> R
        where F: FnOnce(&Scope<'pool, 'scope>) -> R
    {
        let scope = Scope {
            pool: self,
            _marker: PhantomData,
        };
        f(&scope)
    }

    pub fn thread_count(&self) -> u32 {
        self.threads.len() as u32
    }
}

/////////////////////////////////////////////////////////////////////////////

pub struct Scope<'pool, 'scope> {
    pool: &'pool mut PoolCache,
    _marker: PhantomData<&'scope mut ()>,
}

impl<'pool, 'scope> Scope<'pool, 'scope> {
    pub fn execute<F>(&self, f: F)
        where F: FnOnce() + Send + 'scope
    {
        let b = unsafe {
            ::std::mem::transmute::<Thunk<'scope>, Thunk<'static>>(Box::new(f))
        };
        self.pool.job_sender.as_ref().unwrap().send(Message::NewJob(b)).unwrap();
    }
}

impl<'pool, 'scope> Drop for Scope<'pool, 'scope> {
    fn drop(&mut self) {
        for _ in 0..self.pool.threads.len() {
            self.pool.job_sender.as_ref().unwrap().send(Message::Join).unwrap();
        }

        self.pool.join_barrier.1.wait();
    }
}

/////////////////////////////////////////////////////////////////////////////

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

    #[test]
    fn example() {
        // Create a threadpool holding 4 threads
        let mut pool = PoolCache::new(4);

        let mut vec = vec![0, 1, 2, 3, 4, 5, 6, 7];

        // Use the threads as scoped threads that can
        // reference anything outside this closure
        pool.scope(|scoped| {

            // Create references to each element in the vector ...
            for e in &mut vec {
                // ... and add 1 to it in a seperate thread
                scoped.execute(move || {
                    *e += 1;
                });
            }
        });

        assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7, 8]);
    }

    #[test]
    fn smoketest() {
        let mut pool = PoolCache::new(4);

        for i in 1..7 {
            let mut vec = vec![0, 1, 2, 3, 4];
            pool.scope(|s| {
                for e in vec.iter_mut() {
                    s.execute(move || {
                        *e += i;
                    });
                }
            });

            let mut vec2 = vec![0, 1, 2, 3, 4];
            for e in vec2.iter_mut() {
                *e += i;
            }

            assert_eq!(vec, vec2);
        }
    }

    #[test]
    #[should_panic]
    fn panicking() {
        let mut pool = PoolCache::new(4);
        pool.scope(|scoped| {
            scoped.execute(move || {
                panic!()
            });
        });
    }
}

#[cfg(all(test, feature="nightly"))]
mod benches {
    extern crate test;

    use self::test::{Bencher, black_box};
    use super::PoolCache;
    use std::sync::Mutex;

    // const MS_SLEEP_PER_OP: u32 = 1;

    lazy_static! {
        static ref POOL_1: Mutex<PoolCache> = Mutex::new(PoolCache::new(1));
        static ref POOL_2: Mutex<PoolCache> = Mutex::new(PoolCache::new(2));
        static ref POOL_3: Mutex<PoolCache> = Mutex::new(PoolCache::new(3));
        static ref POOL_4: Mutex<PoolCache> = Mutex::new(PoolCache::new(4));
        static ref POOL_5: Mutex<PoolCache> = Mutex::new(PoolCache::new(5));
        static ref POOL_8: Mutex<PoolCache> = Mutex::new(PoolCache::new(8));
    }

    fn fib(n: u64) -> u64 {
        let mut prev_prev: u64 = 1;
        let mut prev = 1;
        let mut current = 1;
        for _ in 2..(n+1) {
            current = prev_prev.wrapping_add(prev);
            prev_prev = prev;
            prev = current;
        }
        current
    }

    fn threads_interleaved_n(pool: &mut PoolCache)  {
        let size = 1024; // 1kiB

        let mut data = vec![1u8; size];
        pool.scope(|s| {
            for e in data.iter_mut() {
                s.execute(move || {
                    *e += fib(black_box(1000 * (*e as u64))) as u8;
                    //thread::sleep_ms(MS_SLEEP_PER_OP);
                });
            }
        });
    }

    #[bench]
    fn threads_interleaved_1(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_1.lock().unwrap()))
    }

    #[bench]
    fn threads_interleaved_2(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_2.lock().unwrap()))
    }

    #[bench]
    fn threads_interleaved_4(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_4.lock().unwrap()))
    }

    #[bench]
    fn threads_interleaved_8(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_8.lock().unwrap()))
    }

    fn threads_chunked_n(pool: &mut PoolCache) {
        let size = 1024 * 1024 * 100 / 4; // 100MiB

        let n = pool.thread_count();
        let mut data = vec![0u32; size];
        pool.scope(|s| {
            let l = (data.len() - 1) / n as usize + 1;
            for es in data.chunks_mut(l) {
                s.execute(move || {
                    if es.len() > 1 {
                        es[0] = 1;
                        es[1] = 1;
                        for i in 2..es.len() {
                            // Fibonnaci gets big fast,
                            // so just wrap around all the time
                            es[i] = es[i-1].wrapping_add(es[i-2]);
                        }
                    }
                    //thread::sleep_ms(MS_SLEEP_PER_OP);
                });
            }
        });
    }

    #[bench]
    fn threads_chunked_1(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_1.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_2(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_2.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_3(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_3.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_4(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_4.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_5(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_5.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_8(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_8.lock().unwrap()))
    }
}
<commit_msg>Replace barrier with sync channels, thus making panicking work<commit_after>#![cfg_attr(all(feature="nightly", test), feature(test))]
#![cfg_attr(feature="nightly", feature(const_fn))]

#[macro_use]
#[cfg(test)]
extern crate lazy_static;

use std::thread::{self, JoinHandle};
use std::sync::mpsc::{channel, Sender, Receiver, SyncSender, sync_channel};
use std::sync::{Arc, Mutex};
use std::marker::PhantomData;

enum Message {
    NewJob(Thunk<'static>),
    Join,
}

trait FnBox {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce()> FnBox for F {
    fn call_box(self: Box<F>) {
        (*self)()
    }
}

type Thunk<'a> = Box<FnBox + Send + 'a>;

impl Drop for PoolCache {
    fn drop(&mut self) {
        ::std::mem::replace(&mut self.job_sender, None);
    }
}

pub struct PoolCache {
    threads: Vec<ThreadData>,
    job_sender: Option<Sender<Message>>
}

struct ThreadData {
    _thread_join_handle: JoinHandle<()>,
    pool_sync_rx: Receiver<()>,
    thread_sync_tx: SyncSender<()>,
}

impl PoolCache {
    pub fn new(n: u32) -> PoolCache {
        assert!(n >= 1);

        let (job_sender, job_receiver) = channel();
        let job_receiver = Arc::new(Mutex::new(job_receiver));

        let mut threads = Vec::with_capacity(n as usize);

        // spawn n threads, put them in waiting mode
        for _ in 0..n {
            let job_receiver = job_receiver.clone();

            let (pool_sync_tx, pool_sync_rx) =
                sync_channel::<()>(0);
            let (thread_sync_tx, thread_sync_rx) =
                sync_channel::<()>(0);

            let thread = thread::spawn(move || {
                loop {
                    let message = {
                        // Only lock jobs for the time it takes
                        // to get a job, not run it.
                        let lock = job_receiver.lock().unwrap();
                        lock.recv()
                    };

                    match message {
                        Ok(Message::NewJob(job)) => {
                            job.call_box();
                        }
                        Ok(Message::Join) => {
                            // syncronize with pool
                            if pool_sync_tx.send(()).is_err() {
                                // The pool was dropped.
                                break;
                            }
                            if thread_sync_rx.recv().is_err() {
                                // The pool was dropped.
                                break;
                            }
                        }
                        Err(..) => {
                            // The pool was dropped.
                            break
                        }
                    }
                }
            });

            threads.push(ThreadData {
                _thread_join_handle: thread,
                pool_sync_rx: pool_sync_rx,
                thread_sync_tx: thread_sync_tx,
            });
        }

        PoolCache {
            threads: threads,
            job_sender: Some(job_sender),
        }
    }

    pub fn scope<'pool, 'scope, F, R>(&'pool mut self, f: F) -> R
        where F: FnOnce(&Scope<'pool, 'scope>) -> R
    {
        let scope = Scope {
            pool: self,
            _marker: PhantomData,
        };
        f(&scope)
    }

    pub fn thread_count(&self) -> u32 {
        self.threads.len() as u32
    }
}

/////////////////////////////////////////////////////////////////////////////

pub struct Scope<'pool, 'scope> {
    pool: &'pool mut PoolCache,
    _marker: PhantomData<&'scope mut ()>,
}

impl<'pool, 'scope> Scope<'pool, 'scope> {
    pub fn execute<F>(&self, f: F)
        where F: FnOnce() + Send + 'scope
    {
        let b = unsafe {
            ::std::mem::transmute::<Thunk<'scope>, Thunk<'static>>(Box::new(f))
        };
        self.pool.job_sender.as_ref().unwrap().send(Message::NewJob(b)).unwrap();
    }
}

impl<'pool, 'scope> Drop for Scope<'pool, 'scope> {
    fn drop(&mut self) {
        for _ in 0..self.pool.threads.len() {
            self.pool.job_sender.as_ref().unwrap().send(Message::Join).unwrap();
        }

        // syncronize with threads
        for thread_data in &self.pool.threads {
            thread_data.pool_sync_rx.recv().unwrap();
        }
        for thread_data in &self.pool.threads {
            thread_data.thread_sync_tx.send(()).unwrap();
        }
    }
}

/////////////////////////////////////////////////////////////////////////////

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

    #[test]
    fn example() {
        // Create a threadpool holding 4 threads
        let mut pool = PoolCache::new(4);

        let mut vec = vec![0, 1, 2, 3, 4, 5, 6, 7];

        // Use the threads as scoped threads that can
        // reference anything outside this closure
        pool.scope(|scoped| {

            // Create references to each element in the vector ...
            for e in &mut vec {
                // ... and add 1 to it in a seperate thread
                scoped.execute(move || {
                    *e += 1;
                });
            }
        });

        assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7, 8]);
    }

    #[test]
    fn smoketest() {
        let mut pool = PoolCache::new(4);

        for i in 1..7 {
            let mut vec = vec![0, 1, 2, 3, 4];
            pool.scope(|s| {
                for e in vec.iter_mut() {
                    s.execute(move || {
                        *e += i;
                    });
                }
            });

            let mut vec2 = vec![0, 1, 2, 3, 4];
            for e in vec2.iter_mut() {
                *e += i;
            }

            assert_eq!(vec, vec2);
        }
    }

    #[test]
    #[should_panic]
    fn panicking() {
        let mut pool = PoolCache::new(4);
        pool.scope(|scoped| {
            scoped.execute(move || {
                panic!()
            });
        });
    }
}

#[cfg(all(test, feature="nightly"))]
mod benches {
    extern crate test;

    use self::test::{Bencher, black_box};
    use super::PoolCache;
    use std::sync::Mutex;

    // const MS_SLEEP_PER_OP: u32 = 1;

    lazy_static! {
        static ref POOL_1: Mutex<PoolCache> = Mutex::new(PoolCache::new(1));
        static ref POOL_2: Mutex<PoolCache> = Mutex::new(PoolCache::new(2));
        static ref POOL_3: Mutex<PoolCache> = Mutex::new(PoolCache::new(3));
        static ref POOL_4: Mutex<PoolCache> = Mutex::new(PoolCache::new(4));
        static ref POOL_5: Mutex<PoolCache> = Mutex::new(PoolCache::new(5));
        static ref POOL_8: Mutex<PoolCache> = Mutex::new(PoolCache::new(8));
    }

    fn fib(n: u64) -> u64 {
        let mut prev_prev: u64 = 1;
        let mut prev = 1;
        let mut current = 1;
        for _ in 2..(n+1) {
            current = prev_prev.wrapping_add(prev);
            prev_prev = prev;
            prev = current;
        }
        current
    }

    fn threads_interleaved_n(pool: &mut PoolCache)  {
        let size = 1024; // 1kiB

        let mut data = vec![1u8; size];
        pool.scope(|s| {
            for e in data.iter_mut() {
                s.execute(move || {
                    *e += fib(black_box(1000 * (*e as u64))) as u8;
                    //thread::sleep_ms(MS_SLEEP_PER_OP);
                });
            }
        });
    }

    #[bench]
    fn threads_interleaved_1(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_1.lock().unwrap()))
    }

    #[bench]
    fn threads_interleaved_2(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_2.lock().unwrap()))
    }

    #[bench]
    fn threads_interleaved_4(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_4.lock().unwrap()))
    }

    #[bench]
    fn threads_interleaved_8(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_8.lock().unwrap()))
    }

    fn threads_chunked_n(pool: &mut PoolCache) {
        let size = 1024 * 1024 * 100 / 4; // 100MiB

        let n = pool.thread_count();
        let mut data = vec![0u32; size];
        pool.scope(|s| {
            let l = (data.len() - 1) / n as usize + 1;
            for es in data.chunks_mut(l) {
                s.execute(move || {
                    if es.len() > 1 {
                        es[0] = 1;
                        es[1] = 1;
                        for i in 2..es.len() {
                            // Fibonnaci gets big fast,
                            // so just wrap around all the time
                            es[i] = es[i-1].wrapping_add(es[i-2]);
                        }
                    }
                    //thread::sleep_ms(MS_SLEEP_PER_OP);
                });
            }
        });
    }

    #[bench]
    fn threads_chunked_1(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_1.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_2(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_2.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_3(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_3.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_4(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_4.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_5(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_5.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_8(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_8.lock().unwrap()))
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate rustc_serialize;

use iron::headers::ContentType;
use iron::prelude::*;
use iron::status;
use diesel::prelude::*;
use rustc_serialize::json;
use database;

pub fn index(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "Welcome to Lugh API!")))
}

pub fn translations(_: &mut Request) -> IronResult<Response> {
    use schema::translations::dsl::*;
    use models::*;

    let connection = database::establish_connection();
    let results = translations.load::<Translation>(&connection)
        .expect("Error loading translations");

    println!("Returns {} translations", results.len());

    let payload = json::encode(&results).unwrap();

    Ok(Response::with((ContentType::json().0, status::Ok, payload)))
}
<commit_msg>Select last translation inserted for each key/locale pair<commit_after>extern crate iron;
extern crate rustc_serialize;

use iron::headers::ContentType;
use iron::prelude::*;
use iron::status;
use diesel::prelude::*;
use rustc_serialize::json;
use database;

pub fn index(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "Welcome to Lugh API!")))
}

pub fn translations(_: &mut Request) -> IronResult<Response> {
    use diesel::expression::dsl::sql;
    use models::*;
    use schema::translations::dsl::*;

    let connection = database::establish_connection();
    let results = translations.filter(sql("id IN (SELECT MAX(id) FROM translations GROUP BY key, locale)"))
        .load::<Translation>(&connection)
        .expect("Error loading translations");

    println!("Returns {} translations", results.len());

    let payload = json::encode(&results).unwrap();

    Ok(Response::with((ContentType::json().0, status::Ok, payload)))
}
<|endoftext|>


<commit_before>/// The API for communicating with devices.

use devices::*;

pub enum Error {
    /// There is no such hub connected to the Foxbox, even indirectly.
    NoSuchHub(HubId),

    /// There is no such endpoint connected to the Foxbox, even indirectly.
    NoSuchEndPoint(EndPointId),

    /// Attempting to set a value with the wrong type
    TypeError,
}

pub struct Value; // FIXME: Define

pub trait Env {
    type Witness;

    ///
    /// # Global API
    ///

    /// Get a snapshot of the entire tree.
    fn get_snapshot(&self) -> Hub;

    ///
    /// # Per hub API
    ///

    fn put_hub_tag(&self, &HubId, String) -> Result<(), Error>;
    fn delete_hub_tag(&self, &HubId, String) -> Result<(), Error>;
    fn get_hub(&self, &HubId) -> Result<Hub, Error>;

    ///
    /// # Per endpoint API
    ///

    fn get_input_endpoint(&self, &EndPointId) -> Result<EndPoint<Input>, Error>;
    fn get_output_endpoint(&self, &EndPointId) -> Result<EndPoint<Output>, Error>;

    fn get_endpoint_value(&self, &EndPoint<Input>) -> Result<Value, Error>;
    fn put_endpoint_value(&self, &EndPoint<Output>, Value) -> Result<(), Error>;

    fn register_watch<F>(&self, &EndPoint<Input>, cb: F) -> Result<Self::Witness, Error>
        where F: Fn(Value) + Send;
}

<commit_msg>API: requests<commit_after>//!
//! The API for communicating with devices.
//!
//! This API is provided as Trait to be implemented:
//!
//! - by the low-level layers of the FoxBox, including the adapters;
//! - by test suites and tools that need to simulate connected devices.
//!
//! In turn, this API is used to implement:
//!
//! - the public-facing REST and WebSocket API;
//! - the rules API (ThinkerBell).
//!
//!

use devices::*;

use std::time::Duration;

pub enum Error {
    /// There is no such hub connected to the Foxbox, even indirectly.
    NoSuchHub(HubId),

    /// There is no such endpoint connected to the Foxbox, even indirectly.
    NoSuchEndPoint(EndPointId),

    /// Attempting to set a value with the wrong type
    TypeError,
}

pub struct Value; // FIXME: Define

/// The public API.
pub trait API {
    /// The subset of the API dedicated to hubs.
    type HubAPI: HubAPI;
    fn get_hub_api(&self) -> Self::HubAPI;

    /// The subset of the API dedicated to endpoints.
    type EndPointAPI: EndPointAPI;
    fn get_endpoint_api(&self) -> Self::EndPointAPI;
}

// FIXME: We should probably use traits for building requests, as this
// will be more future-proof.
/// A request for one or more hubs.

pub struct HubRequest {
    /// If `Some(id)`, return only the hub with the corresponding id.
    pub id: Option<HubId>,

    ///  Restrict results to hubs that have all the tags in `tags`.
    pub tags: Vec<String>,

    /// Restrict results to hubs that have all the inputs in `inputs`.
    pub inputs: Vec<InputRequest>,

    /// Restrict results to hubs that have all the outputs in `outputs`.
    pub outputs: Vec<OutputRequest>,
}

pub struct Period {
    pub min: Option<Duration>,
    pub max: Option<Duration>,
}

pub struct InputRequest {
    /// If `Some(id)`, return only the endpoint with the corresponding id.
    pub id: Option<EndPointId>,

    /// If `Some(id)`, return only endpoints that are immediate children
    /// of hub `id`.
    pub parent: Option<HubId>,

    /// If `Some(id)`, return only endpoints that are descendants of hub
    /// `id`.
    pub ancestor: Option<HubId>,

    ///  Restrict results to endpoints that have all the tags in `tags`.
    pub tags: Vec<String>,

    /// If `Some(k)`, restrict results to endpoints that produce values
    /// of kind `k`.
    pub kind: Option<ValueKind>,

    /// If `Some(r)`, restrict results to endpoints that support polling
    /// with the acceptable period.
    pub poll: Option<Period>,

    /// If `Some(r)`, restrict results to endpoints that support trigger
    /// with the acceptable period.
    pub trigger: Option<Period>,
}

pub struct OutputRequest {
    /// If `Some(id)`, return only the endpoint with the corresponding id.
    pub id: Option<EndPointId>,

    /// If `Some(id)`, return only endpoints that are immediate children
    /// of hub `id`.
    pub parent: Option<HubId>,

    /// If `Some(id)`, return only endpoints that are descendants of hub
    /// `id`.
    pub ancestor: Option<HubId>,

    ///  Restrict results to endpoints that have all the tags in `tags`.
    pub tags: Vec<String>,

    /// If `Some(k)`, restrict results to endpoints that accept values
    /// of kind `k`.
    pub kind: Option<ValueKind>,

    /// If `Some(r)`, restrict results to endpoints that support pushing
    /// with the acceptable period.
    pub push: Option<Period>,
}

///
/// Hub-level API
///
pub trait HubAPI {
    /// Get a list of hubs matching some conditions
    ///
    /// # REST API
    ///
    /// GET /api/v1/hub/list
    fn get_list(&self, &HubRequest) -> Vec<Hub>;

    /// Add a tag to an existing hub.
    ///
    /// Tags can be used to locate hubs.
    ///
    /// # REST API
    ///
    /// PUT /api/v1/hub/tag/$HubId
    fn put_tag(&self, &HubId, String) -> Result<(), Error>;

    /// Add a tag to an existing hub.
    ///
    /// Tags can be used to locate hubs.
    ///
    /// # REST API
    ///
    /// DELETE /api/v1/hub/tag/$HubId
    fn delete_tag(&self, &HubId, String) -> Result<(), Error>;
}

///
/// Endpoint-level API
///
pub trait EndPointAPI {
    /// A value that causes a disconnection once it is dropped.
    type Guard;

    /// Get a list of inputs matching some conditions
    ///
    /// # REST API
    ///
    /// GET /api/v1/endpoint/list
    fn get_input_endpoints(&self, &InputRequest) -> Vec<EndPoint<Input>>;
    fn get_output_endpoints(&self, &OutputRequest) -> Vec<EndPoint<Output>>;

    /// Add a tag to an existing endpoint.
    ///
    /// Tags can be used to locate endpoint.
    ///
    /// # REST API
    ///
    /// PUT /api/v1/endpoint/tag/$EndPointId
    fn put_tag(&self, &EndPointId, String) -> Result<(), Error>;

    /// Add a tag to an existing endpoint.
    ///
    /// Tags can be used to locate endpoints.
    ///
    /// # REST API
    ///
    /// DELETE /api/v1/endpoint/tag/$EndPointId
    fn delete_tag(&self, &EndPointId, String) -> Result<(), Error>;

    /// Read one value from an input enpoint
    ///
    /// # REST API
    ///
    /// GET /api/v1/endpoint/value/$EndpointId
    fn get_endpoint_value(&self, &EndPoint<Input>) -> Result<Value, Error>;

    /// Send one value to an output enpoint
    ///
    /// # REST API
    ///
    /// PUT /api/v1/endpoint/value/$EndpointId
    fn put_endpoint_value(&self, &EndPoint<Output>, Value) -> Result<(), Error>;

    /// Watch for any change
    // FIXME: Optional argument.
    fn register_watch<F>(&self, &EndPoint<Input>, cb: F) -> Result<Self::Guard, Error>
        where F: Fn(Value) + Send;
}

<|endoftext|>


<commit_before>//! This crate provides an API for talking to repositories that implement The Update Framework
//! (TUF).
//!
//! If you are unfamiliar with TUF, you should read up on it via the [official
//! website](http://theupdateframework.github.io/). This crate aims to implement the entirety of
//! the specification as defined at the [head of the `develop`
//! branch](https://github.com/theupdateframework/tuf/blob/develop/docs/tuf-spec.txt) in the
//! official TUF git repository.
//!
//! Additionally, the following two papers are valuable supplements in understanding how to
//! actually implement TUF for a community repository.
//!
//! - [The Diplomat paper
//! (2016)](https://www.usenix.org/conference/nsdi16/technical-sessions/presentation/kuppusamy)
//! - [The Mercury paper
//! (2017)](https://www.usenix.org/conference/atc17/technical-sessions/presentation/kuppusamy)
//!
//! Failure to read the spec and the above papers will likely lead to an implementation that does
//! not take advantage of all the security guarantees that TUF offers.
//!
//! # Interoperability
//!
//! It should be noted that historically the TUF spec defined exactly one metadata format and one
//! way of organizing metadata within a repository. Thus, all TUF implementation could perfectly
//! interoperate. The TUF spec has moved to describing *how a framework should behave* leaving many
//! of the detais up to the implementor. Therefore, there are **zero** guarantees that this library
//! will work with any other TUF implementation. Should you want to access a TUF repository that
//! uses `rust-tuf` as its backend from another language, ASN.1 modules and metadata schemas are
//! provided that will allow you to interoperate with this library.
//!
//! # Implementation Considerations
//!
//! ## Key Management
//!
//! Part of TUF is that it acts as its own PKI, and there is no integration that needs to be done
//! for managing keys.
//!
//! Note: No two private keys that are generated should ever exist on the same hardware. When a
//! step says "generate `N` keys," the implication is that these `N` keys are generated on `N`
//! devices.
//!
//! The first set of keys that need to be generated at the root keys that are used to sign the root
//! metadata. The root should be defined with the following properties:
//!
//! - Minimum:
//!   - 3 keys
//!   - threshold of 2
//! - Recommended:
//!   - 5 keys
//!   - threshold of 3
//!
//! If a threshold of root keys are compromised, then the entire system is compromised and TUF
//! clients will need to be manually updated. Similarly, if some `X` keys are lost such that the
//! threshold `N` cannot be reached, then clients will also need to be manually updated. Both of
//! situations are considered critically unsafe. Whatever number of keys are used, it should be
//! assumed that some small number may be lost or compromised.
//!
//! These root keys should be kept offline on secure media.
//!
//! ## Delegations
//!
//! TUF's most useful feature is the ability to delegate certain roles to sign certain targets.
//! This is discussed in extensive detail in the aforementioned Diplomat paper. There are three
//! problems faced when delegating trust in TUF:
//!
//! 1. What to do for existent accounts that have not yet created and signed TUF metadata
//! 2. What to do when a new account registers
//! 3. What to do when an account uploads a new target and new metadata
//!
//! There are several approaches for dealing with the above scenarios. We are only going to discuss
//! on here as it is the recommended approach. This approach is taken directly from Section 6.1 of
//! he Diplomat paper
//!
//! ### Maximum Security Model
//!
//! The top-level targets role delegates to three other roles and are listed in the following order:
//!
//! 1. `claimed-projects`
//!   - `terminating: true`
//!   - Delegates to project-specific roles that have registered keys with TUF
//! 2. `rarely-updated-projects`
//!   - `terminating: true`
//!   - Signs all packages for all projects that have been "abandoned" or left unupdated for a long
//!   time AND have not yet registered keys with TUF
//! 3. `new-projects`
//!   - `terminating: false`
//!   - Signs all packages for all new projects as well as projects that were relegated to
//!   `rarely-updated-projects`
//!
//! The top-level `targets` role as well as `claimed-projects` and `rarely-updated-projects`
//! **MUST** all use offline keys.
//!
//! The critical, manual step is to register new projects with TUF keys and move them into the
//! `claimed-projects` role. Projects that refuse to register keys should have their packages
//! periodically moved into the `rarely-updated-projects` role. Projects in either of these two
//! roles are safe from compromise as their keys are offline. Since the keys used for the above
//! operation are kept offline, this is periodic, manual process.
//!
//! ## Snapshot & Timestamp
//!
//! In a community repository, these two keys need to be kept online and will be used to sign new
//! metadata on every update.

#![deny(missing_docs)]

extern crate chrono;
extern crate data_encoding;
extern crate derp;
extern crate hyper;
extern crate itoa;
#[cfg(test)]
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[cfg(test)]
#[macro_use]
extern crate maplit;
extern crate ring;
extern crate serde;
#[macro_use]
extern crate serde_derive;

#[cfg(not(test))]
extern crate serde_json as json;
#[cfg(test)]
#[macro_use]
extern crate serde_json as json;

#[cfg(test)]
extern crate tempdir;
extern crate tempfile;
extern crate url;
extern crate untrusted;
extern crate uuid;

pub mod error;

/// Alias for `Result<T, Error>`.
pub type Result<T> = ::std::result::Result<T, Error>;

pub mod client;
pub mod crypto;
pub mod interchange;
pub mod metadata;
pub mod repository;
mod shims;
pub mod tuf;
mod util;

pub use error::*;
pub use tuf::*;
pub use util::*;
<commit_msg>minor deployment docs edits<commit_after>//! This crate provides an API for talking to repositories that implement The Update Framework
//! (TUF).
//!
//! If you are unfamiliar with TUF, you should read up on it via the [official
//! website](http://theupdateframework.github.io/). This crate aims to implement the entirety of
//! the specification as defined at the [head of the `develop`
//! branch](https://github.com/theupdateframework/tuf/blob/develop/docs/tuf-spec.txt) in the
//! official TUF git repository.
//!
//! Additionally, the following two papers are valuable supplements in understanding how to
//! actually implement TUF for a community repository.
//!
//! - [The Diplomat paper
//! (2016)](https://www.usenix.org/conference/nsdi16/technical-sessions/presentation/kuppusamy)
//! - [The Mercury paper
//! (2017)](https://www.usenix.org/conference/atc17/technical-sessions/presentation/kuppusamy)
//!
//! Failure to read the spec and the above papers will likely lead to an implementation that does
//! not take advantage of all the security guarantees that TUF offers.
//!
//! # Interoperability
//!
//! It should be noted that historically the TUF spec defined exactly one metadata format and one
//! way of organizing metadata within a repository. Thus, all TUF implementation could perfectly
//! interoperate. The TUF spec has moved to describing *how a framework should behave* leaving many
//! of the detais up to the implementor. Therefore, there are **zero** guarantees that this library
//! will work with any other TUF implementation. Should you want to access a TUF repository that
//! uses `rust-tuf` as its backend from another language, ASN.1 modules and metadata schemas are
//! provided that will allow you to interoperate with this library.
//!
//! # Implementation Considerations
//!
//! ## Key Management
//!
//! Part of TUF is that it acts as its own PKI, and there is no integration that needs to be done
//! for managing keys.
//!
//! Note: No two private keys that are generated should ever exist on the same hardware. When a
//! step says "generate `N` keys," the implication is that these `N` keys are generated on `N`
//! devices.
//!
//! The first set of keys that need to be generated at the root keys that are used to sign the root
//! metadata. The root should be defined with the following properties:
//!
//! - Minimum:
//!   - 3 keys
//!   - threshold of 2
//! - Recommended:
//!   - 5 keys
//!   - threshold of 3
//!
//! If a threshold of root keys are compromised, then the entire system is compromised and TUF
//! clients will need to be manually updated. Similarly, if some `X` keys are lost such that the
//! threshold `N` cannot be reached, then clients will also need to be manually updated. Both of
//! situations are considered critically unsafe. Whatever number of keys are used, it should be
//! assumed that some small number may be lost or compromised.
//!
//! These root keys **MUST** be kept offline on secure media.
//!
//! ## Delegations
//!
//! TUF's most useful feature is the ability to delegate certain roles to sign certain targets.
//! This is discussed in extensive detail in the aforementioned Diplomat paper. There are three
//! problems faced when delegating trust in TUF:
//!
//! 1. What to do for existent accounts that have not yet created and signed TUF metadata
//! 2. What to do when a new account registers
//! 3. What to do when an account uploads a new target and new metadata
//!
//! There are several approaches for dealing with the above scenarios. We are only going to discuss
//! on here as it is the recommended approach. This approach is taken directly from Section 6.1 of
//! the Diplomat paper
//!
//! ### Maximum Security Model
//!
//! The top-level targets role delegates to three other roles and are listed in the following order:
//!
//! 1. `claimed-projects`
//!   - `terminating: true`
//!   - Delegates to project-specific roles that have registered keys with TUF
//! 2. `rarely-updated-projects`
//!   - `terminating: true`
//!   - Signs all packages for all projects that have been "abandoned" or left unupdated for a long
//!   time AND have not yet registered keys with TUF
//! 3. `new-projects`
//!   - `terminating: false`
//!   - Signs all packages for all new projects as well as projects that were relegated to
//!   `rarely-updated-projects`
//!
//! The top-level `targets` role as well as `claimed-projects` and `rarely-updated-projects`
//! **MUST** all use offline keys.
//!
//! The critical, manual step is to register new projects with TUF keys and move them into the
//! `claimed-projects` role. Projects that refuse to register keys should have their packages
//! periodically moved into the `rarely-updated-projects` role. Projects in either of these two
//! roles are safe from compromise as their keys are offline. Since the keys used for the above
//! operation are kept offline, this is periodic, manual process.
//!
//! ## Snapshot & Timestamp
//!
//! In a community repository, these two keys need to be kept online and will be used to sign new
//! metadata on every update.

#![deny(missing_docs)]

extern crate chrono;
extern crate data_encoding;
extern crate derp;
extern crate hyper;
extern crate itoa;
#[cfg(test)]
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[cfg(test)]
#[macro_use]
extern crate maplit;
extern crate ring;
extern crate serde;
#[macro_use]
extern crate serde_derive;

#[cfg(not(test))]
extern crate serde_json as json;
#[cfg(test)]
#[macro_use]
extern crate serde_json as json;

#[cfg(test)]
extern crate tempdir;
extern crate tempfile;
extern crate url;
extern crate untrusted;
extern crate uuid;

pub mod error;

/// Alias for `Result<T, Error>`.
pub type Result<T> = ::std::result::Result<T, Error>;

pub mod client;
pub mod crypto;
pub mod interchange;
pub mod metadata;
pub mod repository;
mod shims;
pub mod tuf;
mod util;

pub use error::*;
pub use tuf::*;
pub use util::*;
<|endoftext|>


<commit_before>pub enum GTPError {
    NotImplemented,
    InvalidBoardSize,
    InvalidMove,
    BadVertexList,
    BoardNotEmpty,
    CannotUndo,
}

pub enum Colour {
    Black,
    White
}

#[allow(dead_code)]
pub struct Vertex {
    x: int, // letter
    y: int  // number
}

pub enum Move {
    Stone(Vertex),
    Pass,
    Resign
}

#[allow(dead_code)]
pub struct ColouredMove {
    player: Colour,
    move: Move
}

pub enum StoneStatus {
    Alive,
    Seki,
    Dead
}

pub trait GoBot {
    // Static functions identifying the bot :

    // name (ex : "My super Bot")
    fn gtp_name() -> &'static str;
    // version (ex : "v2.3-r5")
    fn gtp_version() -> &'static str;

    // Any function returning a GTPError that it is not supposed
    // to return will be fatal to the framework.

    // Basic functions, must be implemented

    // clear_board : clears the board, can never fail
    fn gtp_clear_board(&self) -> ();
    // komi : sets the komi, can never fail, must accept absurd values
    fn gtp_komi(&self, komi: f32) -> ();
    // boardsize : sets the board size.
    // Returns InvalidBoardSize if the size is not supported.
    fn gtp_boardsize(&self, size: uint) -> Result<(), GTPError>;
    // play : plays the provided move on the board
    // Returns InvalidMove is the move is invalid
    fn gtp_play(&self, move: ColouredMove) -> Result<(), GTPError>;
    // genmove : ask the bot for a move of the chosen color
    // cannot fail, the bot must provide a move even if the last
    // played move is of the same colour
    fn gtp_genmove(&self, player: Colour) -> Move;

    // Optional functions, if not iplemented, the corresponding
    // commands will not be activated
    // All these functions will be called once by the framework
    // at startup, then clear_board will be called

    // genmove_determinisic : like genmove, but must be deterministic
    // if genmove is already deterministic, can be aliased to it
    // should always return Ok(Move), never raise any error
    #[allow(unused_variable)]
    fn gtp_genmove_deterministic(&self, player: Colour) -> Result<Move, GTPError> {
        Err(NotImplemented)
    }
    // undo : undo last move if possible
    // if not, return Err(CannotUndo)
    // if undo is never possible, should not be implemented
    #[allow(unused_variable)]
    fn gtp_undo(&self) -> Result<(), GTPError> {
        Err(NotImplemented)
    }
    // place_free_handicap : The bot places its handicap stones
    // and returns a slice to a vector of Vertexes
    // it can place less stones if the asked number is too high
    // fails with Err(BoardNotEmpty) if board isn't empty
    #[allow(unused_variable)]
    fn gtp_place_free_handicap(&self, number: uint) -> Result<&[Vertex], GTPError> {
        Err(NotImplemented)
    }
    // set_free_handicap : uses the provided list as handicap stones
    // for black
    // fails with Err(BoardNotEmpty) if board isn't empty
    // fails woth Err(BadVertexList) if the vertex list is unusable
    // (two stones at the same place, or stones outside the board)
    #[allow(unused_variable)]
    fn gtp_set_free_handicap(&self, stones: &[Vertex]) -> Result<(), GTPError> {
        Err(NotImplemented)
    }
    // time_settings : sets the time settings for the game
    // it is only informative, the btot should count it's own time,
    // but the controller is supposed to enforce it
    // time are give in minute, should never fail
    #[allow(unused_variable)]
    fn gtp_time_settings(&self, main_time: int, byoyomi_time: int, byoyomi_stones: int) -> Result<(), GTPError> {
        Err(NotImplemented)
    }
    // final_status_list : returns a slice to the list of stones of
    // any color in the given status, in the opinion of the bot
    // should never fail
    #[allow(unused_variable)]
    fn gtp_final_status_list(&self, status: StoneStatus) -> Result<(), GTPError> {
        Err(NotImplemented)
    }
    // final_score : computes the bot's calculation of the final score
    // if it is a draw, float value must be 0 and colour is not important
    // should never fail
    #[allow(unused_variable)]
    fn gtp_final_score(&self) -> Result<(f32, Colour), GTPError> {
        Err(NotImplemented)
    }
    // showboard : returns a description of the board as saw by the bot :
    // (boardsize, black_stones, white_stones, black_captured_count, white_captured_count)
    // should never fail
    #[allow(unused_variable)]
    fn gtp_showboard(&self) -> Result<(int, &[Vertex], &[Vertex], int, int), GTPError> {
        Err(NotImplemented)
    }
}
<commit_msg>Corrections to API.<commit_after>pub enum GTPError {
    NotImplemented,
    InvalidBoardSize,
    InvalidMove,
    BadVertexList,
    BoardNotEmpty,
    CannotUndo,
}

pub enum Colour {
    Black,
    White
}

#[allow(dead_code)]
pub struct Vertex {
    x: u8, // letter
    y: u8  // number
}

pub enum Move {
    Stone(Vertex),
    Pass,
    Resign
}

#[allow(dead_code)]
pub struct ColouredMove {
    player: Colour,
    move: Move
}

pub enum StoneStatus {
    Alive,
    Seki,
    Dead
}

pub trait GoBot {
    // Static functions identifying the bot :

    // name (ex : "My super Bot")
    fn gtp_name() -> &'static str;
    // version (ex : "v2.3-r5")
    fn gtp_version() -> &'static str;

    // Any function returning a GTPError that it is not supposed
    // to return will be fatal to the framework.

    // Basic functions, must be implemented

    // clear_board : clears the board, can never fail
    fn gtp_clear_board(&mut self) -> ();
    // komi : sets the komi, can never fail, must accept absurd values
    fn gtp_komi(&mut self, komi: f32) -> ();
    // boardsize : sets the board size.
    // Returns InvalidBoardSize if the size is not supported.
    fn gtp_boardsize(&mut self, size: uint) -> Result<(), GTPError>;
    // play : plays the provided move on the board
    // Returns InvalidMove is the move is invalid
    fn gtp_play(&mut self, move: ColouredMove) -> Result<(), GTPError>;
    // genmove : ask the bot for a move of the chosen color
    // cannot fail, the bot must provide a move even if the last
    // played move is of the same colour
    // plays the move as well
    fn gtp_genmove(&mut self, player: Colour) -> Move;

    // Optional functions, if not iplemented, the corresponding
    // commands will not be activated
    // All these functions will be called once by the framework
    // at startup, then clear_board will be called

    // genmove_regression : like genmove, but must be deterministic
    // and must not actually play the move
    // should always return Ok(Move), never raise any error
    #[allow(unused_variable)]
    fn gtp_genmove_regression(&self, player: Colour) -> Result<Move, GTPError> {
        Err(NotImplemented)
    }
    // undo : undo last move if possible
    // if not, return Err(CannotUndo)
    // if undo is never possible, should not be implemented
    #[allow(unused_variable)]
    fn gtp_undo(&mut self) -> Result<(), GTPError> {
        Err(NotImplemented)
    }
    // place_free_handicap : The bot places its handicap stones
    // and returns a slice to a vector of Vertexes
    // it can place less stones if the asked number is too high
    // fails with Err(BoardNotEmpty) if board isn't empty
    #[allow(unused_variable)]
    fn gtp_place_free_handicap(&mut self, number: uint) -> Result<&[Vertex], GTPError> {
        Err(NotImplemented)
    }
    // set_free_handicap : uses the provided list as handicap stones
    // for black
    // fails with Err(BoardNotEmpty) if board isn't empty
    // fails woth Err(BadVertexList) if the vertex list is unusable
    // (two stones at the same place, or stones outside the board)
    #[allow(unused_variable)]
    fn gtp_set_free_handicap(&mut self, stones: &[Vertex]) -> Result<(), GTPError> {
        Err(NotImplemented)
    }
    // time_settings : sets the time settings for the game
    // it is only informative, the btot should count it's own time,
    // but the controller is supposed to enforce it
    // time are give in minute, should never fail
    #[allow(unused_variable)]
    fn gtp_time_settings(&mut self, main_time: int, byoyomi_time: int, byoyomi_stones: int) -> Result<(), GTPError> {
        Err(NotImplemented)
    }
    // final_status_list : returns a slice to the list of stones of
    // any color in the given status, in the opinion of the bot
    // should never fail
    #[allow(unused_variable)]
    fn gtp_final_status_list(&self, status: StoneStatus) -> Result<(), GTPError> {
        Err(NotImplemented)
    }
    // final_score : computes the bot's calculation of the final score
    // if it is a draw, float value must be 0 and colour is not important
    // should never fail
    #[allow(unused_variable)]
    fn gtp_final_score(&self) -> Result<(f32, Colour), GTPError> {
        Err(NotImplemented)
    }
    // showboard : returns a description of the board as saw by the bot :
    // (boardsize, black_stones, white_stones, black_captured_count, white_captured_count)
    // should never fail
    #[allow(unused_variable)]
    fn gtp_showboard(&self) -> Result<(int, &[Vertex], &[Vertex], int, int), GTPError> {
        Err(NotImplemented)
    }
}
<|endoftext|>


<commit_before>#![recursion_limit = "1024"]

use syn::spanned::Spanned;

#[macro_use]
extern crate quote;
extern crate proc_macro;
extern crate syn;
extern crate fibers;
extern crate futures;

use proc_macro::TokenStream;

use quote::{TokenStreamExt, ToTokens};
use syn::{ImplItem, Visibility, FnArg};

#[proc_macro_attribute]
pub fn derive_actor(args: TokenStream, item: TokenStream) -> TokenStream
{
    let o_item = item.clone();
    let input: syn::ItemImpl = syn::parse_macro_input!(item as syn::ItemImpl);
    let o_input: syn::ItemImpl = syn::parse_macro_input!(o_item as syn::ItemImpl);

    let attrs = input.attrs;
    let defaultness = input.defaultness;
    let unsafety = input.unsafety;
    let impl_token = input.impl_token;
    let generics = input.generics;
    let ttrait = input.trait_;
    let self_ty = input.self_ty;
    let brace_token = input.brace_token;
    let items: Vec<ImplItem> = input.items;

    let mut actor_methods = quote!();

    let type_name = format!("{}", quote!(#self_ty));

    let type_name: &str = type_name.split("<").next().unwrap_or(&type_name);
    let type_name = type_name.trim();

    let actor_ty = syn::Ident::new(&format!("{}Actor", type_name), self_ty.span());
    let message_ty = syn::Ident::new(&format!("{}Message", type_name), self_ty.span());
    let router_ty = syn::Ident::new(&format!("{}Router", type_name), self_ty.span());

    let all_generics = method_generics(items.clone());
    let all_generic_tys = method_generic_tys(items.clone());

    let message_variants = gen_message_variants(items.clone());

    for item in items.clone() {
        if let ImplItem::Method(method) = item {
            if let Visibility::Public(vis) = method.vis {
                let sig = method.sig.clone();
                let ident = method.sig.ident;

                let mut args = quote![];
                let mut arg_and_tys = quote![];

                for arg in method.sig.decl.inputs {
                    let arg: FnArg = arg;
                    match arg {
                        FnArg::Captured(arg) => {
                            let arg_name = arg.pat;
                            let arg_ty = arg.ty;

                            args.extend(quote!(#arg_name ,));
                            arg_and_tys.extend(quote!(#arg_name : #arg_ty, ));

                        }
                        _ => {
                            continue
                        }
                    }
                }

                let actor_method = quote!(
                    pub fn #ident (&self, #arg_and_tys) {

                        let msg = #message_ty :: #ident { #args };

                        tokio::spawn(self.sender.clone().send(msg).map(|_|()).map_err(|_|()));
                    }
                );

                actor_methods.extend(actor_method);
            }
        }
    }

    let mut route_arms = quote!();

    for item in items.clone() {
        if let ImplItem::Method(method) = item {
            if let Visibility::Public(vis) = method.vis {
                let ident = method.sig.ident;

                let mut args = quote![];

                for arg in method.sig.decl.inputs {
                    let arg: FnArg = arg;
                    match arg {
                        FnArg::Captured(arg) => {
                            let arg_name = arg.pat;

                            args.extend(quote!(#arg_name, ));

                        }
                        _ => {
                            continue
                        }
                    }
                }

                let arm = quote!(
                #message_ty :: #ident { #args }
                    => self. #ident (#args),
                );

                route_arms.extend(arm);
            }
        }
    }

    // Generate generics for the enum

    let result = quote! {
        #o_input
        // Message

        pub enum #message_ty #all_generics {
            #message_variants
        }

        // route_msg impl
        impl #self_ty {
            pub fn route_message #all_generics (&mut self, msg: #message_ty #all_generic_tys ) {
                match msg {
                    #route_arms
                };
            }
        }

        // Actor Struct
        #[derive(Clone)]
        pub struct #actor_ty #all_generics {
            sender: Sender<#message_ty #all_generic_tys>,
        }
        // Actor Impl block
        #impl_token #all_generics #actor_ty #all_generic_tys {
            pub fn new(actor_impl: #self_ty) -> Self {
                let (sender, receiver) = channel(0);
                let id = "random string".to_owned();

                tokio::spawn(#router_ty {
                    receiver,
                    id,
                    actor_impl
                });

                Self {
                    sender
                }
            }

            #actor_methods
        }

        // Router Struct

        pub struct #router_ty #all_generics {
            receiver: Receiver<#message_ty #all_generic_tys>,
            id: String,
            actor_impl: #self_ty

        }

        // Router Future impl

        impl #all_generics Future for #router_ty #all_generic_tys {
            type Item = ();
            type Error = ();

            fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
                match self.receiver.poll() {
                    Ok(Async::Ready(Some(msg))) => {
                        task::current().notify(); // we should poll on receiver again

                        self.actor_impl.route_message(msg);
                        Ok(Async::NotReady)
                    },
                    Ok(Async::Ready(None)) => {
                        self.receiver.close();

                        Ok(Async::Ready(())) // we're done; disconnect
                    },
                    _ => {
                        Ok(Async::NotReady)
                    }
                }
            }
        }

    };

    println!("{}", result.to_string());

    result.into()
}

fn capitalize(s: &str) -> String {
    let char_0 = &s[0..1].to_uppercase();

    format!("{}{}", char_0, &s[1..])
}

fn gen_message_variants(items: Vec<ImplItem>) -> impl quote::ToTokens {
    let mut message_variants = quote!();
    for item in items {
        if let ImplItem::Method(method) = item {
            if let Visibility::Public(vis) = method.vis {

                let ident = method.sig.ident;

                let mut args = quote![];

                for arg in method.sig.decl.inputs {
                    let arg: FnArg = arg;
                    match arg {
                        FnArg::SelfRef(_) | FnArg::SelfValue(_) => {
                            continue
                        }
                        arg => args.extend(quote!(#arg, ))
                    }
                }

                let variant = quote!(
                    #ident {
                        #args
                    }
                );

                message_variants.extend(variant);
            }
        }
    }

    message_variants
}

fn method_generics(items: Vec<ImplItem>) -> impl quote:: ToTokens {
    let mut generic_types = quote!();
    for item in items {

        if let ImplItem::Method(method) = item {
            if let Visibility::Public(vis) = method.vis {
                let generics = method.sig.decl.generics;
                generic_types.extend(quote!(#generics));
            }
        }
    }

//    println!("{}", generic_types.to_string());

    generic_types
}

fn method_generic_tys(items: Vec<ImplItem>) -> impl quote:: ToTokens {
    let mut generic_types = quote!();
    for item in items {

        if let ImplItem::Method(method) = item {
            if let Visibility::Public(vis) = method.vis {
                let mut generics = method.sig.decl.generics;
                let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
                generic_types.extend(quote!(#ty_generics));
            }
        }
    }

//    println!("{}", generic_types.to_string());

    generic_types
}
<commit_msg>Update lib.rs<commit_after>#![allow(warnings)]
#![recursion_limit = "1024"]

use syn::spanned::Spanned;

#[macro_use]
extern crate quote;
extern crate proc_macro;
extern crate syn;
extern crate fibers;
extern crate futures;

use proc_macro::TokenStream;

use quote::{TokenStreamExt, ToTokens};
use syn::{ImplItem, Visibility, FnArg};

use syn::punctuated::Punctuated;
use syn::GenericParam;
use syn::token::Comma;

#[proc_macro_attribute]
pub fn derive_actor(args: TokenStream, item: TokenStream) -> TokenStream
{
    let o_item = item.clone();
    let input: syn::ItemImpl = syn::parse_macro_input!(item as syn::ItemImpl);
    let o_input: syn::ItemImpl = syn::parse_macro_input!(o_item as syn::ItemImpl);

    let attrs = input.attrs;
    let defaultness = input.defaultness;
    let unsafety = input.unsafety;
    let impl_token = input.impl_token;
    let generics = input.generics;
    let ttrait = input.trait_;
    let self_ty = input.self_ty;
    let brace_token = input.brace_token;
    let items: Vec<ImplItem> = input.items;

    let mut actor_methods = quote!();

    let type_name = format!("{}", quote!(#self_ty));

    let type_name: &str = type_name.split("<").next().unwrap_or(&type_name);
    let type_name = type_name.trim();

    let actor_ty = syn::Ident::new(&format!("{}Actor", type_name), self_ty.span());
    let message_ty = syn::Ident::new(&format!("{}Message", type_name), self_ty.span());
    let router_ty = syn::Ident::new(&format!("{}Router", type_name), self_ty.span());

    let method_generics = method_generics(items.clone());
    let method_generic_tys = method_generic_tys(items.clone());

    let all_generics = all_generics(items.clone(), o_input.clone());
    let all_generic_tys = all_generic_tys(items.clone(), o_input.clone());

    let message_variants = gen_message_variants(items.clone());

    for item in items.clone() {
        if let ImplItem::Method(method) = item {
            if let Visibility::Public(vis) = method.vis {
                let sig = method.sig.clone();
                let ident = method.sig.ident;

                let mut args = quote![];
                let mut arg_and_tys = quote![];

                for arg in method.sig.inputs {
                    let arg: FnArg = arg;
                    match arg {
                        FnArg::Typed(arg) => {
                            let arg_name = arg.pat;
                            let arg_ty = arg.ty;

                            args.extend(quote!(#arg_name ,));
                            arg_and_tys.extend(quote!(#arg_name : #arg_ty, ));

                        }
                        _ => {
                            continue
                        }
                    }
                }

                let actor_method = quote!(
                    pub fn #ident (&self, #arg_and_tys) {

                        let msg = #message_ty :: #ident { #args };

                        tokio::spawn(self.sender.clone().send(msg).map(|_|()).map_err(|_|()));
                    }
                );

                actor_methods.extend(actor_method);
            }
        }
    }

    let mut route_arms = quote!();

    for item in items.clone() {
        if let ImplItem::Method(method) = item {
            if let Visibility::Public(vis) = method.vis {
                let ident = method.sig.ident;

                let mut args = quote![];

                for arg in method.sig.inputs {
                    let arg: FnArg = arg;
                    match arg {
                        FnArg::Typed(arg) => {
                            let arg_name = arg.pat;

                            args.extend(quote!(#arg_name, ));

                        }
                        _ => {
                            continue
                        }
                    }
                }

                let arm = quote!(
                #message_ty :: #ident { #args }
                    => self. #ident (#args),
                );

                route_arms.extend(arm);
            }
        }
    }

    // Generate generics for the enum

    let result = quote! {
        #o_input
        // Message

        pub enum #message_ty #method_generics {
            #message_variants
        }

        // route_msg impl
        impl #generics #self_ty {
            pub fn route_message #method_generics (&mut self, msg: #message_ty #method_generic_tys ) {
                match msg {
                    #route_arms
                };
            }
        }

        // Actor Struct
        #[derive(Clone)]
        pub struct #actor_ty #method_generics {
            sender: Sender<#message_ty #method_generic_tys>,
        }
        // Actor Impl block
        #impl_token #method_generics #actor_ty #method_generic_tys {
            pub fn new #generics (actor_impl: #self_ty) -> Self {
                let (sender, receiver) = channel(0);
                let id = "random string".to_owned();

                tokio::spawn(#router_ty {
                    receiver,
                    id,
                    actor_impl
                });

                Self {
                    sender
                }
            }

            #actor_methods
        }

        // Router Struct

        pub struct #router_ty #all_generics {
            receiver: Receiver<#message_ty #method_generic_tys>,
            id: String,
            actor_impl: #self_ty

        }

        // Router Future impl

        impl #all_generics Future for #router_ty #all_generic_tys {
            type Item = ();
            type Error = ();

            fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
                match self.receiver.poll() {
                    Ok(Async::Ready(Some(msg))) => {
                        task::current().notify(); // we should poll on receiver again

                        self.actor_impl.route_message(msg);
                        Ok(Async::NotReady)
                    },
                    Ok(Async::Ready(None)) => {
                        self.receiver.close();

                        Ok(Async::Ready(())) // we're done; disconnect
                    },
                    _ => {
                        Ok(Async::NotReady)
                    }
                }
            }
        }

    };

    // println!("{}", result.to_string());

    result.into()
}

fn capitalize(s: &str) -> String {
    let char_0 = &s[0..1].to_uppercase();

    format!("{}{}", char_0, &s[1..])
}

fn gen_message_variants(items: Vec<ImplItem>) -> impl quote::ToTokens {
    let mut message_variants = quote!();
    for item in items {
        if let ImplItem::Method(method) = item {
            if let Visibility::Public(vis) = method.vis {

                let ident = method.sig.ident;

                let mut args = quote![];

                for arg in method.sig.inputs {
                    let arg: FnArg = arg;
                    match arg {
                        FnArg::Receiver(_) => {
                            continue
                        }
                        arg => args.extend(quote!(#arg, ))
                    }
                }

                let variant = quote!(
                    #ident {
                        #args
                    }
                );

                message_variants.extend(variant);
            }
        }
    }

    message_variants
}

fn all_generics(items: Vec<ImplItem>, item_impl: syn::ItemImpl) -> impl quote:: ToTokens {
    let impl_generics = item_impl.generics;

    let mut all_generics = impl_generics.clone();

    for item in items {

        if let ImplItem::Method(method) = item {
            if let Visibility::Public(vis) = method.vis {
                let mut generics = method.sig.generics;
                let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

                for param in generics.params {
                    all_generics.params.push(param);
                }
            }
        }
    }

    let (impl_generics, ty_generics, where_clause) = all_generics.split_for_impl();
    let all_generics = quote!(#impl_generics);
    // println!("all_generic_tys {}", all_generics.to_string());

    all_generics
}

fn all_generic_tys(items: Vec<ImplItem>, item_impl: syn::ItemImpl) -> impl quote:: ToTokens {
    let impl_generics = item_impl.generics;

    let mut all_generics = impl_generics.clone();

    for item in items {

        if let ImplItem::Method(method) = item {
            if let Visibility::Public(vis) = method.vis {
                let mut generics = method.sig.generics;
                let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

                for param in generics.params {
                    all_generics.params.push(param);
                }
            }
        }
    }

    let (impl_generics, ty_generics, where_clause) = all_generics.split_for_impl();
    let all_generics = quote!(#ty_generics);
    // println!("all_generic_tys {}", all_generics.to_string());

    all_generics
}

fn method_generics(items: Vec<ImplItem>) -> impl quote:: ToTokens {
    let mut generic_types = quote!();
    for item in items {

        if let ImplItem::Method(method) = item {
            if let Visibility::Public(vis) = method.vis {
                let generics = method.sig.generics;
                generic_types.extend(quote!(#generics));
            }
        }
    }

    // println!("method_generics {}", generic_types.to_string());

    generic_types
}

fn method_generic_tys(items: Vec<ImplItem>) -> impl quote:: ToTokens {
    let mut generic_types = quote!();
    for item in items {

        if let ImplItem::Method(method) = item {
            if let Visibility::Public(vis) = method.vis {
                let mut generics = method.sig.generics;
                let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
                generic_types.extend(quote!(#ty_generics));
            }
        }
    }

//    println!("{}", generic_types.to_string());

    generic_types
}
<|endoftext|>