<commit_before>// Copyright (c) 2016-2017 Nikita Pekin and the wolfram_alpha_rs contributors
// See the README.md file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(missing_docs, non_camel_case_types, warnings)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "nightly", feature(custom_derive, proc_macro))]

//! A library providing Rust bindings for the Wolfram|Alpha web API.
//!
//! The library provides a `WolframAlphaRequestSender` trait which can be
//! implemented by various request senders. These implementations may then be
//! used to execute requests to the API.
//!
//! If the `hyper` feature is enabled during compilation, then this library
//! provides an implementation of the `WolframAlphaRequestSender` trait for
//! the `hyper::Client` of the [`hyper`](https://github.com/hyperium/hyper)
//! library.
//!
//! Response bodies are deserialized from XML into structs via the
//! [`serde_xml`](https://github.com/serde-rs/xml) library.

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

#[macro_use]
extern crate log;
extern crate serde;
#[cfg(feature = "nightly")]
#[macro_use]
extern crate serde_derive;
extern crate serde_xml;
extern crate url;

mod error;

pub use self::error::{Error, HttpRequestError, HttpRequestResult, Result};

pub mod model;
pub mod query;
// TODO: implement the `validate_query` function.

use serde::Deserialize;
use std::collections::HashMap;
use std::fmt::Debug;

fn parse_wolfram_alpha_response<T>(response: &str) -> Result<T>
    where T: Debug + Deserialize,
{
    let parsed_response = serde_xml::from_str(response)?;
    trace!("Parsed response: {:?}", parsed_response);
    Ok(parsed_response)
}

/// Functionality for sending requests to Wolfram|Alpha via HTTP.
///
/// Should be implemented for clients to send requests to Wolfram|Alpha.
pub trait WolframAlphaRequestSender {
    /// Performs an API call to Wolfram|Alpha.
    ///
    /// Takes a map of parameters which get appended to the request as query
    /// parameters. Returns the response body string.
    fn send<'a>(&self, method: &str, params: &mut HashMap<&str, &'a str>)
        -> HttpRequestResult<String>;

    /// Make an API call to Wolfram|Alpha that contains the configured App ID.
    ///
    /// Takes a map of parameters which get appended to the request as query
    /// parameters. Returns the response body string.
    fn send_authed<'a>(&self, method: &str, app_id: &'a str, params: &mut HashMap<&str, &'a str>)
        -> HttpRequestResult<String> {
        params.insert("appid", app_id);
        self.send(method, params)
    }
}

#[cfg(feature = "hyper")]
mod hyper_support {
    use error::{HttpRequestError, HttpRequestResult};
    use hyper;
    use std::collections::HashMap;
    use std::io::Read;
    use super::WolframAlphaRequestSender;
    use url::Url;

    impl WolframAlphaRequestSender for hyper::Client {
        fn send<'a>(&self, method: &str, params: &mut HashMap<&str, &'a str>)
            -> HttpRequestResult<String> {
            let url_string = format!("https://api.wolframalpha.com/v2/{}", method);
            let mut url = url_string.parse::<Url>().expect("Unable to parse URL");

            url.query_pairs_mut().extend_pairs(params.into_iter());

            trace!("Sending query \"{:?}\" to url: {}", params, url);
            let mut response = self.get(url).send()?;
            let mut result = String::new();
            response.read_to_string(&mut result)?;
            trace!("Query result: {}", result);

            Ok(result)
        }
    }

    impl From<hyper::Error> for HttpRequestError {
        fn from(error: hyper::Error) -> HttpRequestError {
            match error {
                hyper::Error::Io(e) => HttpRequestError::Io(e),
                e => HttpRequestError::Other(Box::new(e)),
            }
        }
    }
}

#[cfg(feature = "hyper")]
pub use hyper_support::*;
<commit_msg>chore: allow compilation with warnings<commit_after>// Copyright (c) 2016-2017 Nikita Pekin and the wolfram_alpha_rs contributors
// See the README.md file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(missing_docs, non_camel_case_types)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "nightly", feature(custom_derive, proc_macro))]

//! A library providing Rust bindings for the Wolfram|Alpha web API.
//!
//! The library provides a `WolframAlphaRequestSender` trait which can be
//! implemented by various request senders. These implementations may then be
//! used to execute requests to the API.
//!
//! If the `hyper` feature is enabled during compilation, then this library
//! provides an implementation of the `WolframAlphaRequestSender` trait for
//! the `hyper::Client` of the [`hyper`](https://github.com/hyperium/hyper)
//! library.
//!
//! Response bodies are deserialized from XML into structs via the
//! [`serde_xml`](https://github.com/serde-rs/xml) library.

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

#[macro_use]
extern crate log;
extern crate serde;
#[cfg(feature = "nightly")]
#[macro_use]
extern crate serde_derive;
extern crate serde_xml;
extern crate url;

mod error;

pub use self::error::{Error, HttpRequestError, HttpRequestResult, Result};

pub mod model;
pub mod query;
// TODO: implement the `validate_query` function.

use serde::Deserialize;
use std::collections::HashMap;
use std::fmt::Debug;

fn parse_wolfram_alpha_response<T>(response: &str) -> Result<T>
    where T: Debug + Deserialize,
{
    let parsed_response = serde_xml::from_str(response)?;
    trace!("Parsed response: {:?}", parsed_response);
    Ok(parsed_response)
}

/// Functionality for sending requests to Wolfram|Alpha via HTTP.
///
/// Should be implemented for clients to send requests to Wolfram|Alpha.
pub trait WolframAlphaRequestSender {
    /// Performs an API call to Wolfram|Alpha.
    ///
    /// Takes a map of parameters which get appended to the request as query
    /// parameters. Returns the response body string.
    fn send<'a>(&self, method: &str, params: &mut HashMap<&str, &'a str>)
        -> HttpRequestResult<String>;

    /// Make an API call to Wolfram|Alpha that contains the configured App ID.
    ///
    /// Takes a map of parameters which get appended to the request as query
    /// parameters. Returns the response body string.
    fn send_authed<'a>(&self, method: &str, app_id: &'a str, params: &mut HashMap<&str, &'a str>)
        -> HttpRequestResult<String> {
        params.insert("appid", app_id);
        self.send(method, params)
    }
}

#[cfg(feature = "hyper")]
mod hyper_support {
    use error::{HttpRequestError, HttpRequestResult};
    use hyper;
    use std::collections::HashMap;
    use std::io::Read;
    use super::WolframAlphaRequestSender;
    use url::Url;

    impl WolframAlphaRequestSender for hyper::Client {
        fn send<'a>(&self, method: &str, params: &mut HashMap<&str, &'a str>)
            -> HttpRequestResult<String> {
            let url_string = format!("https://api.wolframalpha.com/v2/{}", method);
            let mut url = url_string.parse::<Url>().expect("Unable to parse URL");

            url.query_pairs_mut().extend_pairs(params.into_iter());

            trace!("Sending query \"{:?}\" to url: {}", params, url);
            let mut response = self.get(url).send()?;
            let mut result = String::new();
            response.read_to_string(&mut result)?;
            trace!("Query result: {}", result);

            Ok(result)
        }
    }

    impl From<hyper::Error> for HttpRequestError {
        fn from(error: hyper::Error) -> HttpRequestError {
            match error {
                hyper::Error::Io(e) => HttpRequestError::Io(e),
                e => HttpRequestError::Other(Box::new(e)),
            }
        }
    }
}

#[cfg(feature = "hyper")]
pub use hyper_support::*;
<|endoftext|>


<commit_before>#![feature(associated_consts)]
#![feature(drain)]

extern crate uuid;
extern crate typed_arena;
mod js_types;
mod alloc;

#[test]
fn it_works() {
}
<commit_msg>Stub out basic API for interpreter within lib.rs<commit_after>#![feature(associated_consts)]
#![feature(drain)]

extern crate uuid;
extern crate typed_arena;
mod js_types;
mod alloc;

use std::collections::hash_set::HashSet;
use uuid::Uuid;

use alloc::compartment::Scope;
use js_types::js_type::JsVar;

// TODO Maybe make a scope manager?
pub fn init<F>(callback: F) -> Scope
    where F: Fn() -> HashSet<Uuid> + 'static {
    Scope::new(callback)
}

pub fn alloc(scope: &mut Scope, var: JsVar) -> Uuid {
    scope.alloc(var)
}

pub fn load(scope: &Scope, uuid: Uuid) -> Option<JsVar> {
    scope.get_jst_copy(&uuid)
}

pub fn store(scope: &mut Scope, var: JsVar) -> bool {
    scope.update_var(var)
}

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


<commit_before>#![feature(box_syntax)]
#![feature(zero_one)]

pub mod expr;
pub mod symbol;

use std::{fmt, iter};
use expr::NumType;

pub use expr::{Expr, Condition, ExprError};

/// Used to name symbols and variables.
pub trait Alphabet: fmt::Debug + PartialEq + Eq + Clone {}

impl Alphabet for &'static str {}
impl Alphabet for char {}
impl Alphabet for u8 {}
impl Alphabet for u16 {}
impl Alphabet for u32 {}
impl Alphabet for u64 {}
impl Alphabet for usize {}

/// The common interface for Symbols. Basically this abstracts over
/// the argument implementation.
pub trait Symbol: Clone + PartialEq + fmt::Debug {
    type A: Alphabet;

    type T: NumType;

    fn symbol(&self) -> &Self::A;

    fn args(&self) -> &[Expr<Self::T>];

    fn from_result_iter<I, E>(symbol: Self::A, args_iter: I) -> Result<Self, E>
        where I: Iterator<Item = Result<Expr<Self::T>, E>>;

    fn new(symbol: Self::A) -> Self {
        Self::from_iter(symbol, iter::empty())
    }

    fn from_iter<I>(symbol: Self::A, args_iter: I) -> Self
        where I: Iterator<Item = Expr<Self::T>>
    {
        let res: Result<_, ()> = Self::from_result_iter(symbol, args_iter.map(|i| Ok(i)));
        res.unwrap()
    }

    fn evaluate(&self, bindings: &[Expr<Self::T>]) -> Result<Self, ExprError> {
        Self::from_result_iter((*self.symbol()).clone(),
                               self.args()
                                   .iter()
                                   .map(|expr| expr.evaluate(bindings).map(|ok| Expr::Const(ok))))

    }

    fn debug_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let args = self.args();
        try!(write!(f, "{:?}", *self.symbol()));
        if args.is_empty() {
            return Ok(());
        }

        try!(write!(f, "("));
        for (i, expr) in args.iter().enumerate() {
            if i > 0 {
                try!(write!(f, ", "));
            }
            try!(write!(f, "{:?}", expr));
        }
        write!(f, ")")
    }
}

/// A list of Symbols.
#[derive(PartialEq, Eq, Clone)]
pub struct SymbolString<S: Symbol>(pub Vec<S>);

impl<S: Symbol> fmt::Debug for SymbolString<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for sym in self.0.iter() {
            try!(write!(f, "{:?}", sym));
        }
        Ok(())
    }
}

impl<S: Symbol> SymbolString<S> {
    fn from_result_iter<I, E>(symbol_iter: I) -> Result<SymbolString<S>, E>
        where I: Iterator<Item = Result<S, E>>
    {
        let mut symbols = Vec::with_capacity(symbol_iter.size_hint().0);
        for sym in symbol_iter.into_iter() {
            symbols.push(try!(sym));
        }
        Ok(SymbolString(symbols))
    }

    pub fn evaluate(&self, bindings: &[Expr<S::T>]) -> Result<SymbolString<S>, ExprError> {
        SymbolString::from_result_iter(self.0.iter().map(|sym| sym.evaluate(bindings)))
    }
}

#[derive(Debug, Clone)]
pub struct Rule<S: Symbol> {
    pub symbol: S::A,
    pub condition: Condition<S::T>,
    pub successor: SymbolString<S>,
}

#[derive(Debug, Eq, PartialEq)]
pub enum RuleError {
    SymbolMismatch,
    ConditionFalse,
    ConditionFailed,
    ExprFailed(ExprError),
}

impl<S: Symbol> Rule<S> {
    pub fn new(symbol: S::A, successor: SymbolString<S>) -> Rule<S> {
        Rule {
            symbol: symbol,
            condition: Condition::True,
            successor: successor,
        }
    }

    pub fn new_conditional(symbol: S::A,
                           successor: SymbolString<S>,
                           condition: Condition<S::T>)
                           -> Rule<S> {
        Rule {
            symbol: symbol,
            condition: condition,
            successor: successor,
        }
    }

    /// Apply the rule to the given (constant) symbol and if possible, produce
    /// a successor.
    pub fn apply(&self, sym: &S) -> Result<SymbolString<S>, RuleError> {
        let args = sym.args();
        if self.symbol.eq(sym.symbol()) {
            match self.condition.evaluate(args) {
                Ok(true) => {
                    match self.successor.evaluate(args) {
                        Ok(symstr) => Ok(symstr),
                        Err(e) => Err(RuleError::ExprFailed(e)),
                    }
                }
                Ok(false) => Err(RuleError::ConditionFalse),
                _ => Err(RuleError::ConditionFailed),
            }
        } else {
            Err(RuleError::SymbolMismatch)
        }
    }
}

#[test]
fn test_rule_apply() {
    use symbol::DSym;
    let p = DSym::new_parametric("P", vec![Expr::Const(123u32)]);
    let rule = Rule::new("A", SymbolString(vec![p.clone()]));
    assert_eq!(Err(RuleError::SymbolMismatch), rule.apply(&DSym::new("P")));
    assert_eq!(Ok(SymbolString(vec![DSym::new_parametric("P", vec![Expr::Const(123u32)])])),
               rule.apply(&DSym::new("A")));

    let rule = Rule::new_conditional("A", SymbolString(vec![p.clone()]), Condition::False);
    assert_eq!(Err(RuleError::ConditionFalse), rule.apply(&DSym::new("A")));
}

pub trait LSystem<S: Symbol> {
    fn apply_first_rule(&self, sym: &S) -> Option<SymbolString<S>>;

    /// Apply in parallel the first matching rule to each symbol in the string.
    /// Returns the total number of rule applications.
    fn develop_next(&self, axiom: &SymbolString<S>) -> (SymbolString<S>, usize) {
        let mut expanded = Vec::new();
        let mut rule_applications = 0;

        for sym in axiom.0.iter() {
            match self.apply_first_rule(sym) {
                Some(successor) => {
                    expanded.extend(successor.0);
                    rule_applications += 1;
                    // XXX: Count rule applications of the matching rule.
                }
                None => {
                    expanded.push(sym.clone());
                }
            }
        }

        (SymbolString(expanded), rule_applications)
    }

    /// Develop the system starting with `axiom` up to `max_iterations`. Return iteration count.
    fn develop(&self, axiom: SymbolString<S>, max_iterations: usize) -> (SymbolString<S>, usize) {
        let mut current = axiom;

        for iter in 0..max_iterations {
            let (next, rule_applications) = self.develop_next(&current);
            if rule_applications == 0 {
                return (current, iter);
            }
            current = next;
        }
        return (current, max_iterations);
    }
}

#[derive(Debug, Clone)]
pub struct System<S: Symbol> {
    rules: Vec<Rule<S>>,
}

impl<S: Symbol> System<S> {
    pub fn new() -> System<S> {
        System { rules: vec![] }
    }

    pub fn add_rule(&mut self, rule: Rule<S>) {
        self.rules.push(rule);
    }
}

impl<S: Symbol> LSystem<S> for System<S> {
    /// Apply first matching rule and return expanded successor.
    fn apply_first_rule(&self, sym: &S) -> Option<SymbolString<S>> {
        for rule in self.rules.iter() {
            if let Ok(successor) = rule.apply(sym) {
                return Some(successor);
            }
        }
        return None;
    }
}
<commit_msg>Add helper function apply_first_rule()<commit_after>#![feature(box_syntax)]
#![feature(zero_one)]

pub mod expr;
pub mod symbol;

use std::{fmt, iter};
use expr::NumType;

pub use expr::{Expr, Condition, ExprError};

/// Used to name symbols and variables.
pub trait Alphabet: fmt::Debug + PartialEq + Eq + Clone {}

impl Alphabet for &'static str {}
impl Alphabet for char {}
impl Alphabet for u8 {}
impl Alphabet for u16 {}
impl Alphabet for u32 {}
impl Alphabet for u64 {}
impl Alphabet for usize {}

/// The common interface for Symbols. Basically this abstracts over
/// the argument implementation.
pub trait Symbol: Clone + PartialEq + fmt::Debug {
    type A: Alphabet;

    type T: NumType;

    fn symbol(&self) -> &Self::A;

    fn args(&self) -> &[Expr<Self::T>];

    fn from_result_iter<I, E>(symbol: Self::A, args_iter: I) -> Result<Self, E>
        where I: Iterator<Item = Result<Expr<Self::T>, E>>;

    fn new(symbol: Self::A) -> Self {
        Self::from_iter(symbol, iter::empty())
    }

    fn from_iter<I>(symbol: Self::A, args_iter: I) -> Self
        where I: Iterator<Item = Expr<Self::T>>
    {
        let res: Result<_, ()> = Self::from_result_iter(symbol, args_iter.map(|i| Ok(i)));
        res.unwrap()
    }

    fn evaluate(&self, bindings: &[Expr<Self::T>]) -> Result<Self, ExprError> {
        Self::from_result_iter((*self.symbol()).clone(),
                               self.args()
                                   .iter()
                                   .map(|expr| expr.evaluate(bindings).map(|ok| Expr::Const(ok))))

    }

    fn debug_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let args = self.args();
        try!(write!(f, "{:?}", *self.symbol()));
        if args.is_empty() {
            return Ok(());
        }

        try!(write!(f, "("));
        for (i, expr) in args.iter().enumerate() {
            if i > 0 {
                try!(write!(f, ", "));
            }
            try!(write!(f, "{:?}", expr));
        }
        write!(f, ")")
    }
}

/// A list of Symbols.
#[derive(PartialEq, Eq, Clone)]
pub struct SymbolString<S: Symbol>(pub Vec<S>);

impl<S: Symbol> fmt::Debug for SymbolString<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for sym in self.0.iter() {
            try!(write!(f, "{:?}", sym));
        }
        Ok(())
    }
}

impl<S: Symbol> SymbolString<S> {
    fn from_result_iter<I, E>(symbol_iter: I) -> Result<SymbolString<S>, E>
        where I: Iterator<Item = Result<S, E>>
    {
        let mut symbols = Vec::with_capacity(symbol_iter.size_hint().0);
        for sym in symbol_iter.into_iter() {
            symbols.push(try!(sym));
        }
        Ok(SymbolString(symbols))
    }

    pub fn evaluate(&self, bindings: &[Expr<S::T>]) -> Result<SymbolString<S>, ExprError> {
        SymbolString::from_result_iter(self.0.iter().map(|sym| sym.evaluate(bindings)))
    }
}

#[derive(Debug, Clone)]
pub struct Rule<S: Symbol> {
    pub symbol: S::A,
    pub condition: Condition<S::T>,
    pub successor: SymbolString<S>,
}

#[derive(Debug, Eq, PartialEq)]
pub enum RuleError {
    SymbolMismatch,
    ConditionFalse,
    ConditionFailed,
    ExprFailed(ExprError),
}

impl<S: Symbol> Rule<S> {
    pub fn new(symbol: S::A, successor: SymbolString<S>) -> Rule<S> {
        Rule {
            symbol: symbol,
            condition: Condition::True,
            successor: successor,
        }
    }

    pub fn new_conditional(symbol: S::A,
                           successor: SymbolString<S>,
                           condition: Condition<S::T>)
                           -> Rule<S> {
        Rule {
            symbol: symbol,
            condition: condition,
            successor: successor,
        }
    }

    /// Apply the rule to the given (constant) symbol and if possible, produce
    /// a successor.
    pub fn apply(&self, sym: &S) -> Result<SymbolString<S>, RuleError> {
        let args = sym.args();
        if self.symbol.eq(sym.symbol()) {
            match self.condition.evaluate(args) {
                Ok(true) => {
                    match self.successor.evaluate(args) {
                        Ok(symstr) => Ok(symstr),
                        Err(e) => Err(RuleError::ExprFailed(e)),
                    }
                }
                Ok(false) => Err(RuleError::ConditionFalse),
                _ => Err(RuleError::ConditionFailed),
            }
        } else {
            Err(RuleError::SymbolMismatch)
        }
    }
}

#[test]
fn test_rule_apply() {
    use symbol::DSym;
    let p = DSym::new_parametric("P", vec![Expr::Const(123u32)]);
    let rule = Rule::new("A", SymbolString(vec![p.clone()]));
    assert_eq!(Err(RuleError::SymbolMismatch), rule.apply(&DSym::new("P")));
    assert_eq!(Ok(SymbolString(vec![DSym::new_parametric("P", vec![Expr::Const(123u32)])])),
               rule.apply(&DSym::new("A")));

    let rule = Rule::new_conditional("A", SymbolString(vec![p.clone()]), Condition::False);
    assert_eq!(Err(RuleError::ConditionFalse), rule.apply(&DSym::new("A")));
}

pub trait LSystem<S: Symbol> {
    fn apply_first_rule(&self, sym: &S) -> Option<SymbolString<S>>;

    /// Apply in parallel the first matching rule to each symbol in the string.
    /// Returns the total number of rule applications.
    fn develop_next(&self, axiom: &SymbolString<S>) -> (SymbolString<S>, usize) {
        let mut expanded = Vec::new();
        let mut rule_applications = 0;

        for sym in axiom.0.iter() {
            match self.apply_first_rule(sym) {
                Some(successor) => {
                    expanded.extend(successor.0);
                    rule_applications += 1;
                    // XXX: Count rule applications of the matching rule.
                }
                None => {
                    expanded.push(sym.clone());
                }
            }
        }

        (SymbolString(expanded), rule_applications)
    }

    /// Develop the system starting with `axiom` up to `max_iterations`. Return iteration count.
    fn develop(&self, axiom: SymbolString<S>, max_iterations: usize) -> (SymbolString<S>, usize) {
        let mut current = axiom;

        for iter in 0..max_iterations {
            let (next, rule_applications) = self.develop_next(&current);
            if rule_applications == 0 {
                return (current, iter);
            }
            current = next;
        }
        return (current, max_iterations);
    }
}

#[derive(Debug, Clone)]
pub struct System<S: Symbol> {
    rules: Vec<Rule<S>>,
}

impl<S: Symbol> System<S> {
    pub fn new() -> System<S> {
        System { rules: vec![] }
    }

    pub fn add_rule(&mut self, rule: Rule<S>) {
        self.rules.push(rule);
    }
}

/// Apply first matching rule and return expanded successor.
pub fn apply_first_rule<S:Symbol>(rules: &[Rule<S>], sym: &S) -> Option<SymbolString<S>> {
    for rule in rules {
        if let Ok(successor) = rule.apply(sym) {
            return Some(successor);
        }
    }
    return None;
}

impl<S: Symbol> LSystem<S> for System<S> {
    /// Apply first matching rule and return expanded successor.
    fn apply_first_rule(&self, sym: &S) -> Option<SymbolString<S>> {
        apply_first_rule(&self.rules, sym)
    }
}
<|endoftext|>


<commit_before>//! This is documentation for the `changes-stream` crate.
//!
//! The `changes-stream` crate is designed to give you a readable stream of
//! chunked data, upon which you can register multiple handlers, that are
//! called on Read of the data chunk.

#![feature(proc_macro)]

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;
extern crate futures;
extern crate hyper;
extern crate hyper_tls;
extern crate tokio_core;

use futures::Future;
use futures::stream::Stream;

use hyper::Client;

mod package;

use package::Package;

/// A structure to generate a readable stream on which you can register handlers.
///
/// Internally, the `ChangesStream` struct holds 3 members:
///
/// | Member      | Type                                  | Notes                                                                   |
/// |-------------|---------------------------------------|-------------------------------------------------------------------------|
/// | `db`        | `String`                              | A url pointing to the data you'd like to stream.                        |
/// | `lp`        | [`tokio_core::reactor::Core`]         | The event loop                                                          |
/// | `handlers`  | `Vec<F> where F: Fn(&`[`hyper::Chunk`]`)` | A vector of handlers to be called on each Chunk from the Stream on Read |
///
/// [`tokio_core::reactor::Core`]: ../tokio_core/reactor/struct.Core.html
/// [`hyper::Chunk`]: ../hyper/struct.Chunk.html
pub struct ChangesStream {
    db: hyper::Url,
    lp: tokio_core::reactor::Core,
    handlers: Vec<Box<Fn(&Package)>>,
}

impl ChangesStream {

    /// Constructs a new `ChangesStream` struct
    ///
    /// Takes a single argument, `db`, which represents the
    /// url of the data you wish to stream.
    ///
    /// Every `ChangesStream` struct is initialized with
    /// an event loop ([`tokio_core::reactor::Core`]) and an
    /// empty vector of handlers. See above for more details.
    ///
    /// [`tokio_core::reactor::Core`]: ../tokio_core/reactor/struct.Core.html
    ///
    /// For example, to create a new `ChangesStream` struct
    /// for the npmjs registry, you would write:
    ///
    /// ```no_run
    /// # extern crate serde_json;
    /// # extern crate changes_stream;
    /// # extern crate futures;
    /// #
    /// #
    /// # use changes_stream::ChangesStream;
    /// #
    /// # fn main() {
    ///     let url = "https://replicate.npmjs.com/_changes".to_string();
    ///     let mut changes = ChangesStream::new(url);
    /// #
    /// #   changes.on(|change| {
    /// #       let data = serde_json::to_string(change).unwrap();
    /// #       println!("{}", data);
    /// #   });
    /// #
    /// #   changes.run();
    /// # }
    /// ```
    pub fn new(db: String) -> ChangesStream {
        ChangesStream {
            db: db.parse().unwrap(),
            lp: tokio_core::reactor::Core::new().unwrap(),
            handlers: vec![],
        }
    }

    /// Registers a handler. A handler is simply a function
    /// you'd like to call on a chunk from the stream at the
    /// time the chunk is read.
    ///
    /// `.on()` takes a single argument, a closure. The
    /// closure you pass should take a single [`hyper::Chunk`]
    /// as an argument.
    ///
    /// [`hyper::Chunk`]: ../hyper/struct.Chunk.html
    ///
    /// For example, to write the data in a chunk to standard
    /// out, you would write:
    ///
    /// ```no_run
    /// # extern crate serde_json;
    /// # extern crate changes_stream;
    /// # extern crate futures;
    /// #
    /// # use changes_stream::ChangesStream;
    /// #
    /// # fn main() {
    /// #   let url = "https://replicate.npmjs.com/_changes".to_string();
    /// #   let mut changes = ChangesStream::new(url);
    /// #
    ///    changes.on(|change| {
    ///       let data = serde_json::to_string(change).unwrap();
    ///       println!("{}", data);
    ///    });
    /// #
    /// #   changes.run();
    /// # }
    /// ```
    pub fn on<F: Fn(&Package) + 'static>(&mut self, handler: F) {
        self.handlers.push(Box::new(handler));
    }

    /// Runs the `ChangesStream` struct's event loop, `lp`.
    ///
    /// Call this after you have regsitered all handlers using
    /// `on`.
    ///
    /// Takes no arguments.
    ///
    /// For example:
    ///
    /// ```no_run
    /// # extern crate serde_json;
    /// # extern crate changes_stream;
    /// # extern crate futures;
    /// #
    /// # use changes_stream::ChangesStream;
    /// #
    /// # fn main() {
    /// #   let url = "https://replicate.npmjs.com/_changes".to_string();
    /// #   let mut changes = ChangesStream::new(url);
    /// #
    /// #   changes.on(|change| {
    /// #       let data = serde_json::to_string(change).unwrap();
    /// #       println!("{}", data);
    /// #   });
    /// #
    ///    changes.run();
    /// # }
    /// ```
    pub fn run(mut self) {
        let handle = self.lp.handle();
        let client = Client::configure()
            // 4 is number of threads to use for dns resolution
            .connector(hyper_tls::HttpsConnector::new(4, &handle))
            .build(&handle);

        let handlers = self.handlers;
        self.lp
            .run(client.get(self.db).and_then(move |res| {
                assert!(res.status().is_success());

                res.body().for_each(move |chunk| {
                    let event: Package = serde_json::from_slice(&chunk).unwrap();
                    for handler in &handlers {
                        handler(&event);
                    }
                    Ok(())
                })
            }))
            .unwrap();

    }
}
<commit_msg>remove #![feature(proc_macro)] for rustc 1.16.0-nightly<commit_after>//! This is documentation for the `changes-stream` crate.
//!
//! The `changes-stream` crate is designed to give you a readable stream of
//! chunked data, upon which you can register multiple handlers, that are
//! called on Read of the data chunk.

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;
extern crate futures;
extern crate hyper;
extern crate hyper_tls;
extern crate tokio_core;

use futures::Future;
use futures::stream::Stream;

use hyper::Client;

mod package;

use package::Package;

/// A structure to generate a readable stream on which you can register handlers.
///
/// Internally, the `ChangesStream` struct holds 3 members:
///
/// | Member      | Type                                  | Notes                                                                   |
/// |-------------|---------------------------------------|-------------------------------------------------------------------------|
/// | `db`        | `String`                              | A url pointing to the data you'd like to stream.                        |
/// | `lp`        | [`tokio_core::reactor::Core`]         | The event loop                                                          |
/// | `handlers`  | `Vec<F> where F: Fn(&`[`hyper::Chunk`]`)` | A vector of handlers to be called on each Chunk from the Stream on Read |
///
/// [`tokio_core::reactor::Core`]: ../tokio_core/reactor/struct.Core.html
/// [`hyper::Chunk`]: ../hyper/struct.Chunk.html
pub struct ChangesStream {
    db: hyper::Url,
    lp: tokio_core::reactor::Core,
    handlers: Vec<Box<Fn(&Package)>>,
}

impl ChangesStream {

    /// Constructs a new `ChangesStream` struct
    ///
    /// Takes a single argument, `db`, which represents the
    /// url of the data you wish to stream.
    ///
    /// Every `ChangesStream` struct is initialized with
    /// an event loop ([`tokio_core::reactor::Core`]) and an
    /// empty vector of handlers. See above for more details.
    ///
    /// [`tokio_core::reactor::Core`]: ../tokio_core/reactor/struct.Core.html
    ///
    /// For example, to create a new `ChangesStream` struct
    /// for the npmjs registry, you would write:
    ///
    /// ```no_run
    /// # extern crate serde_json;
    /// # extern crate changes_stream;
    /// # extern crate futures;
    /// #
    /// #
    /// # use changes_stream::ChangesStream;
    /// #
    /// # fn main() {
    ///     let url = "https://replicate.npmjs.com/_changes".to_string();
    ///     let mut changes = ChangesStream::new(url);
    /// #
    /// #   changes.on(|change| {
    /// #       let data = serde_json::to_string(change).unwrap();
    /// #       println!("{}", data);
    /// #   });
    /// #
    /// #   changes.run();
    /// # }
    /// ```
    pub fn new(db: String) -> ChangesStream {
        ChangesStream {
            db: db.parse().unwrap(),
            lp: tokio_core::reactor::Core::new().unwrap(),
            handlers: vec![],
        }
    }

    /// Registers a handler. A handler is simply a function
    /// you'd like to call on a chunk from the stream at the
    /// time the chunk is read.
    ///
    /// `.on()` takes a single argument, a closure. The
    /// closure you pass should take a single [`hyper::Chunk`]
    /// as an argument.
    ///
    /// [`hyper::Chunk`]: ../hyper/struct.Chunk.html
    ///
    /// For example, to write the data in a chunk to standard
    /// out, you would write:
    ///
    /// ```no_run
    /// # extern crate serde_json;
    /// # extern crate changes_stream;
    /// # extern crate futures;
    /// #
    /// # use changes_stream::ChangesStream;
    /// #
    /// # fn main() {
    /// #   let url = "https://replicate.npmjs.com/_changes".to_string();
    /// #   let mut changes = ChangesStream::new(url);
    /// #
    ///    changes.on(|change| {
    ///       let data = serde_json::to_string(change).unwrap();
    ///       println!("{}", data);
    ///    });
    /// #
    /// #   changes.run();
    /// # }
    /// ```
    pub fn on<F: Fn(&Package) + 'static>(&mut self, handler: F) {
        self.handlers.push(Box::new(handler));
    }

    /// Runs the `ChangesStream` struct's event loop, `lp`.
    ///
    /// Call this after you have regsitered all handlers using
    /// `on`.
    ///
    /// Takes no arguments.
    ///
    /// For example:
    ///
    /// ```no_run
    /// # extern crate serde_json;
    /// # extern crate changes_stream;
    /// # extern crate futures;
    /// #
    /// # use changes_stream::ChangesStream;
    /// #
    /// # fn main() {
    /// #   let url = "https://replicate.npmjs.com/_changes".to_string();
    /// #   let mut changes = ChangesStream::new(url);
    /// #
    /// #   changes.on(|change| {
    /// #       let data = serde_json::to_string(change).unwrap();
    /// #       println!("{}", data);
    /// #   });
    /// #
    ///    changes.run();
    /// # }
    /// ```
    pub fn run(mut self) {
        let handle = self.lp.handle();
        let client = Client::configure()
            // 4 is number of threads to use for dns resolution
            .connector(hyper_tls::HttpsConnector::new(4, &handle))
            .build(&handle);

        let handlers = self.handlers;
        self.lp
            .run(client.get(self.db).and_then(move |res| {
                assert!(res.status().is_success());

                res.body().for_each(move |chunk| {
                    let event: Package = serde_json::from_slice(&chunk).unwrap();
                    for handler in &handlers {
                        handler(&event);
                    }
                    Ok(())
                })
            }))
            .unwrap();

    }
}
<|endoftext|>


<commit_before>extern crate num;

#[macro_use]
mod macros;
pub mod traitdefs;

mod nbez;
pub use nbez::*;

use traitdefs::Float;
use std::marker::PhantomData;

// There are macros in place to make it easier to create new bezier structs, as they can be created
// with a very consistent pattern. However, those macros are also written in a very consistent pattern
// which unfortunately is significantly harder, if not impossible, to create with a traditional
// macro. So, the macro invocations are generated with the build script and then inserted here.
include!(concat!(env!("OUT_DIR"), "/macro_invocs.rs"));

impl<F: Float> Vector2d<F> {
    pub fn perp(self) -> Vector2d<F> {
        Vector2d {
            x: -self.y,
            y: self.x
        }
    }
}

pub struct BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {
    points: *const B::Point,
    len: usize,
    order: usize,
    lifetime: PhantomData<&'a ()>
}

impl<'a, F, B> Iterator for BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {
    type Item = B;
    fn next(&mut self) -> Option<B> {
        use std::slice;

        if self.len <= self.order {
            None
        } else {unsafe{
            let slice = slice::from_raw_parts(self.points, self.order + 1);
            self.points = self.points.offset(self.order as isize);
            self.len -= self.order;
            B::from_slice(slice)
        }}
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let size = (self.len - (self.len - 1) % self.order) / self.order;
        (size, Some(size))
    }
}

impl<'a, F, B> DoubleEndedIterator for BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {
    fn next_back(&mut self) -> Option<B> {
        use std::slice;

        // If there are any control points in the iterator that can't be used to create a full curve,
        // ignore them.
        let end = self.len - (self.len - 1) % self.order;
        if end <= self.order {
            None
        } else {unsafe{
            let slice = slice::from_raw_parts(self.points.offset((end-self.order-1) as isize), self.order + 1);
            self.len -= self.order;
            B::from_slice(slice)
        }}
    }
}

impl<'a, F, B> ExactSizeIterator for BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {}

pub trait BezCurve<F: Float>
        where Self: Sized
{
    type Point;
    type Vector;
    type Elevated;

    /// Attempt to create a curve from a slice. Fails if the slice's length does not match the
    /// curve's order + 1, or if it is being used to create an `NBez`/`NBezPoly`.
    fn from_slice(&[Self::Point]) -> Option<Self>;

    /// Perform interpolation on the curve for a value of `t` from `0.0` to `1.0` inclusive. Returns `None`
    /// if `t` is outside of that range.
    fn interp(&self, t: F) -> Option<Self::Point> {
        check_t_bounds!(t);
        Some(self.interp_unbounded(t))
    }
    /// Perform interpolation on the curve with no range bounds
    fn interp_unbounded(&self, t: F) -> Self::Point;

    /// Get the slope for the given `t`, bounded on `0.0` to `1.0` inclusive. Returns `None` if
    /// `t` is not within bounds.
    fn slope(&self, t: F) -> Option<Self::Vector> {
        check_t_bounds!(t);
        Some(self.slope_unbounded(t))
    }
    /// Get the slope for the given `t` with no range bounds
    fn slope_unbounded(&self, t: F) -> Self::Vector;

    fn elevate(&self) -> Self::Elevated;

    /// Gets the order of the curve
    fn order(&self) -> usize;
}

/// Gets the statically-known order of the curve
pub trait OrderStatic {
    fn order_static() -> usize;
}

#[derive(Clone, Copy)]
pub struct BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    points: C,
    phantom: PhantomData<(F, B)>
}

impl<F, B, C> BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    pub fn from_container(container: C) -> BezChain<F, B, C> {
        BezChain {
            points: container,
            phantom: PhantomData
        }
    }

    pub fn get(&self, index: usize) -> B {
        let order = B::order_static();
        let curve_index = index * order;
        B::from_slice(&self.points.as_ref()[curve_index..curve_index + order + 1]).unwrap()
    }

    pub fn iter(&self) -> BezIter<F, B> {
        BezIter {
            points: self.points.as_ref().as_ptr(),
            len: self.points.as_ref().len(),
            order: B::order_static(),
            lifetime: PhantomData
        }
    }

    pub fn order(&self) -> usize {
        B::order_static()
    }

    pub fn unwrap(self) -> C {
        self.points
    }
}

impl<F, B, C> OrderStatic for BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    fn order_static() -> usize {
        B::order_static()
    }
}

impl<F, B, C> AsRef<C> for BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    fn as_ref(&self) -> &C {
        &self.points
    }
}

impl<F, B, C> AsMut<C> for BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    fn as_mut(&mut self) -> &mut C {
        &mut self.points
    }
}

// pub trait BezChain<F, C>: AsRef<C> + AsMut<C>
//         where F: Float,
//               C: AsRef<[<Self::Curve as BezCurve<F>>::Point]>,
//               Self: Sized
// {
//     type Curve: BezCurve<F>;

//     fn from_container(C) -> Self;
//     fn get(&self, usize) -> Self::Curve;
//     fn iter(&self) -> BezIter<F, Self::Curve>;
//     fn order(&self) -> usize;
//     fn unwrap(self) -> C;
// }<commit_msg>Modified BezIter to not store order but instead get it from OrderStatic<commit_after>extern crate num;

#[macro_use]
mod macros;
pub mod traitdefs;

mod nbez;
pub use nbez::*;

use traitdefs::Float;
use std::marker::PhantomData;

// There are macros in place to make it easier to create new bezier structs, as they can be created
// with a very consistent pattern. However, those macros are also written in a very consistent pattern
// which unfortunately is significantly harder, if not impossible, to create with a traditional
// macro. So, the macro invocations are generated with the build script and then inserted here.
include!(concat!(env!("OUT_DIR"), "/macro_invocs.rs"));

impl<F: Float> Vector2d<F> {
    pub fn perp(self) -> Vector2d<F> {
        Vector2d {
            x: -self.y,
            y: self.x
        }
    }
}

pub struct BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {
    points: *const B::Point,
    len: usize,
    lifetime: PhantomData<&'a ()>
}

impl<'a, F, B> Iterator for BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {
    type Item = B;
    fn next(&mut self) -> Option<B> {
        use std::slice;

        let order = B::order_static();

        if self.len <= order {
            None
        } else {unsafe{
            let slice = slice::from_raw_parts(self.points, order + 1);
            self.points = self.points.offset(order as isize);
            self.len -= order;
            B::from_slice(slice)
        }}
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let order = B::order_static();
        let size = (self.len - (self.len - 1) % order) / order;
        (size, Some(size))
    }
}

impl<'a, F, B> DoubleEndedIterator for BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {
    fn next_back(&mut self) -> Option<B> {
        use std::slice;

        let order = B::order_static();

        // If there are any control points in the iterator that can't be used to create a full curve,
        // ignore them.
        let end = self.len - (self.len - 1) % order;
        if end <= order {
            None
        } else {unsafe{
            let slice = slice::from_raw_parts(self.points.offset((end-order-1) as isize), order + 1);
            self.len -= order;
            B::from_slice(slice)
        }}
    }
}

impl<'a, F, B> ExactSizeIterator for BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {}

pub trait BezCurve<F: Float>
        where Self: Sized
{
    type Point;
    type Vector;
    type Elevated;

    /// Attempt to create a curve from a slice. Fails if the slice's length does not match the
    /// curve's order + 1, or if it is being used to create an `NBez`/`NBezPoly`.
    fn from_slice(&[Self::Point]) -> Option<Self>;

    /// Perform interpolation on the curve for a value of `t` from `0.0` to `1.0` inclusive. Returns `None`
    /// if `t` is outside of that range.
    fn interp(&self, t: F) -> Option<Self::Point> {
        check_t_bounds!(t);
        Some(self.interp_unbounded(t))
    }
    /// Perform interpolation on the curve with no range bounds
    fn interp_unbounded(&self, t: F) -> Self::Point;

    /// Get the slope for the given `t`, bounded on `0.0` to `1.0` inclusive. Returns `None` if
    /// `t` is not within bounds.
    fn slope(&self, t: F) -> Option<Self::Vector> {
        check_t_bounds!(t);
        Some(self.slope_unbounded(t))
    }
    /// Get the slope for the given `t` with no range bounds
    fn slope_unbounded(&self, t: F) -> Self::Vector;

    fn elevate(&self) -> Self::Elevated;

    /// Gets the order of the curve
    fn order(&self) -> usize;
}

/// Gets the statically-known order of the curve
pub trait OrderStatic {
    fn order_static() -> usize;
}

#[derive(Clone, Copy)]
pub struct BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    points: C,
    phantom: PhantomData<(F, B)>
}

impl<F, B, C> BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    pub fn from_container(container: C) -> BezChain<F, B, C> {
        BezChain {
            points: container,
            phantom: PhantomData
        }
    }

    pub fn get(&self, index: usize) -> B {
        let order = B::order_static();
        let curve_index = index * order;
        B::from_slice(&self.points.as_ref()[curve_index..curve_index + order + 1]).unwrap()
    }

    pub fn iter(&self) -> BezIter<F, B> {
        BezIter {
            points: self.points.as_ref().as_ptr(),
            len: self.points.as_ref().len(),
            lifetime: PhantomData
        }
    }

    pub fn order(&self) -> usize {
        B::order_static()
    }

    pub fn unwrap(self) -> C {
        self.points
    }
}

impl<F, B, C> OrderStatic for BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    fn order_static() -> usize {
        B::order_static()
    }
}

impl<F, B, C> AsRef<C> for BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    fn as_ref(&self) -> &C {
        &self.points
    }
}

impl<F, B, C> AsMut<C> for BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    fn as_mut(&mut self) -> &mut C {
        &mut self.points
    }
}<|endoftext|>


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

extern crate error_chain;

pub mod config;
mod errors;

use std::process::Command;

use config::Config;
use errors::*;

#[derive(Clone, Debug, PartialEq)]
pub struct Author {
  pub name: String,
  pub email: String,
}

pub struct GitTogether<C> {
  pub config: C,
}

impl<C: Config> GitTogether<C> {
  pub fn set_active(&self, inits: &[&str]) -> Result<()> {
    self.get_authors(inits)
      .and_then(|_| self.config.set("active", &inits.join("+")))
  }

  pub fn signoff<'a>(&self,
                         cmd: &'a mut Command)
                         -> Result<&'a mut Command> {
    let active = try!(self.get_active());

    let cmd = match active.get(0) {
      Some(author) => {
        cmd.env("GIT_AUTHOR_NAME", author.name.clone())
          .env("GIT_AUTHOR_EMAIL", author.email.clone())
      }
      _ => cmd,
    };

    let cmd = match active.get(1) {
      Some(committer) => {
        cmd.env("GIT_COMMITTER_NAME", committer.name.clone())
          .env("GIT_COMMITTER_EMAIL", committer.email.clone())
          .arg("--signoff")
      }
      _ => cmd,
    };

    Ok(cmd)
  }

  fn get_active(&self) -> Result<Vec<Author>> {
    self.config.get("active").and_then(|inits| {
      let inits: Vec<_> = inits.split('+').collect();
      self.get_authors(&inits)
    })
  }

  fn get_authors(&self, inits: &[&str]) -> Result<Vec<Author>> {
    let domain = try!(self.config.get("domain"));
    inits.iter()
      .map(|&init| {
        self.config
          .get(&format!("authors.{}", init))
          .chain_err(|| ErrorKind::AuthorNotFound(init.into()))
          .and_then(|raw| {
            if raw.is_empty() {
              return Err(ErrorKind::InvalidAuthor(raw).into());
            }

            let mut split = raw.split(';');
            let name = try!(split.next()
                .ok_or(ErrorKind::InvalidAuthor(raw.clone())))
              .trim();
            let username = try!(split.next()
                .ok_or(ErrorKind::InvalidAuthor(raw.clone())))
              .trim();
            let email = format!("{}@{}", username, domain);

            Ok(Author {
              name: name.into(),
              email: email,
            })
          })
      })
      .collect()
  }
}

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

  use std::cell::RefCell;
  use std::collections::HashMap;

  use config::Config;
  use errors::*;

  #[test]
  fn get_authors_no_domain() {
    let config = MockConfig::new(&[("authors.jh", "James Holden; jholden")]);
    let gt = GitTogether { config: config };

    assert!(gt.get_authors(&["jh"]).is_err());
  }

  #[test]
  fn get_authors() {
    let config = MockConfig::new(&[("domain", "rocinante.com"),
                                   ("authors.jh", ""),
                                   ("authors.nn", "Naomi Nagata"),
                                   ("authors.ab", "Amos Burton; aburton"),
                                   ("authors.ak", "Alex Kamal; akamal") /* ("authors.ca", "Chrisjen Avasarala;"),
                                                                         * ("authors.bd", "Bobbie Draper; bdraper@mars.mil"),
                                                                         * ("authors.jm", "Joe Miller; jmiller@starhelix.com"), */]);
    let gt = GitTogether { config: config };

    assert!(gt.get_authors(&["jh"]).is_err());
    assert!(gt.get_authors(&["nn"]).is_err());
    // assert!(gt.get_authors(&["ca"]).is_err());
    // assert!(gt.get_authors(&["jh", "bd"]).is_err());

    assert_eq!(gt.get_authors(&["ab", "ak"]).unwrap(),
               vec![
               Author { name: "Amos Burton".into(), email: "aburton@rocinante.com".into() },
               Author { name: "Alex Kamal".into(), email: "akamal@rocinante.com".into() },
               ]);
    // assert_eq!(gt.get_authors(&["ab", "bd", "jm"]).unwrap(),
    //            vec![Author { name: "Amos Burton".into(), email: "aburton@rocinante.com".into() },
    // Author { name: "Bobbie Draper".into(), email: "bdraper@mars.mil".into() },
    // Author { name: "Joe Miller".into(), email: "jmiller@starhelix.com".into() },
    // ]);
  }

  #[test]
  fn set_active() {
    let config = MockConfig::new(&[("domain", "rocinante.com"),
                                   ("authors.jh", "James Holden; jholden"),
                                   ("authors.nn", "Naomi Nagata; nnagata")]);
    let gt = GitTogether { config: config };

    gt.set_active(&["jh"]).unwrap();
    assert_eq!(gt.config.get("active").unwrap(), "jh".to_string());

    gt.set_active(&["jh", "nn"]).unwrap();
    assert_eq!(gt.config.get("active").unwrap(), "jh+nn".to_string());
  }

  struct MockConfig {
    data: RefCell<HashMap<String, String>>,
  }

  impl MockConfig {
    fn new(data: &[(&str, &str)]) -> MockConfig {
      let data = data.iter()
        .map(|&(k, v)| (k.into(), v.into()))
        .collect();
      MockConfig { data: RefCell::new(data) }
    }
  }

  impl Config for MockConfig {
    fn get(&self, name: &str) -> Result<String> {
      self.data.borrow().get(name.into()).cloned().ok_or("".into())
    }

    fn set(&self, name: &str, value: &str) -> Result<()> {
      self.data.borrow_mut().insert(name.into(), value.into());
      Ok(())
    }
  }
}
<commit_msg>remove unnecessary helper function<commit_after>#![recursion_limit = "1024"]
#[macro_use]

extern crate error_chain;

pub mod config;
mod errors;

use std::process::Command;

use config::Config;
use errors::*;

#[derive(Clone, Debug, PartialEq)]
pub struct Author {
  pub name: String,
  pub email: String,
}

pub struct GitTogether<C> {
  pub config: C,
}

impl<C: Config> GitTogether<C> {
  pub fn set_active(&self, inits: &[&str]) -> Result<()> {
    self.get_authors(inits)
      .and_then(|_| self.config.set("active", &inits.join("+")))
  }

  pub fn signoff<'a>(&self,
                         cmd: &'a mut Command)
                         -> Result<&'a mut Command> {
    let active = try!(self.config.get("active"));
    let inits: Vec<_> = active.split('+').collect();
    let authors = try!(self.get_authors(&inits));

    let cmd = match authors.get(0) {
      Some(author) => {
        cmd.env("GIT_AUTHOR_NAME", author.name.clone())
          .env("GIT_AUTHOR_EMAIL", author.email.clone())
      }
      _ => cmd,
    };

    let cmd = match authors.get(1) {
      Some(committer) => {
        cmd.env("GIT_COMMITTER_NAME", committer.name.clone())
          .env("GIT_COMMITTER_EMAIL", committer.email.clone())
          .arg("--signoff")
      }
      _ => cmd,
    };

    Ok(cmd)
  }

  fn get_authors(&self, inits: &[&str]) -> Result<Vec<Author>> {
    let domain = try!(self.config.get("domain"));
    inits.iter()
      .map(|&init| {
        self.config
          .get(&format!("authors.{}", init))
          .chain_err(|| ErrorKind::AuthorNotFound(init.into()))
          .and_then(|raw| {
            if raw.is_empty() {
              return Err(ErrorKind::InvalidAuthor(raw).into());
            }

            let mut split = raw.split(';');
            let name = try!(split.next()
                .ok_or(ErrorKind::InvalidAuthor(raw.clone())))
              .trim();
            let username = try!(split.next()
                .ok_or(ErrorKind::InvalidAuthor(raw.clone())))
              .trim();
            let email = format!("{}@{}", username, domain);

            Ok(Author {
              name: name.into(),
              email: email,
            })
          })
      })
      .collect()
  }
}

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

  use std::cell::RefCell;
  use std::collections::HashMap;

  use config::Config;
  use errors::*;

  #[test]
  fn get_authors_no_domain() {
    let config = MockConfig::new(&[("authors.jh", "James Holden; jholden")]);
    let gt = GitTogether { config: config };

    assert!(gt.get_authors(&["jh"]).is_err());
  }

  #[test]
  fn get_authors() {
    let config = MockConfig::new(&[("domain", "rocinante.com"),
                                   ("authors.jh", ""),
                                   ("authors.nn", "Naomi Nagata"),
                                   ("authors.ab", "Amos Burton; aburton"),
                                   ("authors.ak", "Alex Kamal; akamal") /* ("authors.ca", "Chrisjen Avasarala;"),
                                                                         * ("authors.bd", "Bobbie Draper; bdraper@mars.mil"),
                                                                         * ("authors.jm", "Joe Miller; jmiller@starhelix.com"), */]);
    let gt = GitTogether { config: config };

    assert!(gt.get_authors(&["jh"]).is_err());
    assert!(gt.get_authors(&["nn"]).is_err());
    // assert!(gt.get_authors(&["ca"]).is_err());
    // assert!(gt.get_authors(&["jh", "bd"]).is_err());

    assert_eq!(gt.get_authors(&["ab", "ak"]).unwrap(),
               vec![
               Author { name: "Amos Burton".into(), email: "aburton@rocinante.com".into() },
               Author { name: "Alex Kamal".into(), email: "akamal@rocinante.com".into() },
               ]);
    // assert_eq!(gt.get_authors(&["ab", "bd", "jm"]).unwrap(),
    //            vec![Author { name: "Amos Burton".into(), email: "aburton@rocinante.com".into() },
    // Author { name: "Bobbie Draper".into(), email: "bdraper@mars.mil".into() },
    // Author { name: "Joe Miller".into(), email: "jmiller@starhelix.com".into() },
    // ]);
  }

  #[test]
  fn set_active() {
    let config = MockConfig::new(&[("domain", "rocinante.com"),
                                   ("authors.jh", "James Holden; jholden"),
                                   ("authors.nn", "Naomi Nagata; nnagata")]);
    let gt = GitTogether { config: config };

    gt.set_active(&["jh"]).unwrap();
    assert_eq!(gt.config.get("active").unwrap(), "jh".to_string());

    gt.set_active(&["jh", "nn"]).unwrap();
    assert_eq!(gt.config.get("active").unwrap(), "jh+nn".to_string());
  }

  struct MockConfig {
    data: RefCell<HashMap<String, String>>,
  }

  impl MockConfig {
    fn new(data: &[(&str, &str)]) -> MockConfig {
      let data = data.iter()
        .map(|&(k, v)| (k.into(), v.into()))
        .collect();
      MockConfig { data: RefCell::new(data) }
    }
  }

  impl Config for MockConfig {
    fn get(&self, name: &str) -> Result<String> {
      self.data.borrow().get(name.into()).cloned().ok_or("".into())
    }

    fn set(&self, name: &str, value: &str) -> Result<()> {
      self.data.borrow_mut().insert(name.into(), value.into());
      Ok(())
    }
  }
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate test;

use md5::{Digest, Md5};
use test::Bencher;
use identicon::Identicon;

#[bench]
fn generate(x: &mut Bencher) {
    let input = "42".as_bytes();
    let bytes = Md5::digest(input);
    let identicon = Identicon::new(&bytes);
    x.iter(|| identicon.image());
}
<commit_msg>Sort imports<commit_after>#![feature(test)]
extern crate test;

use identicon::Identicon;
use md5::{Digest, Md5};
use test::Bencher;

#[bench]
fn generate(x: &mut Bencher) {
    let input = "42".as_bytes();
    let bytes = Md5::digest(input);
    let identicon = Identicon::new(&bytes);
    x.iter(|| identicon.image());
}
<|endoftext|>


<commit_before>extern crate disque;

use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread::{spawn, JoinHandle};

use disque::Disque;

#[derive(Clone)]
pub enum JobStatus {
    FastAck,
    AckJob,
    NAck,
}

pub trait Handler {
    fn process_job(&self, queue_name: &[u8], jobid: &String, body: Vec<u8>) -> JobStatus;
    fn process_error(&self, queue_name: &[u8], jobid: &String, nack: u32, additional_deliveries: u32) -> bool;
}

#[derive(Clone)]
struct HandlerWrapper<H: Handler> {
    handler: Arc<H>,
}
unsafe impl<H: Handler> Send for HandlerWrapper<H> {}
unsafe impl<H: Handler> Sync for HandlerWrapper<H> {}

fn create_worker<H: Handler + Clone + 'static>(position: usize,
        task_rx: Receiver<Option<(Vec<u8>, String, Vec<u8>, u32, u32)>>,
        completion_tx: Sender<(usize, String, JobStatus)>,
        handler_: HandlerWrapper<H>,
        ) -> JoinHandle<()> {
    let handlerw = handler_.clone();
    spawn(move || {
        let handler = handlerw.handler;
        loop {
            let (queue, jobid, job, nack,
                additional_deliveries) = match task_rx.recv().unwrap() {
                Some(v) => v,
                None => break,
            };

            if nack > 0 || additional_deliveries > 0 {
                if !handler.process_error(&*queue, &jobid, nack,
                    additional_deliveries) {
                    return;
                }
            }
            let status = handler.process_job(&*queue, &jobid, job);

            completion_tx.send((position, jobid, status)).unwrap();
        }
    })
}

pub struct EventLoop {
    disque: Disque,
    workers: Vec<(JoinHandle<()>, Sender<Option<(Vec<u8>, String, Vec<u8>, u32, u32)>>)>,
    completion_rx: Receiver<(usize, String, JobStatus)>,
    free_workers: HashSet<usize>,
    queues: HashSet<Vec<u8>>,
    hello: (u8, String, Vec<(String, String, u16, u32)>),
    node_counter: HashMap<Vec<u8>, usize>,
}

impl EventLoop {
    pub fn new<H: Handler + Clone + 'static>(
            disque: Disque, numworkers: usize,
            handler: H) -> Self {
        let mut workers = Vec::with_capacity(numworkers);
        let mut free_workers = HashSet::with_capacity(numworkers);
        let (completion_tx, completion_rx) = channel();
        let ahandler = HandlerWrapper { handler: Arc::new(handler) };
        for i in 0..numworkers {
            let (task_tx, task_rx) = channel();
            let jg = create_worker(i, task_rx, completion_tx.clone(),
                    ahandler.clone());
            workers.push((jg, task_tx));
            free_workers.insert(i);
        }
        let hello = disque.hello().unwrap();
        EventLoop {
            disque: disque,
            completion_rx: completion_rx,
            workers: workers,
            hello: hello,
            free_workers: free_workers,
            queues: HashSet::new(),
            node_counter: HashMap::new(),
        }
    }

    pub fn watch_queue(&mut self, queue_name: Vec<u8>) {
        self.queues.insert(queue_name);
    }

    pub fn unwatch_queue(&mut self, queue_name: &Vec<u8>) {
        self.queues.remove(queue_name);
    }

    fn completed(&mut self, worker: usize, jobid: String, status: JobStatus) {
        self.free_workers.insert(worker);
        match status {
            JobStatus::FastAck => self.disque.fastackjob(jobid.as_bytes()),
            JobStatus::AckJob => self.disque.ackjob(jobid.as_bytes()),
            JobStatus::NAck => self.disque.nackjob(jobid.as_bytes()),
        }.unwrap();
    }

    fn mark_completed(&mut self) {
        loop {
            match self.completion_rx.try_recv() {
                Ok(c) => self.completed(c.0, c.1, c.2),
                Err(_) => break,
            }
        }
    }

    pub fn jobcount_current_node(&self) -> usize {
        let nodeid = self.hello.1.as_bytes()[0..8].to_vec();
        self.node_counter.get(&nodeid).unwrap_or(&0).clone()
    }

    fn run_once(&mut self) -> bool {
        self.mark_completed();
        let worker = match self.free_workers.iter().next() {
            Some(w) => w.clone(),
            None => return false,
        };

        let job = match self.disque.getjob_withcounters(false, None,
                &*self.queues.iter().map(|k| &**k).collect::<Vec<_>>()
                ).unwrap() {
            Some(j) => j,
            None => return false,
        };

        let nodeid = job.1.as_bytes()[2..10].to_vec();
        let v = self.node_counter.remove(&nodeid).unwrap_or(0);
        self.node_counter.insert(nodeid, v + 1);

        self.free_workers.remove(&worker);
        self.workers[worker].1.send(Some(job)).unwrap();
        true
    }

    pub fn run(&mut self) {
        loop {
            self.run_once();
        }
    }

    pub fn run_times(&mut self, mut times: usize) {
        while times > 0 {
            if self.run_once() {
                times -= 1;
            }
        }
    }

    pub fn stop(mut self) {
        for worker in std::mem::replace(&mut self.workers, vec![]).into_iter() {
            worker.1.send(None).unwrap();
            worker.0.join().unwrap();
        }
        self.mark_completed();
    }
}
<commit_msg>Add favorite node choosing<commit_after>#![feature(iter_cmp)]
extern crate disque;

use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread::{spawn, JoinHandle};

use disque::Disque;

#[derive(Clone)]
pub enum JobStatus {
    FastAck,
    AckJob,
    NAck,
}

pub trait Handler {
    fn process_job(&self, queue_name: &[u8], jobid: &String, body: Vec<u8>) -> JobStatus;
    fn process_error(&self, queue_name: &[u8], jobid: &String, nack: u32, additional_deliveries: u32) -> bool;
}

#[derive(Clone)]
struct HandlerWrapper<H: Handler> {
    handler: Arc<H>,
}
unsafe impl<H: Handler> Send for HandlerWrapper<H> {}
unsafe impl<H: Handler> Sync for HandlerWrapper<H> {}

fn create_worker<H: Handler + Clone + 'static>(position: usize,
        task_rx: Receiver<Option<(Vec<u8>, String, Vec<u8>, u32, u32)>>,
        completion_tx: Sender<(usize, String, JobStatus)>,
        handler_: HandlerWrapper<H>,
        ) -> JoinHandle<()> {
    let handlerw = handler_.clone();
    spawn(move || {
        let handler = handlerw.handler;
        loop {
            let (queue, jobid, job, nack,
                additional_deliveries) = match task_rx.recv().unwrap() {
                Some(v) => v,
                None => break,
            };

            if nack > 0 || additional_deliveries > 0 {
                if !handler.process_error(&*queue, &jobid, nack,
                    additional_deliveries) {
                    return;
                }
            }
            let status = handler.process_job(&*queue, &jobid, job);

            completion_tx.send((position, jobid, status)).unwrap();
        }
    })
}

pub struct EventLoop {
    disque: Disque,
    workers: Vec<(JoinHandle<()>, Sender<Option<(Vec<u8>, String, Vec<u8>, u32, u32)>>)>,
    completion_rx: Receiver<(usize, String, JobStatus)>,
    free_workers: HashSet<usize>,
    queues: HashSet<Vec<u8>>,
    hello: (u8, String, Vec<(String, String, u16, u32)>),
    node_counter: HashMap<Vec<u8>, usize>,
}

impl EventLoop {
    pub fn new<H: Handler + Clone + 'static>(
            disque: Disque, numworkers: usize,
            handler: H) -> Self {
        let mut workers = Vec::with_capacity(numworkers);
        let mut free_workers = HashSet::with_capacity(numworkers);
        let (completion_tx, completion_rx) = channel();
        let ahandler = HandlerWrapper { handler: Arc::new(handler) };
        for i in 0..numworkers {
            let (task_tx, task_rx) = channel();
            let jg = create_worker(i, task_rx, completion_tx.clone(),
                    ahandler.clone());
            workers.push((jg, task_tx));
            free_workers.insert(i);
        }
        let hello = disque.hello().unwrap();
        EventLoop {
            disque: disque,
            completion_rx: completion_rx,
            workers: workers,
            hello: hello,
            free_workers: free_workers,
            queues: HashSet::new(),
            node_counter: HashMap::new(),
        }
    }

    pub fn watch_queue(&mut self, queue_name: Vec<u8>) {
        self.queues.insert(queue_name);
    }

    pub fn unwatch_queue(&mut self, queue_name: &Vec<u8>) {
        self.queues.remove(queue_name);
    }

    fn completed(&mut self, worker: usize, jobid: String, status: JobStatus) {
        self.free_workers.insert(worker);
        match status {
            JobStatus::FastAck => self.disque.fastackjob(jobid.as_bytes()),
            JobStatus::AckJob => self.disque.ackjob(jobid.as_bytes()),
            JobStatus::NAck => self.disque.nackjob(jobid.as_bytes()),
        }.unwrap();
    }

    fn mark_completed(&mut self) {
        loop {
            match self.completion_rx.try_recv() {
                Ok(c) => self.completed(c.0, c.1, c.2),
                Err(_) => break,
            }
        }
    }

    pub fn choose_favorite_node(&self) -> Vec<u8> {
        let default = (&Vec::new(), &0);
        self.node_counter.iter().max_by(|node| node.1).unwrap_or(default).0.clone()
    }

    pub fn jobcount_current_node(&self) -> usize {
        let nodeid = self.hello.1.as_bytes()[0..8].to_vec();
        self.node_counter.get(&nodeid).unwrap_or(&0).clone()
    }

    fn run_once(&mut self) -> bool {
        self.mark_completed();
        let worker = match self.free_workers.iter().next() {
            Some(w) => w.clone(),
            None => return false,
        };

        let job = match self.disque.getjob_withcounters(false, None,
                &*self.queues.iter().map(|k| &**k).collect::<Vec<_>>()
                ).unwrap() {
            Some(j) => j,
            None => return false,
        };

        let nodeid = job.1.as_bytes()[2..10].to_vec();
        let v = self.node_counter.remove(&nodeid).unwrap_or(0);
        self.node_counter.insert(nodeid, v + 1);

        self.free_workers.remove(&worker);
        self.workers[worker].1.send(Some(job)).unwrap();
        true
    }

    pub fn run(&mut self) {
        loop {
            self.run_once();
        }
    }

    pub fn run_times(&mut self, mut times: usize) {
        while times > 0 {
            if self.run_once() {
                times -= 1;
            }
        }
    }

    pub fn stop(mut self) {
        for worker in std::mem::replace(&mut self.workers, vec![]).into_iter() {
            worker.1.send(None).unwrap();
            worker.0.join().unwrap();
        }
        self.mark_completed();
    }
}

#[test]
fn favorite() {
    #[derive(Clone)]
    struct MyHandler;
    impl Handler for MyHandler {
        fn process_job(&self, _: &[u8], _: &String, _: Vec<u8>) -> JobStatus {
            JobStatus::AckJob
        }
        fn process_error(&self, _: &[u8], _: &String, _: u32, _: u32) -> bool {
            false
        }
    }
    let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
    let mut el = EventLoop::new(disque, 1, MyHandler);
    el.node_counter.insert(vec![1, 2, 3], 123);
    el.node_counter.insert(vec![4, 5, 6], 456);
    el.node_counter.insert(vec![0, 0, 0], 0);
    assert_eq!(el.choose_favorite_node(), vec![4, 5, 6]);
}
<|endoftext|>


<commit_before>extern crate xmltree;
extern crate hyper;

use hyper::Client;
use hyper::header::Connection;
use std::io::Read;

use hyper::Url;

/// Turns "123" into 123
pub fn intify(instr: &str) -> u32{
    // TODO: Better error handling
    instr.to_owned().parse::<u32>().unwrap()
}

/// Errors in contacting TheTVDB
#[derive(Debug)]
pub enum TvdbError {
    SeriesNotFound,
    CommunicationError{reason: String},
    DataError{reason: String},
    Cancelled,
}

#[derive(Debug,Clone)]
pub struct SeriesSearchResult{
    pub seriesid: u32, // seriesid is preferred over id according to TVDB wiki
    pub seriesname: String,
    pub language: String,
    pub overview: Option<String>,
    pub banner: Option<String>,
    pub imdb_id: Option<String>,
    //pub firstaired: Date,
    pub network: Option<String>,
    pub zap2it_id: Option<String>,
}

pub struct Tvdb{
    key: String,
}

impl Tvdb{
    fn new(key: String) -> Tvdb{
        Tvdb{key: key}
    }

    /// Searches for a given series name.
    fn search(&self, seriesname: String, lang: String) -> Result<Vec<SeriesSearchResult>, TvdbError>{
        let client = Client::new();

        let formatted_url = format!("http://thetvdb.com/api/GetSeries.php?seriesname={}", seriesname);
        let url = Url::parse(&formatted_url).ok().expect("invalid URL");
        println!("Getting {}", url);

        let res = client.get(url)
            .header(Connection::close())
            .send();

        let mut res = match res {
            Err(e) => return Err(TvdbError::CommunicationError{reason: "Error contacting TVDB".to_owned()}), // FIXME: http://stackoverflow.com/questions/28911833/error-handling-best-practices
            Ok(r) => r
        };

        // Read the Response.
        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        // Parse XML
        let tree = xmltree::Element::parse(body.as_bytes());

        // Convert XML into structs
        let mut results : Vec<SeriesSearchResult> = vec![];

        for child in tree.children.iter(){

            fn get_text(child: &xmltree::Element, x: &str) -> Option<String>{
                child.get_child(x).and_then(|id_child| id_child.text.clone())
            }

            let r = SeriesSearchResult{
                seriesid:   intify(&get_text(child, "seriesid").expect("Search result XML missing 'seriesid' element")),
                seriesname: get_text(child, "SeriesName").expect("Search result XML Missing 'SeriesName' element"),
                language:   get_text(child, "language").expect("Search result XML missing 'language' element"),
                overview:   get_text(child, "Overview"),
                banner:     get_text(child, "banner"),
                imdb_id:    get_text(child, "IMDB_ID"),
                //firstaired: Date,
                network:    get_text(child, "Network"),
                zap2it_id:  get_text(child, "zap2it_id"),
            };

            results.push(r);
        }

        if results.is_empty(){
            return Err(TvdbError::SeriesNotFound);
        }

        return Ok(results);
    }
}

struct EpisodeInfo{
    pub episodename: String,
}

impl SeriesSearchResult{
    fn episode(&self, season: u32, episode: u32) -> EpisodeInfo{
        println!("{} s{}e{}", self.seriesname, season, episode);

        EpisodeInfo{episodename: "My First Day".to_owned()} // FIXME
    }
}

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

    #[test]
    fn search() {
        let api = Tvdb::new("APIKEY".to_owned());
        let sr = api.search("scrubs".to_owned(), "en".to_owned());
        assert!(sr.ok().unwrap()[0].seriesname == "Scrubs");
    }

    #[test]
    fn nonexist() {
        let api = Tvdb::new("APIKEY".to_owned());
        let sr = api.search("ladlkgdklfgsdfglk".to_owned(), "en".to_owned());
        assert!(sr.is_err());
    }

    #[test]
    fn epinfo_default(){
        let api = Tvdb::new("APIKEY".to_owned());
        let sr = api.search("scrubs".to_owned(), "en".to_owned()).ok().unwrap();
        let ep = sr[0].episode(1, 2);
        assert!(ep.episodename == "My First Day");
    }

    #[test]
    fn epinfo_dvd(){
        let api = Tvdb::new("APIKEY".to_owned());
        let sr = api.search("scrubs".to_owned(), "en".to_owned()).ok().unwrap();
        let ep = sr[0].episode(1, 2);
        assert!(ep.episodename == "My First Day");
    }

}
<commit_msg>Getting episode name works<commit_after>extern crate xmltree;
extern crate hyper;

use hyper::Client;
use hyper::header::Connection;
use std::io::Read;

use hyper::Url;

/// Turns "123" into 123
pub fn intify(instr: &str) -> u32{
    // TODO: Better error handling
    instr.to_owned().parse::<u32>().unwrap()
}

/// Errors in contacting TheTVDB
#[derive(Debug)]
pub enum TvdbError {
    SeriesNotFound,
    CommunicationError{reason: String},
    DataError{reason: String},
    Cancelled,
}

#[derive(Debug,Clone)]
pub struct SeriesSearchResult{
    pub seriesid: u32, // seriesid is preferred over id according to TVDB wiki
    pub seriesname: String,
    pub language: String,
    pub overview: Option<String>,
    pub banner: Option<String>,
    pub imdb_id: Option<String>,
    //pub firstaired: Date,
    pub network: Option<String>,
    pub zap2it_id: Option<String>,

    api: Tvdb,
}

#[derive(Debug,Clone)]
pub struct Tvdb{
    key: String,
}

impl Tvdb{
    fn new(key: String) -> Tvdb{
        Tvdb{key: key}
    }

    /// Searches for a given series name.
    fn search(&self, seriesname: String, lang: String) -> Result<Vec<SeriesSearchResult>, TvdbError>{
        let client = Client::new();

        let formatted_url = format!("http://thetvdb.com/api/GetSeries.php?seriesname={}", seriesname);
        let url = Url::parse(&formatted_url).ok().expect("invalid URL");
        println!("Getting {}", url);

        let res = client.get(url)
            .header(Connection::close())
            .send();

        let mut res = match res {
            Err(e) => return Err(TvdbError::CommunicationError{reason: "Error contacting TVDB".to_owned()}), // FIXME: http://stackoverflow.com/questions/28911833/error-handling-best-practices
            Ok(r) => r
        };

        // Read the Response.
        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        // Parse XML
        let tree = xmltree::Element::parse(body.as_bytes());

        // Convert XML into structs
        let mut results : Vec<SeriesSearchResult> = vec![];

        for child in tree.children.iter(){

            fn get_text(child: &xmltree::Element, x: &str) -> Option<String>{
                child.get_child(x).and_then(|id_child| id_child.text.clone())
            }

            let r = SeriesSearchResult{
                seriesid:   intify(&get_text(child, "seriesid").expect("Search result XML missing 'seriesid' element")),
                seriesname: get_text(child, "SeriesName").expect("Search result XML Missing 'SeriesName' element"),
                language:   get_text(child, "language").expect("Search result XML missing 'language' element"),
                overview:   get_text(child, "Overview"),
                banner:     get_text(child, "banner"),
                imdb_id:    get_text(child, "IMDB_ID"),
                //firstaired: Date,
                network:    get_text(child, "Network"),
                zap2it_id:  get_text(child, "zap2it_id"),

                api: self.clone(), // TODO: Is there better way of allowing EpisodeInfo.episode(..) to access the key?
            };

            results.push(r);
        }

        if results.is_empty(){
            return Err(TvdbError::SeriesNotFound);
        }

        return Ok(results);
    }
}

struct EpisodeInfo{
    id: u32, //id
    // Combined_episodenumber
    // Combined_season
    // DVD_chapter
    // DVD_discid
    // DVD_episodenumber
    // DVD_season
    // Director
    // EpImgFlag
    episodename: String, // EpisodeName
    // EpisodeNumber
    // FirstAired
    // GuestStars
    // IMDB_ID
    // Language
    // Overview
    // ProductionCode
    // Rating
    // RatingCount
    // SeasonNumber
    // Writer
    // absolute_number
    // airsafter_season
    // airsbefore_episode
    // airsbefore_season
    // filename
    // lastupdated
    // seasonid
    // seriesid
    // thumb_added
    // thumb_height
    // thumb_width
}

impl SeriesSearchResult{
    fn episode(&self, season: u32, episode: u32) -> Result<EpisodeInfo, TvdbError>{
        // <mirrorpath>/api/<apikey>/series/{seriesid}/default/{season}/{episode}/{language}.xml
        println!("{} s{}e{}", self.seriesname, season, episode);

        let client = Client::new();

        let formatted_url = format!("http://thetvdb.com/api/{apikey}/series/{seriesid}/default/{season}/{episode}/{language}.xml",
                                    apikey=self.api.key,
                                    seriesid=self.seriesid,
                                    language=self.language,
                                    season=season,
                                    episode=episode,
                                    );
        let url = Url::parse(&formatted_url).ok().expect("invalid URL");
        println!("Getting {}", url);

        // Perform request
        let res = client.get(url)
            .header(Connection::close())
            .send();

        let mut res = match res {
            Err(e) => return Err(TvdbError::CommunicationError{reason: "Error contacting TVDB".to_owned()}), // FIXME: http://stackoverflow.com/questions/28911833/error-handling-best-practices
            Ok(r) => r
        };

        // Read the Response.
        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        // Parse XML
        let tree = xmltree::Element::parse(body.as_bytes());
        let root = tree.children.first().unwrap();

        fn get_text(child: &xmltree::Element, x: &str) -> Option<String>{
            child.get_child(x).and_then(|id_child| id_child.text.clone())
        }

        // Convert XML into struct
        Ok(EpisodeInfo{
            id: intify(&get_text(root, "id").unwrap()),
            episodename: get_text(root, "EpisodeName").unwrap(),
        })
    }
}

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

    const APIKEY: &'static str = "0629B785CE550C8D";

    #[test]
    fn search() {
        let api = Tvdb::new(APIKEY.to_owned());
        let sr = api.search("scrubs".to_owned(), "en".to_owned());
        assert!(sr.ok().unwrap()[0].seriesname == "Scrubs");
    }

    #[test]
    fn nonexist() {
        let api = Tvdb::new(APIKEY.to_owned());
        let sr = api.search("ladlkgdklfgsdfglk".to_owned(), "en".to_owned());
        assert!(sr.is_err());
    }

    #[test]
    fn epinfo_default(){
        let api = Tvdb::new(APIKEY.to_owned());
        let sr = api.search("scrubs".to_owned(), "en".to_owned()).ok().unwrap();
        let ep = sr[0].episode(1, 2).ok().unwrap();
        assert!(ep.episodename == "My Mentor");
    }

}
<|endoftext|>


<commit_before>macro_rules! FSM {
    (@inner command $cur:ident;$callback:block;$new_state:ident{$($new_el:ident:$new_el_val:expr),*}) => (
        {
            $callback;
            Some(States::$new_state{context: $new_state{$($new_el:$new_el_val),*}})
        }
    );
    (@inner command $cur:ident;$callback:block;) => ({$callback; Some(States::__SameState__)});
    (@inner command $cur:ident; ;$new_state:ident{$($new_el:ident:$new_el_val:expr),*}) => ({
        Some(States::$new_state{context: $new_state{$($new_el:$new_el_val),*}})
    });
    (@inner command $cur:ident ; ;) => (Some(States::__SameState__));
(
    $machine:ident ($initial:ident{$($init_field:ident:$init_val:expr),*})
    commands:($($commands:ident),*)

    $(($state:ident $sel:ident{$($el:ident:$typ:ty),*}
        >> $income:block
        << $outcome:block
        $({$cmd:ident;$($callback:block)*;$($new_state:ident{$($new_el:ident:$new_el_val:expr),*})*})*
    ))*
) => (
    mod $machine {
        trait CanDoJob {
            fn do_job(&mut self, cmd: &Commands) -> Option<States>;
            fn leave(&self) -> Result<(), ()>;
            fn enter(&self) -> Result<(), ()>;
        }

        $(
        #[derive(Debug)]
        #[derive(PartialEq)]
        struct $state{$($el:$typ),*}

        impl CanDoJob for $state {
            fn do_job(&mut self, cmd: & Commands) -> Option<States> {
                let $sel = self;
                match *cmd {
                    $(Commands::$cmd => {FSM!(@inner command self;$($callback)*;$($new_state{$($new_el:$new_el_val),*})*)})*
                    _ => None
                }
            }
            fn leave(&self) -> Result<(), ()> {
                let $sel = self;
                $outcome
                Ok(())
            }
            fn enter(&self) -> Result<(), ()> {
                let $sel = self;
                $income
                Ok(())
            }
        }
        )*

        #[derive(Debug)]
        #[derive(PartialEq)]
        enum States {
            __SameState__,
            $($state {context: $state}),*
        }

        #[derive(Debug)]
        #[derive(PartialEq)]
        pub enum Commands {
            $($commands),*
        }

        pub struct Machine {
            state: States
        }
        pub fn new() -> Machine {
            let context = $initial{$($init_field: $init_val),*};
            context.enter().unwrap();
            Machine{state: States::$initial{context: context}}
        }

        impl Machine {
            pub fn execute(&mut self, cmd: & Commands) {
                match {
                    match self.state {
                        States::__SameState__ => None,
                        $(States::$state{ ref mut context } => context.do_job(cmd)),*
                    }
                } {
                    Some(x) => {
                        match x {
                            States::__SameState__ => {},
                            _ => {
                                self.change_state(x)
                            }
                        }
                    },
                    None => println!("Wrong operation {:?} for {:?} state!", cmd, self.state)
                }
            }
            fn change_state(&mut self, new_state: States) {
                match self.state {
                    States::__SameState__ => Ok(()),
                    $(States::$state{ ref mut context } => context.leave()),*
                }.unwrap();
                self.state = new_state;
                match self.state {
                    States::__SameState__ => Ok(()),
                    $(States::$state{ ref mut context } => context.enter()),*
                }.unwrap();
            }
        }
    }
)
}

#[cfg(test)]
mod tests {

    FSM!(
    Mach1 (New{x:0})

    commands:(Configure, ConfigureDone, Drop)

    ( New context{x: i16}
        >> {println!("Enter {:?}", context)}
        << {println!("Leave {:?}", context)}
        {Configure;     {println!("In New with context val: {}", context.x);};     InConfig{x:context.x+1, y:0}}
        {ConfigureDone; ; New{x:0}}
    )
    ( InConfig context{x:i16, y:i16}
        >> {println!("Enter {:?}", context)}
        << {println!("Leave {:?}", context)}
        {ConfigureDone; ; Operational{x:context.x+1, y:context.y+1}}
    )
    ( Operational context{x:i16, y:i16}
        >> {println!("Enter {:?}", context)}
        << {println!("Leave {:?}", context)}
        {ConfigureDone; ; }
        {Drop; ; New{x:context.x+1}}
    )
    );

    #[test]
    fn test1() {
        let mut m = Mach1::new();
        m.execute(&Mach1::Commands::Configure);
        m.execute(&Mach1::Commands::ConfigureDone);
        m.execute(&Mach1::Commands::Configure);
        m.execute(&Mach1::Commands::Drop);
        m.execute(&Mach1::Commands::Configure);
        m.execute(&Mach1::Commands::ConfigureDone);
        m.execute(&Mach1::Commands::ConfigureDone);
        m.execute(&Mach1::Commands::ConfigureDone);
    }
}
<commit_msg>Make simplest state machine possible.<commit_after>macro_rules! FSM {
    (@inner next $new_state:ident{$($new_el:ident:$new_el_val:expr),*}) => (
        $new_state{$($new_el:$new_el_val),*}
    );
    (@inner next $new_state:ident) => (
        $new_state{}
    );

    (@inner command $cur:ident;$callback:block;$new_state:ident$({$($new_el:ident:$new_el_val:expr),*})*) => (
        {
            $callback;
            Some(States::$new_state{context: FSM!(@inner next $new_state$({$($new_el:$new_el_val),*})*)})
        }
    );
    (@inner command $cur:ident;$callback:block;) => ({$callback; Some(States::__SameState__)});
    (@inner command $cur:ident; ;$new_state:ident$({$($new_el:ident:$new_el_val:expr),*})*) => ({
        Some(States::$new_state{context: FSM!(@inner next $new_state$({$($new_el:$new_el_val),*})*)})
    });
    (@inner command $cur:ident ; ;) => (Some(States::__SameState__));

    (@inner >> $sel:ident $income:block) => (
            fn enter(&self) -> Result<(), ()> {
                let $sel = self;
                $income
                Ok(())
            }
    );
    (@inner << $sel:ident $outcome:block) => (
            fn leave(&self) -> Result<(), ()> {
                let $sel = self;
                $outcome
                Ok(())
            }
    );
    (@inner >> $sel:ident) => (
            fn enter(&self) -> Result<(), ()> {
                Ok(())
            }
    );
    (@inner << $sel:ident) => (
            fn leave(&self) -> Result<(), ()> {
                Ok(())
            }
    );
    (@inner params $state:ident {$($el:ident:$typ:ty);*}) => (
        #[derive(Debug)]
        #[derive(PartialEq)]
        struct $state {$($el:$typ),*}
    );
    (@inner params $state:ident) => (
        #[derive(Debug)]
        #[derive(PartialEq)]
        struct $state {}
    );
    (@inner initial $initial:ident{$($init_field:ident:$init_val:expr),*}) => ($initial{$($init_field: $init_val),*});
    (@inner initial $initial:ident) => ($initial{});
(
    $machine:ident ($initial:ident$({$($init_field:ident:$init_val:expr),*})*)
    states[$($states:ident),*]
    commands[$($commands:ident),*]

    $(($state:ident $sel:ident$({$($el:ident:$typ:ty);*})*
        $(>> $income:block)*
        $(<< $outcome:block)*
        $($cmd:ident $($callback:block)* => $($new_state:ident$({$($new_el:ident:$new_el_val:expr),*})*)*;)*
    ))*
) => (
    mod $machine {
    use super::*;
        trait CanDoJob {
            fn do_job(&mut self, cmd: &Commands) -> Option<States>;
            fn leave(&self) -> Result<(), ()>;
            fn enter(&self) -> Result<(), ()>;
        }

        $(
        FSM!(@inner params $state $({$($el:$typ);*})*);

        impl CanDoJob for $state {
            fn do_job(&mut self, cmd: & Commands) -> Option<States> {
                let $sel = self;
                match *cmd {
                    $(Commands::$cmd => {FSM!(@inner command self;$($callback)*;$($new_state$({$($new_el:$new_el_val),*})*)*)})*
                    _ => None
                }
            }

            FSM!(@inner >> $sel $($income)*);
            FSM!(@inner << $sel $($outcome)*);
        }
        )*

        #[derive(Debug)]
        #[derive(PartialEq)]
        enum States {
            __SameState__,
            $($states {context: $states}),*
        }

        #[derive(Debug)]
        #[derive(PartialEq)]
        pub enum Commands {
            $($commands),*
        }

        pub struct Machine {
            state: States
        }
        pub fn new() -> Machine {
            let context = FSM!(@inner initial $initial $({$($init_field: $init_val),*})*);
            context.enter().unwrap();
            Machine{state: States::$initial{context: context}}
        }

        impl Machine {
            pub fn execute(&mut self, cmd: & Commands) -> Result<(),()>{
                match {
                    match self.state {
                        States::__SameState__ => None,
                        $(States::$state{ ref mut context } => context.do_job(cmd)),*
                    }
                } {
                    Some(x) => {
                        match x {
                            States::__SameState__ => {},
                            _ => {
                                self.change_state(x)
                            }
                        };Ok(())
                    },
                    None => {println!("Wrong operation {:?} for {:?} state!", cmd, self.state); Err(())}
                }
            }
            fn change_state(&mut self, new_state: States) {
                match self.state {
                    States::__SameState__ => Ok(()),
                    $(States::$state{ ref mut context } => context.leave()),*
                }.unwrap();
                self.state = new_state;
                match self.state {
                    States::__SameState__ => Ok(()),
                    $(States::$state{ ref mut context } => context.enter()),*
                }.unwrap();
            }
        }
    }
)
}

#[cfg(test)]
mod tests {
    fn tes(x:i16) {
        println!("x:{}",x);
    }

    FSM!(
    Mach1 (New{x:0})

    states[New,InConfig,Operational]
    commands[Configure, ConfigureDone, Drop]

    ( New context{x: i16}
        >> {println!("Enter {:?}", context)}
        << {println!("Leave {:?}", context)}
        Configure     {println!("In New with context val: {}", context.x);} =>     InConfig{x:context.x+1, y:0};
        ConfigureDone => New{x:0};
    )
    ( InConfig context{x:i16; y:i16}
        >> {println!("Enter {:?}", context)}
        << {println!("Leave {:?}", context)}
        ConfigureDone {tes(context.x)}=> Operational;
    )
    ( Operational context
        >> {println!("Enter {:?}", context)}
        << {println!("Leave {:?}", context)}
        ConfigureDone =>;
        Drop => New{x:0};
    )
    );

    FSM!(
    Mach2 (State1)

    states[State1,State2,State3]
    commands[ToState1, ToState2, ToState3]

    ( State1 context
        ToState2 => State2;
    )
    ( State2 context
        ToState3 => State3;
    )
    ( State3 context
        ToState1 => State1;
    )
    );

    #[test]
    fn test1() {
        let mut m = Mach1::new();
        m.execute(&Mach1::Commands::Configure);
        m.execute(&Mach1::Commands::ConfigureDone);
        m.execute(&Mach1::Commands::Configure);
        m.execute(&Mach1::Commands::Drop);
        m.execute(&Mach1::Commands::Configure);
        m.execute(&Mach1::Commands::ConfigureDone);
        m.execute(&Mach1::Commands::ConfigureDone);
        m.execute(&Mach1::Commands::ConfigureDone);
    }

    #[test]
    #[should_panic]
    fn test2() {
        let mut m = Mach2::new();
        m.execute(&Mach2::Commands::ToState2).unwrap();
        m.execute(&Mach2::Commands::ToState3).unwrap();
        m.execute(&Mach2::Commands::ToState1).unwrap();
        m.execute(&Mach2::Commands::ToState3).unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate libc;

mod binding;
mod class;
mod types;
mod unsafe_binding;
mod util;

#[test]
fn it_works() {
}
<commit_msg>Reexport classes to crate level<commit_after>extern crate libc;

mod binding;
mod class;
mod types;
mod unsafe_binding;
mod util;

pub use class::array::Array;
pub use class::class::Class;
pub use class::hash::Hash;
pub use class::object::Object;
pub use class::string::RString;

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