<commit_before>mod set_like;
mod unused_slots;

use itertools::*;
use ordermap::OrderMap;
use rand::*;
use std::cmp::max;
use std::time::*;

use crusader::*;
use dps::*;
use formation::*;
use self::unused_slots::unused_slots;
use self::set_like::*;

const EXPLORATION_COEF: f64 = 1.6;

pub struct FormationSearch<'a> {
    state: State<'a>,
    search_root: Node<'a>,
}

impl<'a> FormationSearch<'a> {
    pub fn new(formation: Formation<'a>, crusaders: &'a [Crusader]) -> Self {
        FormationSearch {
            state: State { formation, crusaders },
            search_root: Node::new(),
        }
    }

    pub fn perform_search(&mut self, max_time: Duration) {
        let empty_positions = self.state.formation.empty_positions().count();
        for _ in 0..empty_positions {
            let loop_start = Instant::now();
            while loop_start.elapsed() < max_time && !self.search_root.is_complete() {
                self.search_root.expand(&mut self.state.clone())
            }
            {
                let mut children = self.search_root.children
                    .iter()
                    .collect::<Vec<_>>();
                children.sort_by_key(|&(_, ref c)| c.times_checked);
                for (placement, child) in children {
                    println!("{:?} checked {} times", placement, child.times_checked);
                }
            }
            let current_dps = self.state.formation.total_dps();
            let options = self.search_root.children
                .drain(..)
                .filter(|&(_, ref c)| c.highest_dps_seen >= current_dps)
                .collect::<Vec<_>>();
            let best_option = if options.iter().any(|&(_, ref c)| c.is_complete()) {
                options.into_iter()
                    .max_by_key(|&(_, ref c)| (c.highest_dps_seen, c.times_checked))
            } else {
                options.into_iter()
                    .max_by_key(|&(_, ref c)| (c.times_checked, c.highest_dps_seen))
            };
            if let Some((placement, child)) = best_option {
                self.state.place(placement);
                self.state.formation.print();
                self.search_root = child;
            } else {
                break;
            }
        }
    }

    pub fn formation(self) -> Formation<'a> {
        self.state.formation
    }
}

type Placement<'a> = (usize, &'a Crusader);

#[derive(Debug, PartialEq, Eq)]
enum Progress {
    Expandable,
    FullyExpanded,
    Complete,
}

struct Node<'a> {
    highest_dps_seen: Dps,
    total_dps_seen: Dps,
    progress: Progress,
    children: OrderMap<Placement<'a>, Node<'a>>,
    times_checked: u32,
}

impl<'a> Node<'a> {
    fn new() -> Self {
        Node {
            progress: Progress::Expandable,
            highest_dps_seen: Default::default(),
            total_dps_seen: Default::default(),
            children: Default::default(),
            times_checked: 0,
        }
    }

    fn expand(&mut self, state: &mut State<'a>) {
        match self.progress {
            Progress::Expandable => {
                if let Some(placement) = state.random_placement(&self.children) {
                    state.place(placement);
                    let mut child = Node::new();
                    child.check_single_formation(state);
                    self.maybe_assign_dps(child.highest_dps_seen);
                    self.total_dps_seen += state.formation.total_dps();
                    self.children.insert(placement, child);
                } else {
                    self.progress = Progress::FullyExpanded;
                    return self.expand(state);
                }
            }
            Progress::FullyExpanded => self.to_best_child(state, Self::expand),
            Progress::Complete => panic!("expand called on complete node"),
        }
        self.times_checked += 1;
    }

    fn best_child(&mut self) -> Option<(Placement<'a>, &mut Self)> {
        let log_total = (self.times_checked as f64).ln();
        let highest_dps = self.highest_dps_seen.0;
        let score = |c: &Self| {
            let normalized_dps_seen = c.total_dps_seen.0 / (c.times_checked as f64) / highest_dps;
            let exploration_adjustment = EXPLORATION_COEF
                * (log_total / c.times_checked as f64).sqrt();
            Dps(normalized_dps_seen + exploration_adjustment)
        };
        self.children.iter_mut()
            .filter(|&(_, ref v)| !v.is_complete())
            .map(|(&k, v)| (k, v))
            .max_by_key(|&(_, ref c1)| score(c1))
    }

    fn check_single_formation(&mut self, state: &mut State<'a>) {
        match self.progress {
            Progress::Expandable => {
                if let Some(placement) = state.random_placement(&EmptySet) {
                    state.place(placement);
                    let search_dps;
                    if let Some(child) = self.children.get_mut(&placement) {
                        child.check_single_formation(state);
                        search_dps = child.highest_dps_seen;
                    } else {
                        state.fill_formation_randomly();
                        search_dps = state.formation.total_dps()
                    }
                    self.maybe_assign_dps(search_dps);
                    self.total_dps_seen += state.formation.total_dps();
                } else {
                    self.progress = Progress::Complete;
                    self.maybe_assign_dps(state.formation.total_dps());
                    self.total_dps_seen += state.formation.total_dps();
                }
            }
            Progress::FullyExpanded => self.to_best_child(state, Self::check_single_formation),
            Progress::Complete => {}
        }
        self.times_checked += 1;
    }

    fn maybe_assign_dps(&mut self, dps: Dps) {
        if dps > self.highest_dps_seen {
            self.highest_dps_seen = dps;
        }
    }

    fn is_complete(&self) -> bool {
        self.progress == Progress::Complete
    }

    fn to_best_child(
        &mut self,
        state: &mut State<'a>,
        action: fn(&mut Self, &mut State<'a>),
    ) {
        let mut search_dps = None;
        if let Some((placement, child)) = self.best_child() {
            state.place(placement);
            action(child, state);
            search_dps = Some(child.highest_dps_seen);
        }
        if let Some(dps) = search_dps {
            self.maybe_assign_dps(dps);
            self.total_dps_seen += dps;
        } else {
            self.progress = Progress::Complete;
        }
    }
}

#[derive(Clone)]
struct State<'a> {
    formation: Formation<'a>,
    crusaders: &'a [Crusader],
}

impl<'a> State<'a> {
    fn fill_formation_randomly(&mut self) {
        while let Some(placement) = self.random_placement(&EmptySet) {
            self.place(placement)
        }
    }

    fn random_placement<T>(&self, exclude: &T) -> Option<Placement<'a>> where
        T: SetLike<Placement<'a>>,
    {
        let mut rng = thread_rng();
        let num_placements = self.formation.empty_positions().count()
            * unused_slots(&self.formation, self.crusaders).count()
            - exclude.len();
        let selection = rng.gen_range(0, max(1, num_placements));
        self.formation.empty_positions()
            .cartesian_product(unused_slots(&self.formation, self.crusaders))
            .filter(|p| !exclude.contains(p))
            .nth(selection)
    }

    fn place(&mut self, (position, crusader): Placement<'a>) {
        self.formation.place_crusader(position, crusader);
    }
}

#[test]
fn fill_formation_randomly_fills_formation_until_formation_is_full() {
    let crusaders = test_crusaders();
    let mut state = search_state(&crusaders);
    state.fill_formation_randomly();
    assert_eq!(0, state.formation.empty_positions().count());
}

#[test]
fn fill_formation_randomly_stops_when_no_more_crusaders() {
    let crusaders = vec![test_crusaders().pop().unwrap()];
    let mut state = search_state(&crusaders);
    state.fill_formation_randomly();
    assert_eq!(1, state.formation.empty_positions().count());
}

#[test]
fn expanding_expandable_node_always_adds_new_child() {
    let crusaders = test_crusaders();
    let state = search_state(&crusaders);
    let mut search = Node::new();
    for _ in 0..6 {
        assert_eq!(Progress::Expandable, search.progress);
        search.expand(&mut state.clone());
    }
    // Expand one more time. Whether determining FullyExpanded is eager when 1
    // choice left, or lazy when attempting to expand and no choices is an impl
    // detail
    search.expand(&mut state.clone());
    assert_eq!(Progress::FullyExpanded, search.progress);
}

#[test]
fn expanding_updates_highest_dps_seen() {
    let crusaders = test_crusaders();
    let mut state = search_state(&crusaders);
    let mut search = Node::new();
    assert_eq!(Dps(0.0), search.highest_dps_seen);
    search.expand(&mut state);
    // Sanity check, make sure the formation was filled
    assert_eq!(0, state.formation.empty_positions().count());
    assert_eq!(state.formation.total_dps(), search.highest_dps_seen);
}

#[test]
fn expand_eventually_completes_node() {
    let crusaders = test_crusaders();
    let state = search_state(&crusaders);
    let mut search = Node::new();
    for _ in 0..1000 {
        if search.progress == Progress::Complete {
            break;
        }
        search.expand(&mut state.clone());
    }
    assert_eq!(Progress::Complete, search.progress);
}

#[cfg(test)]
fn test_formation<'a>() -> Formation<'a> {
    let positions = vec![
        Coordinate::new(0, 0),
        Coordinate::new(0, 1),
    ];
    Formation::empty(positions)
}

#[cfg(test)]
fn test_crusaders() -> Vec<Crusader> {
    vec![
        Crusader::new(CrusaderName::JimTheLumberjack, Level(5000), None),
        Crusader::new(CrusaderName::VeronicaTheAndroidArcher, Level(5000), None),
        Crusader::new(CrusaderName::SallyTheSuccubus, Level(5000), None),
    ]
}

#[cfg(test)]
fn search_state(crusaders: &[Crusader]) -> State {
    State {
        formation: test_formation(),
        crusaders,
    }
}

#[cfg(test)]
mod benchmarks {
    extern crate test;
    use create_user_data;
    use self::test::Bencher;
    use super::*;

    #[bench]
    fn bench_expand_root_node(b: &mut Bencher) {
        let positions = vec![
            Coordinate::new(0, 0),
            Coordinate::new(0, 1),
            Coordinate::new(0, 2),
            Coordinate::new(0, 3),
            Coordinate::new(1, 0),
            Coordinate::new(1, 1),
            Coordinate::new(1, 2),
            Coordinate::new(2, 1),
            Coordinate::new(2, 2),
            Coordinate::new(3, 1),
        ];
        let formation = Formation::empty(positions);
        let crusaders = create_user_data().unlocked_crusaders(None);
        let mut search = Node::new();
        let state = State { formation, crusaders: &crusaders };

        b.iter(|| {
            search.expand(&mut state.clone())
        })
    }

    #[bench]
    fn bench_search_root_after_1k_expands(b: &mut Bencher) {
        let positions = vec![
            Coordinate::new(0, 0),
            Coordinate::new(0, 1),
            Coordinate::new(0, 2),
            Coordinate::new(0, 3),
            Coordinate::new(1, 0),
            Coordinate::new(1, 1),
            Coordinate::new(1, 2),
            Coordinate::new(2, 1),
            Coordinate::new(2, 2),
            Coordinate::new(3, 1),
        ];
        let formation = Formation::empty(positions);
        let crusaders = create_user_data().unlocked_crusaders(None);
        let mut search = Node::new();
        let state = State { formation, crusaders: &crusaders };
        for _ in 0..1_000 {
            search.expand(&mut state.clone());
        }

        b.iter(|| {
            search.check_single_formation(&mut state.clone())
        })
    }
}
<commit_msg>Fix over-convergence of search<commit_after>mod set_like;
mod unused_slots;

use itertools::*;
use ordermap::OrderMap;
use rand::*;
use std::cmp::max;
use std::time::*;

use crusader::*;
use dps::*;
use formation::*;
use self::unused_slots::unused_slots;
use self::set_like::*;

const EXPLORATION_COEF: f64 = 1.4;

pub struct FormationSearch<'a> {
    state: State<'a>,
    search_root: Node<'a>,
}

impl<'a> FormationSearch<'a> {
    pub fn new(formation: Formation<'a>, crusaders: &'a [Crusader]) -> Self {
        FormationSearch {
            state: State { formation, crusaders },
            search_root: Node::new(),
        }
    }

    pub fn perform_search(&mut self, max_time: Duration) {
        let empty_positions = self.state.formation.empty_positions().count();
        for _ in 0..empty_positions {
            let loop_start = Instant::now();
            while loop_start.elapsed() < max_time && !self.search_root.is_complete() {
                self.search_root.expand(&mut self.state.clone())
            }
            {
                let mut children = self.search_root.children
                    .iter()
                    .collect::<Vec<_>>();
                children.sort_by_key(|&(_, ref c)| c.times_checked);
                for (placement, child) in children {
                    println!("{:?} checked {} times", placement, child.times_checked);
                }
            }
            let current_dps = self.state.formation.total_dps();
            let options = self.search_root.children
                .drain(..)
                .filter(|&(_, ref c)| c.highest_dps_seen >= current_dps)
                .collect::<Vec<_>>();
            let best_option = if options.iter().any(|&(_, ref c)| c.is_complete()) {
                options.into_iter()
                    .max_by_key(|&(_, ref c)| (c.highest_dps_seen, c.times_checked))
            } else {
                options.into_iter()
                    .max_by_key(|&(_, ref c)| (c.times_checked, c.highest_dps_seen))
            };
            if let Some((placement, child)) = best_option {
                self.state.place(placement);
                self.state.formation.print();
                self.search_root = child;
            } else {
                break;
            }
        }
    }

    pub fn formation(self) -> Formation<'a> {
        self.state.formation
    }
}

type Placement<'a> = (usize, &'a Crusader);

#[derive(Debug, PartialEq, Eq)]
enum Progress {
    Expandable,
    FullyExpanded,
    Complete,
}

// NOTE: We're storing/checking redundant information here due to how the
// tree is set up. e.g. Placing Grandmora and then Sally will not share data
// with placing Sally then Grandmora even if the formation is the same. The
// alternative would be to store everything in a flat map, where the key
// is the formation. What we have now is probably better than at least the
// naive implementation of the alternative, since that would require duplicating
// the vec of placements once per option, and would balloon memory usage.
// However, if we track the placements using some sort of persistent data
// structure, we may be able to see a decent boost from flattening the tree
struct Node<'a> {
    highest_dps_seen: Dps,
    total_dps_seen: Dps,
    progress: Progress,
    children: OrderMap<Placement<'a>, Node<'a>>,
    times_checked: u32,
}

impl<'a> Node<'a> {
    fn new() -> Self {
        Node {
            progress: Progress::Expandable,
            highest_dps_seen: Default::default(),
            total_dps_seen: Default::default(),
            children: Default::default(),
            times_checked: 0,
        }
    }

    fn expand(&mut self, state: &mut State<'a>) {
        match self.progress {
            Progress::Expandable => {
                if let Some(placement) = state.random_placement(&self.children) {
                    state.place(placement);
                    let mut child = Node::new();
                    child.check_single_formation(state);
                    self.track_dps_changes(state);
                    self.children.insert(placement, child);
                } else {
                    self.progress = Progress::FullyExpanded;
                    return self.expand(state);
                }
            }
            Progress::FullyExpanded => self.to_best_child(state, Self::expand),
            Progress::Complete => panic!("expand called on complete node"),
        }
        self.times_checked += 1;
    }

    fn best_child(&mut self) -> Option<(Placement<'a>, &mut Self)> {
        let log_total = (self.times_checked as f64).ln();
        let highest_dps = self.highest_dps_seen.0;
        let score = |c: &Self| {
            let normalized_dps_seen = c.total_dps_seen.0 / (c.times_checked as f64) / highest_dps;
            let exploration_adjustment = EXPLORATION_COEF
                * (log_total / c.times_checked as f64).sqrt();
            Dps(normalized_dps_seen + exploration_adjustment)
        };
        self.children.iter_mut()
            .filter(|&(_, ref v)| !v.is_complete())
            .map(|(&k, v)| (k, v))
            .max_by_key(|&(_, ref c1)| score(c1))
    }

    fn check_single_formation(&mut self, state: &mut State<'a>) {
        match self.progress {
            Progress::Expandable => {
                if let Some(placement) = state.random_placement(&EmptySet) {
                    state.place(placement);
                    if let Some(child) = self.children.get_mut(&placement) {
                        child.check_single_formation(state);
                    } else {
                        state.fill_formation_randomly();
                    }
                } else {
                    self.progress = Progress::Complete;
                }
                self.track_dps_changes(state);
            }
            Progress::FullyExpanded => self.to_best_child(state, Self::check_single_formation),
            Progress::Complete => {}
        }
        self.times_checked += 1;
    }

    fn track_dps_changes(&mut self, state: &State) {
        let dps = state.formation.total_dps();
        self.total_dps_seen += dps;
        if dps > self.highest_dps_seen {
            self.highest_dps_seen = dps;
        }
    }

    fn is_complete(&self) -> bool {
        self.progress == Progress::Complete
    }

    fn to_best_child(
        &mut self,
        state: &mut State<'a>,
        action: fn(&mut Self, &mut State<'a>),
    ) {
        let mut found_child = false;
        if let Some((placement, child)) = self.best_child() {
            state.place(placement);
            action(child, state);
            found_child = true;
        }
        if found_child {
            self.track_dps_changes(state);
        } else {
            self.progress = Progress::Complete;
        }
    }
}

#[derive(Clone)]
struct State<'a> {
    formation: Formation<'a>,
    crusaders: &'a [Crusader],
}

impl<'a> State<'a> {
    fn fill_formation_randomly(&mut self) {
        while let Some(placement) = self.random_placement(&EmptySet) {
            self.place(placement)
        }
    }

    fn random_placement<T>(&self, exclude: &T) -> Option<Placement<'a>> where
        T: SetLike<Placement<'a>>,
    {
        let mut rng = thread_rng();
        let num_placements = self.formation.empty_positions().count()
            * unused_slots(&self.formation, self.crusaders).count()
            - exclude.len();
        let selection = rng.gen_range(0, max(1, num_placements));
        self.formation.empty_positions()
            .cartesian_product(unused_slots(&self.formation, self.crusaders))
            .filter(|p| !exclude.contains(p))
            .nth(selection)
    }

    fn place(&mut self, (position, crusader): Placement<'a>) {
        self.formation.place_crusader(position, crusader);
    }
}

#[test]
fn fill_formation_randomly_fills_formation_until_formation_is_full() {
    let crusaders = test_crusaders();
    let mut state = search_state(&crusaders);
    state.fill_formation_randomly();
    assert_eq!(0, state.formation.empty_positions().count());
}

#[test]
fn fill_formation_randomly_stops_when_no_more_crusaders() {
    let crusaders = vec![test_crusaders().pop().unwrap()];
    let mut state = search_state(&crusaders);
    state.fill_formation_randomly();
    assert_eq!(1, state.formation.empty_positions().count());
}

#[test]
fn expanding_expandable_node_always_adds_new_child() {
    let crusaders = test_crusaders();
    let state = search_state(&crusaders);
    let mut search = Node::new();
    for _ in 0..6 {
        assert_eq!(Progress::Expandable, search.progress);
        search.expand(&mut state.clone());
    }
    // Expand one more time. Whether determining FullyExpanded is eager when 1
    // choice left, or lazy when attempting to expand and no choices is an impl
    // detail
    search.expand(&mut state.clone());
    assert_eq!(Progress::FullyExpanded, search.progress);
}

#[test]
fn expanding_updates_highest_dps_seen() {
    let crusaders = test_crusaders();
    let mut state = search_state(&crusaders);
    let mut search = Node::new();
    assert_eq!(Dps(0.0), search.highest_dps_seen);
    search.expand(&mut state);
    // Sanity check, make sure the formation was filled
    assert_eq!(0, state.formation.empty_positions().count());
    assert_eq!(state.formation.total_dps(), search.highest_dps_seen);
}

#[test]
fn expand_eventually_completes_node() {
    let crusaders = test_crusaders();
    let state = search_state(&crusaders);
    let mut search = Node::new();
    for _ in 0..1000 {
        if search.progress == Progress::Complete {
            break;
        }
        search.expand(&mut state.clone());
    }
    assert_eq!(Progress::Complete, search.progress);
}

#[cfg(test)]
fn test_formation<'a>() -> Formation<'a> {
    let positions = vec![
        Coordinate::new(0, 0),
        Coordinate::new(0, 1),
    ];
    Formation::empty(positions)
}

#[cfg(test)]
fn test_crusaders() -> Vec<Crusader> {
    vec![
        Crusader::new(CrusaderName::JimTheLumberjack, Level(5000), None),
        Crusader::new(CrusaderName::VeronicaTheAndroidArcher, Level(5000), None),
        Crusader::new(CrusaderName::SallyTheSuccubus, Level(5000), None),
    ]
}

#[cfg(test)]
fn search_state(crusaders: &[Crusader]) -> State {
    State {
        formation: test_formation(),
        crusaders,
    }
}

#[cfg(test)]
mod benchmarks {
    extern crate test;
    use create_user_data;
    use self::test::Bencher;
    use super::*;

    #[bench]
    fn bench_expand_root_node(b: &mut Bencher) {
        let positions = vec![
            Coordinate::new(0, 0),
            Coordinate::new(0, 1),
            Coordinate::new(0, 2),
            Coordinate::new(0, 3),
            Coordinate::new(1, 0),
            Coordinate::new(1, 1),
            Coordinate::new(1, 2),
            Coordinate::new(2, 1),
            Coordinate::new(2, 2),
            Coordinate::new(3, 1),
        ];
        let formation = Formation::empty(positions);
        let crusaders = create_user_data().unlocked_crusaders(None);
        let mut search = Node::new();
        let state = State { formation, crusaders: &crusaders };

        b.iter(|| {
            search.expand(&mut state.clone())
        })
    }

    #[bench]
    fn bench_search_root_after_1k_expands(b: &mut Bencher) {
        let positions = vec![
            Coordinate::new(0, 0),
            Coordinate::new(0, 1),
            Coordinate::new(0, 2),
            Coordinate::new(0, 3),
            Coordinate::new(1, 0),
            Coordinate::new(1, 1),
            Coordinate::new(1, 2),
            Coordinate::new(2, 1),
            Coordinate::new(2, 2),
            Coordinate::new(3, 1),
        ];
        let formation = Formation::empty(positions);
        let crusaders = create_user_data().unlocked_crusaders(None);
        let mut search = Node::new();
        let state = State { formation, crusaders: &crusaders };
        for _ in 0..1_000 {
            search.expand(&mut state.clone());
        }

        b.iter(|| {
            search.check_single_formation(&mut state.clone())
        })
    }
}
<|endoftext|>


<commit_before>//! This implements metafactory construction from a closure.
//!
//! Using some macro magic, it supports up to 12 arguments.
//!
//! ```
//! use metafactory::metafactory;
//! use metafactory::AsFactoryExt;
//!
//! fn main() {
//!     // build a metafactory from multi-argument closure.
//!     let meta_factory = metafactory(
//!         |a: int, b: bool, c: &str| {
//!             format!("invoked with {}, {}, {}", a, b, c)
//!         }
//!     );
//!
//!     // create a factory instance this closure.
//!     // argument factories can be constructed from cloneable sources.
//!     let factory = meta_factory.new(vec![
//!         metafactory(3i).new(Vec::new()).ok().unwrap(),
//!         metafactory(false).new(Vec::new()).ok().unwrap(),
//!         metafactory("hello").new(Vec::new()).ok().unwrap(),
//!     ]).ok().unwrap().as_factory_of::<String>().unwrap();
//!
//!     // value should match what factory produced.
//!     assert_eq!("invoked with 3, false, hello", factory.take());
//! }
//! ```

use std::any::Any;
use std::rc::Rc;
use std::cell::RefCell;

use typedef::TypeDef;

use super::super::{ MetaFactory, ToMetaFactory, AsFactoryExt };
use super::super::factory::{ Factory, Getter };
use super::super::error::{ FactoryErrorKind, ArgCountMismatch, ArgTypeMismatch };

#[macro_escape]
mod macros {
    macro_rules! assert_arg_count(
        ($expected:expr, $specified:expr)
        =>
        (
            if $expected != $specified {
                return Err(
                    FactoryErrorKind::ArgCountMismatch(
                        ArgCountMismatch::new($expected, $specified)
                    )
                )
            }
        )
    )

    macro_rules! try_unwrap_factory(
        ($T:ty, $factory:expr, $index:ident)
        =>
        (
            match $factory.as_factory_of::<$T>() {
                Some(factory) => factory,
                None => {
                    return Err(
                        FactoryErrorKind::ArgTypeMismatch(
                            ArgTypeMismatch::new(TypeDef::of::<$T>(), $index)
                        )
                    );
                }
            }
        )
    )

    macro_rules! count_exprs {
        () => (0);
        ($head:expr $(, $tail:expr)*) => (1 + count_exprs!($($tail),*));
    }

    macro_rules! many_arg_closure_impl(
        ($GetterScope:ident: $($_A:ident,$_AT:ty,$_a:ident)|+)
        =>
        (
            /// Contains references to parent factories, so they
            /// can be invoked directly to get arguments for the closure.
            struct $GetterScope<$($_A:'static), +, T:'static> {
                // References to argument factories.
                $(
                    $_a: Factory<$_AT>,
                )+
                // Closure reference.
                closure: Rc<RefCell<|$($_AT), +|:'static -> T>>,
            }

            /// Implement `ToMetaFactory` conversion for closures
            /// |A1, A2, ... AN| -> T
            impl<$($_A:'static), +, T:'static> ToMetaFactory for (|$($_AT), +|:'static -> T) {
                fn to_metafactory<'a>(self) -> Box<MetaFactory + 'a> {
                    box Rc::new(RefCell::new(self))
                }
            }

            /// Use the closure reference itself as metafactory. For now I did
            /// not notice any issues with this, but the Rc can be put into some
            /// wrapper struct, and then we could implement MetaFactory for that.
            impl<$($_A:'static), +, T:'static> MetaFactory for Rc<RefCell<|$($_AT), +|:'static -> T>> {
                fn get_type(&self) -> TypeDef {
                    TypeDef::of::<T>()
                }

                fn get_arg_types(&self) -> Vec<TypeDef> {
                    // Just go over the types and output TypeDefs for them.
                    vec![$(TypeDef::of::<$_AT>()), +]
                }

                #[allow(unused_assignments)]
                fn new(&self, arg_getters: Vec<Box<Any>>) -> Result<Box<Any>, FactoryErrorKind> {
                    // Calculate required argument count from specified type count.
                    let required_argc = count_exprs!($($_A),+);

                    // Return error if count does not match.
                    assert_arg_count!(required_argc, arg_getters.len());

                    let mut getters = arg_getters;
                    let mut arg_index = 0;
                    $(
                        let $_a; // Factory object of correct type.
                        { // Scope so we can reuse `maybe_factory`.
                            // Already checked the argc above, so unwrap.
                            let maybe_factory = getters.remove(0).unwrap();

                            // Return error if factory does not have a correct type.
                            $_a = try_unwrap_factory!($_AT, maybe_factory, arg_index);

                            arg_index += 1;
                        }
                    )+

                    // Build factory instance for THIS closure copy, passing
                    // all parent factories as arguments.
                    let factory = box Factory::<T>::new(
                        box $GetterScope::<$($_AT), +, T> {
                            $(
                                $_a: $_a,
                            )+
                            closure: self.clone(),
                        }
                    ) as Box<Any>;

                    Ok(factory)
                }
            }

            /// Use GetterScope as a value getter. This is part
            /// that is actually used at runtime, and would benefit from
            /// any further optimizations.
            impl<'a, $($_A:'static), +, T: 'static> Getter<T> for $GetterScope<$($_AT), +, T> {
                fn take(&self) -> T {
                    (*(self.closure.borrow_mut().deref_mut()))(
                        $(
                            self.$_a.take()
                        ),+
                    )
                }

                fn boxed_clone(&self) -> Box<Getter<T> + 'static> {
                    $(
                        let $_a = &self.$_a;
                    )+
                    box $GetterScope::<$($_AT), +, T> {
                        $(
                            $_a: $_a.clone()
                        ),
                        +,
                        closure: self.closure.clone(),
                    }
                }
            }
        )
    )
}

many_arg_closure_impl!(
    GetterScope:
    A, A, a
)

many_arg_closure_impl!(
    GetterScope2:
    A1, A1, a1 |
    A2, A2, a2
)

many_arg_closure_impl!(
    GetterScope3:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3
)

many_arg_closure_impl!(
    GetterScope4:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4
)

many_arg_closure_impl!(
    GetterScope5:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5
)

many_arg_closure_impl!(
    GetterScope6:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5 |
    A6, A6, a6
)

many_arg_closure_impl!(
    GetterScope7:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5 |
    A6, A6, a6 |
    A7, A7, a7
)

many_arg_closure_impl!(
    GetterScope8:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5 |
    A6, A6, a6 |
    A7, A7, a7 |
    A8, A8, a8
)

many_arg_closure_impl!(
    GetterScope9:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5 |
    A6, A6, a6 |
    A7, A7, a7 |
    A8, A8, a8 |
    A9, A9, a9
)

many_arg_closure_impl!(
    GetterScope10:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5 |
    A6, A6, a6 |
    A7, A7, a7 |
    A8, A8, a8 |
    A9, A9, a9 |
    A10, A10, a10
)

many_arg_closure_impl!(
    GetterScope11:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5 |
    A6, A6, a6 |
    A7, A7, a7 |
    A8, A8, a8 |
    A9, A9, a9 |
    A10, A10, a10 |
    A11, A11, a11
)

many_arg_closure_impl!(
    GetterScope12:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5 |
    A6, A6, a6 |
    A7, A7, a7 |
    A8, A8, a8 |
    A9, A9, a9 |
    A10, A10, a10 |
    A11, A11, a11 |
    A12, A12, a12
)

#[cfg(test)]
mod test {
    use std::any::Any;
    use typedef::TypeDef;
    use super::super::super::{ ToMetaFactory, MetaFactory, AsFactoryExt }; // super
    use super::super::super::error::{ FactoryErrorKind }; // really super

    #[test]
    fn should_work_with_1_arg_closure() {
        assert_eq!(
            create(
                |ok: bool| {
                    if ok { 5i } else { 6i }
                },
                vec![
                    arg(false)
                ]
            ).as_factory_of::<int>().unwrap().take(),
            6i
        );
    }

    #[test]
    fn should_work_with_2_arg_closure() {
        assert_eq!(
            create(
                |a: u8, b: u8| {
                    (a + b) as uint
                },
                vec![
                    arg(13u8), arg(12u8)
                ]
            ).as_factory_of::<uint>().unwrap().take(),
            13u + 12u
        );
    }

    #[test]
    fn should_return_arg_count_mismatch_for_3_arg_closure_with_2_args() {
        match maybe_create(
            |a: i8, b: i8, c:i8| {
                a + b + c
            },
            vec![
                arg(1i8), arg(1i8)
            ]
        ) {
            Err(FactoryErrorKind::ArgCountMismatch(e)) => {
                assert_eq!(e.expected, 3);
                assert_eq!(e.specified, 2);
            },
            _ => panic!("Expected ArgCountMismatch error!"),
        }
    }

    #[test]
    fn should_return_arg_type_mismatch_for_bad_arg_0() {
        match maybe_create(
            |a: i8, b: i8, c:i8| {
                a + b + c
            },
            vec![
                arg(true), arg(1i8), arg(1i8)
            ]
        ) {
            Err(FactoryErrorKind::ArgTypeMismatch(e)) => {
                assert_eq!(e.expected_type, TypeDef::of::<i8>());
                assert_eq!(e.argument_index, 0);
            },
            _ => panic!("Expected ArgTypeMismatch error!"),
        }
    }

    #[test]
    fn should_return_arg_type_mismatch_for_bad_arg_1() {
        match maybe_create(
            |a: i8, b: i8, c:i8| {
                a + b + c
            },
            vec![
                arg(1i8), arg("hello :)"), arg(1i8)
            ]
        ) {
            Err(FactoryErrorKind::ArgTypeMismatch(e)) => {
                assert_eq!(e.expected_type, TypeDef::of::<i8>());
                assert_eq!(e.argument_index, 1);
            },
            _ => panic!("Expected ArgTypeMismatch error!"),
        }
    }

    #[test]
    fn should_return_arg_type_mismatch_for_bad_arg_2() {
        match maybe_create(
            |a: i8, b: i8, c:i8| {
                a + b + c
            },
            vec![
            arg(1i8), arg(1i8), arg(box 23.3f64)
            ]
        ) {
            Err(FactoryErrorKind::ArgTypeMismatch(e)) => {
                assert_eq!(e.expected_type, TypeDef::of::<i8>());
                assert_eq!(e.argument_index, 2);
            },
            _ => panic!("Expected ArgTypeMismatch error!"),
        }
    }

    #[test]
    fn should_return_arg_type_mismatch_for_bad_arg_1_and_2() {
        match maybe_create(
            |a: i8, b: i8, c:i8| {
                a + b + c
            },
            vec![
            arg(1i8), arg(false), arg(box 23.3f64)
            ]
        ) {
            Err(FactoryErrorKind::ArgTypeMismatch(e)) => {
                assert_eq!(e.expected_type, TypeDef::of::<i8>());
                assert_eq!(e.argument_index, 1);
            },
            _ => panic!("Expected ArgTypeMismatch error!"),
        }
    }

    #[test]
    fn should_work_with_12_arg_closure() {
        assert_eq!(
            create(
                |a1: i16, a2: i16, a3: i16, a4: i16, a5: i16, a6: i16,
                 a7: i16, a8: i16, a9: i16, a10: i16, a11: i16, a12: i16| {
                    a1 + a2 + a3 + a4 + a5 + a6 + a7
                    + a8 + a9 + a10 + a11 + a12
                },
                vec![
                    arg(3i16), arg(3i16), arg(3i16), arg(3i16), arg(3i16),
                    arg(3i16), arg(3i16), arg(3i16), arg(3i16), arg(3i16),
                    arg(3i16), arg(3i16)
                ]
            ).as_factory_of::<i16>().unwrap().take(),
            3i16 * 12
        );
    }

    fn create<T: ToMetaFactory>(source: T, args: Vec<Box<Any>>) -> Box<Any> {
        source.to_metafactory().new(args).ok().unwrap()
    }

    fn maybe_create<T: ToMetaFactory>(source: T, args: Vec<Box<Any>>) -> Result<Box<Any>, FactoryErrorKind>  {
        source.to_metafactory().new(args)
    }

    fn arg<T: ToMetaFactory>(source: T) -> Box<Any> {
        source.to_metafactory().new(Vec::new()).ok().unwrap()
    }
}
<commit_msg>Update code after rust bug fix for 'static.<commit_after>//! This implements metafactory construction from a closure.
//!
//! Using some macro magic, it supports up to 12 arguments.
//!
//! ```
//! use metafactory::metafactory;
//! use metafactory::AsFactoryExt;
//!
//! fn main() {
//!     // build a metafactory from multi-argument closure.
//!     let meta_factory = metafactory(
//!         |a: int, b: bool, c: &'static str| {
//!             format!("invoked with {}, {}, {}", a, b, c)
//!         }
//!     );
//!
//!     // create a factory instance this closure.
//!     // argument factories can be constructed from cloneable sources.
//!     let factory = meta_factory.new(vec![
//!         metafactory(3i).new(Vec::new()).ok().unwrap(),
//!         metafactory(false).new(Vec::new()).ok().unwrap(),
//!         metafactory("hello").new(Vec::new()).ok().unwrap(),
//!     ]).ok().unwrap().as_factory_of::<String>().unwrap();
//!
//!     // value should match what factory produced.
//!     assert_eq!("invoked with 3, false, hello", factory.take());
//! }
//! ```

use std::any::Any;
use std::rc::Rc;
use std::cell::RefCell;

use typedef::TypeDef;

use super::super::{ MetaFactory, ToMetaFactory, AsFactoryExt };
use super::super::factory::{ Factory, Getter };
use super::super::error::{ FactoryErrorKind, ArgCountMismatch, ArgTypeMismatch };

#[macro_escape]
mod macros {
    macro_rules! assert_arg_count(
        ($expected:expr, $specified:expr)
        =>
        (
            if $expected != $specified {
                return Err(
                    FactoryErrorKind::ArgCountMismatch(
                        ArgCountMismatch::new($expected, $specified)
                    )
                )
            }
        )
    )

    macro_rules! try_unwrap_factory(
        ($T:ty, $factory:expr, $index:ident)
        =>
        (
            match $factory.as_factory_of::<$T>() {
                Some(factory) => factory,
                None => {
                    return Err(
                        FactoryErrorKind::ArgTypeMismatch(
                            ArgTypeMismatch::new(TypeDef::of::<$T>(), $index)
                        )
                    );
                }
            }
        )
    )

    macro_rules! count_exprs {
        () => (0);
        ($head:expr $(, $tail:expr)*) => (1 + count_exprs!($($tail),*));
    }

    macro_rules! many_arg_closure_impl(
        ($GetterScope:ident: $($_A:ident,$_AT:ty,$_a:ident)|+)
        =>
        (
            /// Contains references to parent factories, so they
            /// can be invoked directly to get arguments for the closure.
            struct $GetterScope<$($_A:'static), +, T:'static> {
                // References to argument factories.
                $(
                    $_a: Factory<$_AT>,
                )+
                // Closure reference.
                closure: Rc<RefCell<|$($_AT), +|:'static -> T>>,
            }

            /// Implement `ToMetaFactory` conversion for closures
            /// |A1, A2, ... AN| -> T
            impl<$($_A:'static), +, T:'static> ToMetaFactory for (|$($_AT), +|:'static -> T) {
                fn to_metafactory<'a>(self) -> Box<MetaFactory + 'a> {
                    box Rc::new(RefCell::new(self))
                }
            }

            /// Use the closure reference itself as metafactory. For now I did
            /// not notice any issues with this, but the Rc can be put into some
            /// wrapper struct, and then we could implement MetaFactory for that.
            impl<$($_A:'static), +, T:'static> MetaFactory for Rc<RefCell<|$($_AT), +|:'static -> T>> {
                fn get_type(&self) -> TypeDef {
                    TypeDef::of::<T>()
                }

                fn get_arg_types(&self) -> Vec<TypeDef> {
                    // Just go over the types and output TypeDefs for them.
                    vec![$(TypeDef::of::<$_AT>()), +]
                }

                #[allow(unused_assignments)]
                fn new(&self, arg_getters: Vec<Box<Any>>) -> Result<Box<Any>, FactoryErrorKind> {
                    // Calculate required argument count from specified type count.
                    let required_argc = count_exprs!($($_A),+);

                    // Return error if count does not match.
                    assert_arg_count!(required_argc, arg_getters.len());

                    let mut getters = arg_getters;
                    let mut arg_index = 0;
                    $(
                        let $_a; // Factory object of correct type.
                        { // Scope so we can reuse `maybe_factory`.
                            // Already checked the argc above, so unwrap.
                            let maybe_factory = getters.remove(0).unwrap();

                            // Return error if factory does not have a correct type.
                            $_a = try_unwrap_factory!($_AT, maybe_factory, arg_index);

                            arg_index += 1;
                        }
                    )+

                    // Build factory instance for THIS closure copy, passing
                    // all parent factories as arguments.
                    let factory = box Factory::<T>::new(
                        box $GetterScope::<$($_AT), +, T> {
                            $(
                                $_a: $_a,
                            )+
                            closure: self.clone(),
                        }
                    ) as Box<Any>;

                    Ok(factory)
                }
            }

            /// Use GetterScope as a value getter. This is part
            /// that is actually used at runtime, and would benefit from
            /// any further optimizations.
            impl<'a, $($_A:'static), +, T: 'static> Getter<T> for $GetterScope<$($_AT), +, T> {
                fn take(&self) -> T {
                    (*(self.closure.borrow_mut().deref_mut()))(
                        $(
                            self.$_a.take()
                        ),+
                    )
                }

                fn boxed_clone(&self) -> Box<Getter<T> + 'static> {
                    $(
                        let $_a = &self.$_a;
                    )+
                    box $GetterScope::<$($_AT), +, T> {
                        $(
                            $_a: $_a.clone()
                        ),
                        +,
                        closure: self.closure.clone(),
                    }
                }
            }
        )
    )
}

many_arg_closure_impl!(
    GetterScope:
    A, A, a
)

many_arg_closure_impl!(
    GetterScope2:
    A1, A1, a1 |
    A2, A2, a2
)

many_arg_closure_impl!(
    GetterScope3:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3
)

many_arg_closure_impl!(
    GetterScope4:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4
)

many_arg_closure_impl!(
    GetterScope5:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5
)

many_arg_closure_impl!(
    GetterScope6:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5 |
    A6, A6, a6
)

many_arg_closure_impl!(
    GetterScope7:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5 |
    A6, A6, a6 |
    A7, A7, a7
)

many_arg_closure_impl!(
    GetterScope8:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5 |
    A6, A6, a6 |
    A7, A7, a7 |
    A8, A8, a8
)

many_arg_closure_impl!(
    GetterScope9:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5 |
    A6, A6, a6 |
    A7, A7, a7 |
    A8, A8, a8 |
    A9, A9, a9
)

many_arg_closure_impl!(
    GetterScope10:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5 |
    A6, A6, a6 |
    A7, A7, a7 |
    A8, A8, a8 |
    A9, A9, a9 |
    A10, A10, a10
)

many_arg_closure_impl!(
    GetterScope11:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5 |
    A6, A6, a6 |
    A7, A7, a7 |
    A8, A8, a8 |
    A9, A9, a9 |
    A10, A10, a10 |
    A11, A11, a11
)

many_arg_closure_impl!(
    GetterScope12:
    A1, A1, a1 |
    A2, A2, a2 |
    A3, A3, a3 |
    A4, A4, a4 |
    A5, A5, a5 |
    A6, A6, a6 |
    A7, A7, a7 |
    A8, A8, a8 |
    A9, A9, a9 |
    A10, A10, a10 |
    A11, A11, a11 |
    A12, A12, a12
)

#[cfg(test)]
mod test {
    use std::any::Any;
    use typedef::TypeDef;
    use super::super::super::{ ToMetaFactory, MetaFactory, AsFactoryExt }; // super
    use super::super::super::error::{ FactoryErrorKind }; // really super

    #[test]
    fn should_work_with_1_arg_closure() {
        assert_eq!(
            create(
                |ok: bool| {
                    if ok { 5i } else { 6i }
                },
                vec![
                    arg(false)
                ]
            ).as_factory_of::<int>().unwrap().take(),
            6i
        );
    }

    #[test]
    fn should_work_with_2_arg_closure() {
        assert_eq!(
            create(
                |a: u8, b: u8| {
                    (a + b) as uint
                },
                vec![
                    arg(13u8), arg(12u8)
                ]
            ).as_factory_of::<uint>().unwrap().take(),
            13u + 12u
        );
    }

    #[test]
    fn should_return_arg_count_mismatch_for_3_arg_closure_with_2_args() {
        match maybe_create(
            |a: i8, b: i8, c:i8| {
                a + b + c
            },
            vec![
                arg(1i8), arg(1i8)
            ]
        ) {
            Err(FactoryErrorKind::ArgCountMismatch(e)) => {
                assert_eq!(e.expected, 3);
                assert_eq!(e.specified, 2);
            },
            _ => panic!("Expected ArgCountMismatch error!"),
        }
    }

    #[test]
    fn should_return_arg_type_mismatch_for_bad_arg_0() {
        match maybe_create(
            |a: i8, b: i8, c:i8| {
                a + b + c
            },
            vec![
                arg(true), arg(1i8), arg(1i8)
            ]
        ) {
            Err(FactoryErrorKind::ArgTypeMismatch(e)) => {
                assert_eq!(e.expected_type, TypeDef::of::<i8>());
                assert_eq!(e.argument_index, 0);
            },
            _ => panic!("Expected ArgTypeMismatch error!"),
        }
    }

    #[test]
    fn should_return_arg_type_mismatch_for_bad_arg_1() {
        match maybe_create(
            |a: i8, b: i8, c:i8| {
                a + b + c
            },
            vec![
                arg(1i8), arg("hello :)"), arg(1i8)
            ]
        ) {
            Err(FactoryErrorKind::ArgTypeMismatch(e)) => {
                assert_eq!(e.expected_type, TypeDef::of::<i8>());
                assert_eq!(e.argument_index, 1);
            },
            _ => panic!("Expected ArgTypeMismatch error!"),
        }
    }

    #[test]
    fn should_return_arg_type_mismatch_for_bad_arg_2() {
        match maybe_create(
            |a: i8, b: i8, c:i8| {
                a + b + c
            },
            vec![
            arg(1i8), arg(1i8), arg(box 23.3f64)
            ]
        ) {
            Err(FactoryErrorKind::ArgTypeMismatch(e)) => {
                assert_eq!(e.expected_type, TypeDef::of::<i8>());
                assert_eq!(e.argument_index, 2);
            },
            _ => panic!("Expected ArgTypeMismatch error!"),
        }
    }

    #[test]
    fn should_return_arg_type_mismatch_for_bad_arg_1_and_2() {
        match maybe_create(
            |a: i8, b: i8, c:i8| {
                a + b + c
            },
            vec![
            arg(1i8), arg(false), arg(box 23.3f64)
            ]
        ) {
            Err(FactoryErrorKind::ArgTypeMismatch(e)) => {
                assert_eq!(e.expected_type, TypeDef::of::<i8>());
                assert_eq!(e.argument_index, 1);
            },
            _ => panic!("Expected ArgTypeMismatch error!"),
        }
    }

    #[test]
    fn should_work_with_12_arg_closure() {
        assert_eq!(
            create(
                |a1: i16, a2: i16, a3: i16, a4: i16, a5: i16, a6: i16,
                 a7: i16, a8: i16, a9: i16, a10: i16, a11: i16, a12: i16| {
                    a1 + a2 + a3 + a4 + a5 + a6 + a7
                    + a8 + a9 + a10 + a11 + a12
                },
                vec![
                    arg(3i16), arg(3i16), arg(3i16), arg(3i16), arg(3i16),
                    arg(3i16), arg(3i16), arg(3i16), arg(3i16), arg(3i16),
                    arg(3i16), arg(3i16)
                ]
            ).as_factory_of::<i16>().unwrap().take(),
            3i16 * 12
        );
    }

    fn create<T: ToMetaFactory>(source: T, args: Vec<Box<Any>>) -> Box<Any> {
        source.to_metafactory().new(args).ok().unwrap()
    }

    fn maybe_create<T: ToMetaFactory>(source: T, args: Vec<Box<Any>>) -> Result<Box<Any>, FactoryErrorKind>  {
        source.to_metafactory().new(args)
    }

    fn arg<T: ToMetaFactory>(source: T) -> Box<Any> {
        source.to_metafactory().new(Vec::new()).ok().unwrap()
    }
}
<|endoftext|>


<commit_before>//! The module that contains the request code.

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::io::Error;
use std::str::from_utf8;
use std::sync::mpsc::channel;
use std::time::Duration;
use super::Method;
use curl::easy::{Easy, List};
use futures::{BoxFuture, failed, Future};
use response::Response;
use tokio_core::reactor::Handle;
use tokio_curl::Session;
use url::Url;

#[cfg(feature = "rustc-serialization")]
use rustc_serialize;

#[cfg(feature = "serde-serialization")]
use serde;
#[cfg(feature = "serde-serialization")]
use serde_json;

/// The default low byte rate threshold.
///
/// See [`Request::lowspeed_limit`](struct.Request.html#method.lowspeed_limit)
/// for more information.
pub const LOW_SPEED_LIMIT: u32 = 10;

/// The default low speed time threshold in seconds.
///
/// See [`Request::lowspeed_limit`](struct.Request.html#method.lowspeed_limit)
/// for more information.
pub const LOW_SPEED_TIME: u32 = 10;

/// The default redirect threshold for a single request.
///
/// cURL will follow this many redirects by default before aborting
/// the request. See [`Request::max_redirects`](struct.Request.html#method.max_redirects)
/// for more information.
pub const MAX_REDIRECTS: u32 = 15;

/// Represents an HTTP request.
///
/// While this can be used directly (and _must_ be for special HTTP verbs, it is
/// preferred to use the [`get`](fn.get.html), [`post`](fn.post.html), etc. functions
/// since they are shorter.
pub struct Request {
    body: Option<Vec<u8>>,
    follow_redirects: bool,
    handle: Option<Easy>,
    headers: HashMap<String, String>,
    lowspeed_limits: Option<(u32, Duration)>,
    max_redirects: u32,
    method: Method,
    params: HashMap<String, Vec<String>>,
    timeout: Option<Duration>,
    url: Url
}

impl Request {
    /// Creates a new instance of `Request`.
    pub fn new(url: &Url, method: Method) -> Self {
        Request {
            body: None,
            follow_redirects: true,
            handle: None,
            headers: HashMap::new(),
            lowspeed_limits: Some((LOW_SPEED_LIMIT, Duration::from_secs(LOW_SPEED_TIME as u64))),
            max_redirects: MAX_REDIRECTS,
            method: method,
            params: HashMap::new(),
            timeout: None,
            url: url.clone()
        }
    }

    /// Sets the body of the request as raw byte array.
    pub fn body(mut self, body: &AsRef<[u8]>) -> Self {
        self.body = Some(Vec::from(body.as_ref()));
        self
    }

    /// Sets the option whether to follow 3xx-redirects or not.
    ///
    /// Defaults to `true`.
    pub fn follow_redirects(mut self, follow: bool) -> Self {
        self.follow_redirects = follow;
        self
    }

    /// Sets an HTTP header for the request. Remove headers by passing
    /// an empty value.
    ///
    /// ## Duplicates
    /// In spite of the W3C allowing multiple headers with the same name
    /// (https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2),
    /// we do not so that we get a cleaner and leaner API.
    ///
    /// If you really need to specify multiple header values for a single
    /// header, just set a comma-separated list here, as that, as per standards,
    /// is equivalent to sending multiple headers with the same name (see link).
    /// If your server code can't deal with that, go and burn. :P
    pub fn header(mut self, name: &str, value: &str) -> Self {
        if value.is_empty() {
            self.headers.remove(name);
        } else {
            let value = value.to_owned();
            match self.headers.entry(name.to_owned()) {
                Entry::Occupied(mut e) => { e.insert(value); () }
                Entry::Vacant(e) => { e.insert(value); () }
            }
        }
        self
    }

    /// Serializes the given object to JSON and uses that as the request body.
    /// Also automatically sets the `Content-Type` to `application/json`.
    #[cfg(feature = "rustc-serialization")]
    pub fn json<T: rustc_serialize::Encodable>(self, body: &T) -> Self {
        self.set_json(rustc_serialize::json::encode(body).unwrap().into_bytes())
    }

    /// Serializes the given object to JSON and uses that as the request body.
    /// Also automatically sets the `Content-Type` to `application/json`.
    #[cfg(feature = "serde-serialization")]
    pub fn json<T: serde::Serialize>(self, body: &T) -> Self {
        self.set_json(serde_json::to_vec(body).unwrap())
    }

    /// Sets the thresholds which, when reached, aborts a download due to too
    /// low speeds.
    ///
    /// Pass 0 for either parameter to disable lowspeed limiting.
    ///
    /// ## Remarks
    /// `bytes` sets the minimum average amount of bytes transferred in `per_duration`
    /// time. If this number is not reached, cURL will abort the transfer because the transfer
    /// speed is too low.
    ///
    /// The values here default to [`LOW_SPEED_LIMIT`](constant.LOW_SPEED_LIMIT.html) and
    /// [`LOW_SPEED_TIME`](constant.LOW_SPEED_TIME.html).
    pub fn lowspeed_limit(mut self, bytes: u32, per_duration: Duration) -> Self {
        self.lowspeed_limits = if bytes > 0 && per_duration > Duration::from_secs(0) {
            Some((bytes, per_duration))
        } else {
            None
        };
        self
    }

    /// Sets the maximum amount of redirects cURL will follow when
    /// [`Request::follow_redirects`](#method.follow_redirects) is
    /// enabled.
    pub fn max_redirects(mut self, max_redirects: u32) -> Self {
        self.max_redirects = max_redirects;
        self
    }

    /// Adds a URL parameter to the request.
    ///
    /// ## Duplicates
    /// Duplicates are allowed to enable things like query parameters that use
    /// PHP array syntax (`&key[]=value`).
    pub fn param(mut self, name: &str, value: &str) -> Self {
        let value = value.to_owned();
        match self.params.entry(name.to_owned()) {
            Entry::Occupied(mut e) => e.get_mut().push(value),
            Entry::Vacant(e) => { e.insert(vec![value]); () }
        };
        self
    }

    /// Creates a new `Session` on the specified event loop to send the HTTP request through
    /// and returns a future that fires off the request, parses the response and resolves to
    /// a `Response`-struct on success.
    pub fn send(self, h: Handle) -> BoxFuture<Response, Error> {
        self.send_with_session(&Session::new(h))
    }

    /// Uses the given `Session` to send the HTTP request through and returns a future that
    /// fires off the request, parses the response and resolves to a `Response`-struct on success.
    pub fn send_with_session(mut self, session: &Session) -> BoxFuture<Response, Error> {
        {
            let mut query_pairs = self.url.query_pairs_mut();
            for (key, values) in self.params {
                for value in values {
                    query_pairs.append_pair(&key, &value);
                }
            }
        }
        let headers = {
            let mut list = List::new();
            for (key, value) in self.headers {
                list.append(&format!("{}: {}", key.trim(), value.trim())).expect("Failed to append header value to (native cURL) header list.");
            }
            list
        };

        let mut easy = self.handle.unwrap_or_else(|| Easy::new());
        let (header_tx, header_rx) = channel();
        let (body_tx, body_rx) = channel();

        let config_res = {
            // Make the borrow checker happy
            let body = self.body;
            let follow_redirects = self.follow_redirects;
            let lowspeed_limits = self.lowspeed_limits;
            let max_redirects = self.max_redirects;
            let method = self.method;
            let timeout = self.timeout;
            let url = self.url;
            let mut first_header = true;

            // We cannot use try! here, since we're dealing with futures, not with Results
            Ok(())
                .and_then(|_| easy.accept_encoding(""))
                .and_then(|_| easy.custom_request(method.as_ref()))
                .and_then(|_| if follow_redirects {
                    easy.follow_location(true)
                        .and_then(|_| easy.max_redirections(max_redirects))
                } else {
                    Ok(())
                })
                .and_then(|_| easy.header_function(move |header| {
                    match from_utf8(header) {
                        Ok(s) => {
                            let s = s.trim(); // Headers are \n-separated
                            if !first_header && s.len() > 0 { // First header is HTTP status line, don't want that
                                let _ = header_tx.send(s.to_owned());
                            }
                            first_header = false;
                            true
                        },
                        Err(_) => false
                    }
                }))
                .and_then(|_| easy.http_headers(headers))
                .and_then(|_| if let Some((bytes, per_time)) = lowspeed_limits {
                    easy.low_speed_limit(bytes)
                        .and_then(|_| easy.low_speed_time(per_time))
                } else {
                    Ok(())
                })
                .and_then(|_| if method == Method::Head {
                    easy.nobody(true)
                } else {
                    Ok(())
                })
                .and_then(|_| if let Some(ref body) = body {
                    easy.post_fields_copy(body)
                } else {
                    Ok(())
                })
                .and_then(|_| if let Some(timeout) = timeout {
                    easy.timeout(timeout)
                } else {
                    Ok(())
                })
                .and_then(|_| easy.url(url.as_str()))
                .and_then(|_| easy.write_function(move |data| {
                    let _ = body_tx.send(Vec::from(data));
                    Ok(data.len())
                }))
        };

        match config_res {
            Ok(_) => session.perform(easy)
                            .map(move |ez| {
                                let body = body_rx.try_iter().fold(Vec::new(), |mut data, slice| {
                                    data.extend(slice);
                                    data
                                });
                                let headers = header_rx.try_iter().collect::<Vec<_>>();
                                (ez, headers, body)
                            })
                            .map(|(ez, headers, body)| Response::new(ez, headers, body))
                            .map_err(|err| err.into_error())
                            .boxed(),
            Err(error) => failed(error.into()).boxed()
        }
    }

    /// Set the maximum time the request is allowed to take.
    ///
    /// Disabled by default in favor of [`lowspeed_limit`]
    pub fn timeout(mut self, duration: Duration) -> Self {
        self.timeout = Some(duration);
        self
    }

    /// Uses the given cURL handle in the request process reusing its resources
    /// and improving performance.
    ///
    /// This is solely a way to improve performance, it is not necessary to call
    /// this method prior to firing off the request. The easy handle will be created
    /// automatically if necessary.
    pub fn use_handle(mut self, handle: Easy) -> Self {
        self.handle = Some(handle);
        self
    }

    #[cfg(any(feature = "rustc-serialization", feature = "serde-serialization"))]
    fn set_json(mut self, body: Vec<u8>) -> Self {
        self.body = Some(body);
        self.header("Content-Type", "application/json")
    }
}

impl Debug for Request {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        let len = if let Some(ref body) = self.body {
            body.len() as isize
        } else {
            -1isize
        };
        fmt.debug_struct(stringify!(Request))
            .field("body_len", &len)
            .field("follow_redirects", &self.follow_redirects)
            .field("headers", &self.headers)
            .field("method", &self.method)
            .field("params", &self.params)
            .field("reuses_handle", &self.handle.is_some())
            .field("url", &self.url)
            .finish()
    }
}

impl Display for Request {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        write!(fmt, "{} {}", self.method, self.url)
    }
}

#[cfg(test)]
mod tests {
    use ::{Method, Request};
    use url::Url;

    #[cfg(feature = "rustc-serialization")]
    use rustc_serialize;

    #[cfg(feature = "serde-serialization")]
    use serde_json;

    #[cfg_attr(feature = "rustc-serialization", derive(RustcEncodable, RustcDecodable))]
    #[cfg_attr(feature = "serde-serialization", derive(Serialize, Deserialize))]
    struct TestPayload {
        a: u32,
        b: u32
    }

    #[test]
    fn test_payload() {
        let r = Request::new(&Url::parse("http://google.com/").unwrap(), Method::Get)
            .body(&get_serialized_payload());
        assert!(r.body.is_some());
    }

    #[cfg(feature = "rustc-serialization")]
    fn get_serialized_payload() -> Vec<u8> {
        rustc_serialize::json::encode(&TestPayload { a: 10, b: 15 }).unwrap().into_bytes()
    }

    #[cfg(feature = "serde-serialization")]
    fn get_serialized_payload() -> Vec<u8> {
        serde_json::to_vec(&TestPayload { a: 10, b: 15}).unwrap()
    }
}<commit_msg>Simplify header method in Request<commit_after>//! The module that contains the request code.

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::io::Error;
use std::str::from_utf8;
use std::sync::mpsc::channel;
use std::time::Duration;
use super::Method;
use curl::easy::{Easy, List};
use futures::{BoxFuture, failed, Future};
use response::Response;
use tokio_core::reactor::Handle;
use tokio_curl::Session;
use url::Url;

#[cfg(feature = "rustc-serialization")]
use rustc_serialize;

#[cfg(feature = "serde-serialization")]
use serde;
#[cfg(feature = "serde-serialization")]
use serde_json;

/// The default low byte rate threshold.
///
/// See [`Request::lowspeed_limit`](struct.Request.html#method.lowspeed_limit)
/// for more information.
pub const LOW_SPEED_LIMIT: u32 = 10;

/// The default low speed time threshold in seconds.
///
/// See [`Request::lowspeed_limit`](struct.Request.html#method.lowspeed_limit)
/// for more information.
pub const LOW_SPEED_TIME: u32 = 10;

/// The default redirect threshold for a single request.
///
/// cURL will follow this many redirects by default before aborting
/// the request. See [`Request::max_redirects`](struct.Request.html#method.max_redirects)
/// for more information.
pub const MAX_REDIRECTS: u32 = 15;

/// Represents an HTTP request.
///
/// While this can be used directly (and _must_ be for special HTTP verbs, it is
/// preferred to use the [`get`](fn.get.html), [`post`](fn.post.html), etc. functions
/// since they are shorter.
pub struct Request {
    body: Option<Vec<u8>>,
    follow_redirects: bool,
    handle: Option<Easy>,
    headers: HashMap<String, String>,
    lowspeed_limits: Option<(u32, Duration)>,
    max_redirects: u32,
    method: Method,
    params: HashMap<String, Vec<String>>,
    timeout: Option<Duration>,
    url: Url
}

impl Request {
    /// Creates a new instance of `Request`.
    pub fn new(url: &Url, method: Method) -> Self {
        Request {
            body: None,
            follow_redirects: true,
            handle: None,
            headers: HashMap::new(),
            lowspeed_limits: Some((LOW_SPEED_LIMIT, Duration::from_secs(LOW_SPEED_TIME as u64))),
            max_redirects: MAX_REDIRECTS,
            method: method,
            params: HashMap::new(),
            timeout: None,
            url: url.clone()
        }
    }

    /// Sets the body of the request as raw byte array.
    pub fn body(mut self, body: &AsRef<[u8]>) -> Self {
        self.body = Some(Vec::from(body.as_ref()));
        self
    }

    /// Sets the option whether to follow 3xx-redirects or not.
    ///
    /// Defaults to `true`.
    pub fn follow_redirects(mut self, follow: bool) -> Self {
        self.follow_redirects = follow;
        self
    }

    /// Sets an HTTP header for the request. Remove headers by passing
    /// an empty value.
    ///
    /// ## Duplicates
    /// In spite of the W3C allowing multiple headers with the same name
    /// (https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2),
    /// we do not so that we get a cleaner and leaner API.
    ///
    /// If you really need to specify multiple header values for a single
    /// header, just set a comma-separated list here, as that, as per standards,
    /// is equivalent to sending multiple headers with the same name (see link).
    /// If your server code can't deal with that, go and burn. :P
    pub fn header(mut self, name: &str, value: &str) -> Self {
        if value.is_empty() {
            self.headers.remove(name);
        } else {
            self.headers.insert(name.to_owned(), value.to_owned());
        }
        self
    }

    /// Serializes the given object to JSON and uses that as the request body.
    /// Also automatically sets the `Content-Type` to `application/json`.
    #[cfg(feature = "rustc-serialization")]
    pub fn json<T: rustc_serialize::Encodable>(self, body: &T) -> Self {
        self.set_json(rustc_serialize::json::encode(body).unwrap().into_bytes())
    }

    /// Serializes the given object to JSON and uses that as the request body.
    /// Also automatically sets the `Content-Type` to `application/json`.
    #[cfg(feature = "serde-serialization")]
    pub fn json<T: serde::Serialize>(self, body: &T) -> Self {
        self.set_json(serde_json::to_vec(body).unwrap())
    }

    /// Sets the thresholds which, when reached, aborts a download due to too
    /// low speeds.
    ///
    /// Pass 0 for either parameter to disable lowspeed limiting.
    ///
    /// ## Remarks
    /// `bytes` sets the minimum average amount of bytes transferred in `per_duration`
    /// time. If this number is not reached, cURL will abort the transfer because the transfer
    /// speed is too low.
    ///
    /// The values here default to [`LOW_SPEED_LIMIT`](constant.LOW_SPEED_LIMIT.html) and
    /// [`LOW_SPEED_TIME`](constant.LOW_SPEED_TIME.html).
    pub fn lowspeed_limit(mut self, bytes: u32, per_duration: Duration) -> Self {
        self.lowspeed_limits = if bytes > 0 && per_duration > Duration::from_secs(0) {
            Some((bytes, per_duration))
        } else {
            None
        };
        self
    }

    /// Sets the maximum amount of redirects cURL will follow when
    /// [`Request::follow_redirects`](#method.follow_redirects) is
    /// enabled.
    pub fn max_redirects(mut self, max_redirects: u32) -> Self {
        self.max_redirects = max_redirects;
        self
    }

    /// Adds a URL parameter to the request.
    ///
    /// ## Duplicates
    /// Duplicates are allowed to enable things like query parameters that use
    /// PHP array syntax (`&key[]=value`).
    pub fn param(mut self, name: &str, value: &str) -> Self {
        let value = value.to_owned();
        match self.params.entry(name.to_owned()) {
            Entry::Occupied(mut e) => e.get_mut().push(value),
            Entry::Vacant(e) => { e.insert(vec![value]); () }
        };
        self
    }

    /// Creates a new `Session` on the specified event loop to send the HTTP request through
    /// and returns a future that fires off the request, parses the response and resolves to
    /// a `Response`-struct on success.
    pub fn send(self, h: Handle) -> BoxFuture<Response, Error> {
        self.send_with_session(&Session::new(h))
    }

    /// Uses the given `Session` to send the HTTP request through and returns a future that
    /// fires off the request, parses the response and resolves to a `Response`-struct on success.
    pub fn send_with_session(mut self, session: &Session) -> BoxFuture<Response, Error> {
        {
            let mut query_pairs = self.url.query_pairs_mut();
            for (key, values) in self.params {
                for value in values {
                    query_pairs.append_pair(&key, &value);
                }
            }
        }
        let headers = {
            let mut list = List::new();
            for (key, value) in self.headers {
                list.append(&format!("{}: {}", key.trim(), value.trim())).expect("Failed to append header value to (native cURL) header list.");
            }
            list
        };

        let mut easy = self.handle.unwrap_or_else(|| Easy::new());
        let (header_tx, header_rx) = channel();
        let (body_tx, body_rx) = channel();

        let config_res = {
            // Make the borrow checker happy
            let body = self.body;
            let follow_redirects = self.follow_redirects;
            let lowspeed_limits = self.lowspeed_limits;
            let max_redirects = self.max_redirects;
            let method = self.method;
            let timeout = self.timeout;
            let url = self.url;
            let mut first_header = true;

            // We cannot use try! here, since we're dealing with futures, not with Results
            Ok(())
                .and_then(|_| easy.accept_encoding(""))
                .and_then(|_| easy.custom_request(method.as_ref()))
                .and_then(|_| if follow_redirects {
                    easy.follow_location(true)
                        .and_then(|_| easy.max_redirections(max_redirects))
                } else {
                    Ok(())
                })
                .and_then(|_| easy.header_function(move |header| {
                    match from_utf8(header) {
                        Ok(s) => {
                            let s = s.trim(); // Headers are \n-separated
                            if !first_header && s.len() > 0 { // First header is HTTP status line, don't want that
                                let _ = header_tx.send(s.to_owned());
                            }
                            first_header = false;
                            true
                        },
                        Err(_) => false
                    }
                }))
                .and_then(|_| easy.http_headers(headers))
                .and_then(|_| if let Some((bytes, per_time)) = lowspeed_limits {
                    easy.low_speed_limit(bytes)
                        .and_then(|_| easy.low_speed_time(per_time))
                } else {
                    Ok(())
                })
                .and_then(|_| if method == Method::Head {
                    easy.nobody(true)
                } else {
                    Ok(())
                })
                .and_then(|_| if let Some(ref body) = body {
                    easy.post_fields_copy(body)
                } else {
                    Ok(())
                })
                .and_then(|_| if let Some(timeout) = timeout {
                    easy.timeout(timeout)
                } else {
                    Ok(())
                })
                .and_then(|_| easy.url(url.as_str()))
                .and_then(|_| easy.write_function(move |data| {
                    let _ = body_tx.send(Vec::from(data));
                    Ok(data.len())
                }))
        };

        match config_res {
            Ok(_) => session.perform(easy)
                            .map(move |ez| {
                                let body = body_rx.try_iter().fold(Vec::new(), |mut data, slice| {
                                    data.extend(slice);
                                    data
                                });
                                let headers = header_rx.try_iter().collect::<Vec<_>>();
                                (ez, headers, body)
                            })
                            .map(|(ez, headers, body)| Response::new(ez, headers, body))
                            .map_err(|err| err.into_error())
                            .boxed(),
            Err(error) => failed(error.into()).boxed()
        }
    }

    /// Set the maximum time the request is allowed to take.
    ///
    /// Disabled by default in favor of [`lowspeed_limit`]
    pub fn timeout(mut self, duration: Duration) -> Self {
        self.timeout = Some(duration);
        self
    }

    /// Uses the given cURL handle in the request process reusing its resources
    /// and improving performance.
    ///
    /// This is solely a way to improve performance, it is not necessary to call
    /// this method prior to firing off the request. The easy handle will be created
    /// automatically if necessary.
    pub fn use_handle(mut self, handle: Easy) -> Self {
        self.handle = Some(handle);
        self
    }

    #[cfg(any(feature = "rustc-serialization", feature = "serde-serialization"))]
    fn set_json(mut self, body: Vec<u8>) -> Self {
        self.body = Some(body);
        self.header("Content-Type", "application/json")
    }
}

impl Debug for Request {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        let len = if let Some(ref body) = self.body {
            body.len() as isize
        } else {
            -1isize
        };
        fmt.debug_struct(stringify!(Request))
            .field("body_len", &len)
            .field("follow_redirects", &self.follow_redirects)
            .field("headers", &self.headers)
            .field("method", &self.method)
            .field("params", &self.params)
            .field("reuses_handle", &self.handle.is_some())
            .field("url", &self.url)
            .finish()
    }
}

impl Display for Request {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        write!(fmt, "{} {}", self.method, self.url)
    }
}

#[cfg(test)]
mod tests {
    use ::{Method, Request};
    use url::Url;

    #[cfg(feature = "rustc-serialization")]
    use rustc_serialize;

    #[cfg(feature = "serde-serialization")]
    use serde_json;

    #[cfg_attr(feature = "rustc-serialization", derive(RustcEncodable, RustcDecodable))]
    #[cfg_attr(feature = "serde-serialization", derive(Serialize, Deserialize))]
    struct TestPayload {
        a: u32,
        b: u32
    }

    #[test]
    fn test_payload() {
        let r = Request::new(&Url::parse("http://google.com/").unwrap(), Method::Get)
            .body(&get_serialized_payload());
        assert!(r.body.is_some());
    }

    #[cfg(feature = "rustc-serialization")]
    fn get_serialized_payload() -> Vec<u8> {
        rustc_serialize::json::encode(&TestPayload { a: 10, b: 15 }).unwrap().into_bytes()
    }

    #[cfg(feature = "serde-serialization")]
    fn get_serialized_payload() -> Vec<u8> {
        serde_json::to_vec(&TestPayload { a: 10, b: 15}).unwrap()
    }
}<|endoftext|>


<commit_before>//! jsonrpc request
use serde::de::{Deserialize, Deserializer, SeqVisitor, MapVisitor, Error};
use serde_json::value;
use super::{Id, Params, Version, Value};

/// Represents jsonrpc request which is a method call.
#[derive(Debug, PartialEq, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct MethodCall {
	/// A String specifying the version of the JSON-RPC protocol.
	/// MUST be exactly "2.0".
	pub jsonrpc: Version,
	/// A String containing the name of the method to be invoked.
	pub method: String,
	/// A Structured value that holds the parameter values to be used
	/// during the invocation of the method. This member MAY be omitted.
	pub params: Option<Params>,
	/// An identifier established by the Client that MUST contain a String,
	/// Number, or NULL value if included. If it is not included it is assumed
	/// to be a notification.
	pub id: Id,
}

/// Represents jsonrpc request which is a notification.
#[derive(Debug, PartialEq, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Notification {
	/// A String specifying the version of the JSON-RPC protocol.
	/// MUST be exactly "2.0".
	pub jsonrpc: Version,
	/// A String containing the name of the method to be invoked.
	pub method: String,
	/// A Structured value that holds the parameter values to be used
	/// during the invocation of the method. This member MAY be omitted.
	pub params: Option<Params>
}

/// Represents single jsonrpc call.
#[derive(Debug, PartialEq)]
pub enum Call {
	MethodCall(MethodCall),
	Notification(Notification),
	Invalid
}

impl Deserialize for Call {
	fn deserialize<D>(deserializer: &mut D) -> Result<Call, D::Error>
	where D: Deserializer {
		let v = try!(Value::deserialize(deserializer));
		Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Call::Notification)
			.or_else(|_| Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Call::MethodCall))
			.map_err(|_| Error::custom("")) // types must match
			.or_else(|_: D::Error | Ok(Call::Invalid))
	}
}

/// Represents jsonrpc request.
#[derive(Debug, PartialEq)]
pub enum Request {
	Single(Call),
	Batch(Vec<Call>)
}

impl Deserialize for Request {
	fn deserialize<D>(deserializer: &mut D) -> Result<Request, D::Error>
	where D: Deserializer {
		let v = try!(Value::deserialize(deserializer));
		Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Request::Batch)
			.or_else(|_| Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Request::Single))
			.map_err(|_| Error::custom("")) // unreachable, but types must match
	}
}

#[test]
fn notification_deserialize() {
	use serde_json;
	use serde_json::Value;

	let s = r#"{"jsonrpc": "2.0", "method": "update", "params": [1,2]}"#;
	let deserialized: Notification = serde_json::from_str(s).unwrap();

	assert_eq!(deserialized, Notification {
		jsonrpc: Version::V2,
		method: "update".to_string(),
		params: Some(Params::Array(vec![Value::U64(1), Value::U64(2)]))
	});

	let s = r#"{"jsonrpc": "2.0", "method": "foobar"}"#;
	let deserialized: Notification = serde_json::from_str(s).unwrap();

	assert_eq!(deserialized, Notification {
		jsonrpc: Version::V2,
		method: "foobar".to_string(),
		params: None
	});

	let s = r#"{"jsonrpc": "2.0", "method": "update", "params": [1,2], "id": 1}"#;
	let deserialized: Result<Notification, _> = serde_json::from_str(s);
	assert!(deserialized.is_err())
}

#[test]
fn call_deserialize() {
	use serde_json;

	let s = r#"{"jsonrpc": "2.0", "method": "update", "params": [1]}"#;
	let deserialized: Call = serde_json::from_str(s).unwrap();
	assert_eq!(deserialized, Call::Notification(Notification {
		jsonrpc: Version::V2,
		method: "update".to_owned(),
		params: Some(Params::Array(vec![Value::U64(1)]))
	}));

	let s = r#"{"jsonrpc": "2.0", "method": "update", "params": [1], "id": 1}"#;
	let deserialized: Call = serde_json::from_str(s).unwrap();
	assert_eq!(deserialized, Call::MethodCall(MethodCall {
		jsonrpc: Version::V2,
		method: "update".to_owned(),
		params: Some(Params::Array(vec![Value::U64(1)])),
		id: Id::Num(1)
	}));
}

#[test]
fn request_deserialize_batch() {
	use serde_json;

	let s = r#"[1, {"jsonrpc": "2.0", "method": "update", "params": [1,2], "id": 1},{"jsonrpc": "2.0", "method": "update", "params": [1]}]"#;
	let deserialized: Request = serde_json::from_str(s).unwrap();
	assert_eq!(deserialized, Request::Batch(vec![
		Call::Invalid,
		Call::MethodCall(MethodCall {
			jsonrpc: Version::V2,
			method: "update".to_owned(),
			params: Some(Params::Array(vec![Value::U64(1), Value::U64(2)])),
			id: Id::Num(1)
		}),
		Call::Notification(Notification {
			jsonrpc: Version::V2,
			method: "update".to_owned(),
			params: Some(Params::Array(vec![Value::U64(1)]))
		})
	]))
}
<commit_msg>derive Serialize for MethodCall and Notification<commit_after>//! jsonrpc request
use serde::de::{Deserialize, Deserializer, SeqVisitor, MapVisitor, Error};
use serde_json::value;
use super::{Id, Params, Version, Value};

/// Represents jsonrpc request which is a method call.
#[derive(Debug, PartialEq, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct MethodCall {
	/// A String specifying the version of the JSON-RPC protocol.
	/// MUST be exactly "2.0".
	pub jsonrpc: Version,
	/// A String containing the name of the method to be invoked.
	pub method: String,
	/// A Structured value that holds the parameter values to be used
	/// during the invocation of the method. This member MAY be omitted.
	pub params: Option<Params>,
	/// An identifier established by the Client that MUST contain a String,
	/// Number, or NULL value if included. If it is not included it is assumed
	/// to be a notification.
	pub id: Id,
}

/// Represents jsonrpc request which is a notification.
#[derive(Debug, PartialEq, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Notification {
	/// A String specifying the version of the JSON-RPC protocol.
	/// MUST be exactly "2.0".
	pub jsonrpc: Version,
	/// A String containing the name of the method to be invoked.
	pub method: String,
	/// A Structured value that holds the parameter values to be used
	/// during the invocation of the method. This member MAY be omitted.
	pub params: Option<Params>
}

/// Represents single jsonrpc call.
#[derive(Debug, PartialEq)]
pub enum Call {
	MethodCall(MethodCall),
	Notification(Notification),
	Invalid
}

impl Deserialize for Call {
	fn deserialize<D>(deserializer: &mut D) -> Result<Call, D::Error>
	where D: Deserializer {
		let v = try!(Value::deserialize(deserializer));
		Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Call::Notification)
			.or_else(|_| Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Call::MethodCall))
			.map_err(|_| Error::custom("")) // types must match
			.or_else(|_: D::Error | Ok(Call::Invalid))
	}
}

/// Represents jsonrpc request.
#[derive(Debug, PartialEq)]
pub enum Request {
	Single(Call),
	Batch(Vec<Call>)
}

impl Deserialize for Request {
	fn deserialize<D>(deserializer: &mut D) -> Result<Request, D::Error>
	where D: Deserializer {
		let v = try!(Value::deserialize(deserializer));
		Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Request::Batch)
			.or_else(|_| Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Request::Single))
			.map_err(|_| Error::custom("")) // unreachable, but types must match
	}
}

#[test]
fn method_call_serialize() {
	use serde_json;
	use serde_json::Value;

	let m = MethodCall {
		jsonrpc: Version::V2,
		method: "update".to_string(),
		params: Some(Params::Array(vec![Value::U64(1), Value::U64(2)])),
		id: Id::Num(1)
	};

	let serialized = serde_json::to_string(&m).unwrap();

	assert_eq!(serialized, r#"{"jsonrpc":"2.0","method":"update","params":[1,2],"id":1}"#);

}

#[test]
fn notification_serialize() {
	use serde_json;
	use serde_json::Value;

	let n = Notification {
		jsonrpc: Version::V2,
		method: "update".to_string(),
		params: Some(Params::Array(vec![Value::U64(1), Value::U64(2)]))
	};

	let serialized = serde_json::to_string(&n).unwrap();

	assert_eq!(serialized, r#"{"jsonrpc":"2.0","method":"update","params":[1,2]}"#);
}

#[test]
fn notification_deserialize() {
	use serde_json;
	use serde_json::Value;

	let s = r#"{"jsonrpc": "2.0", "method": "update", "params": [1,2]}"#;
	let deserialized: Notification = serde_json::from_str(s).unwrap();

	assert_eq!(deserialized, Notification {
		jsonrpc: Version::V2,
		method: "update".to_string(),
		params: Some(Params::Array(vec![Value::U64(1), Value::U64(2)]))
	});

	let s = r#"{"jsonrpc": "2.0", "method": "foobar"}"#;
	let deserialized: Notification = serde_json::from_str(s).unwrap();

	assert_eq!(deserialized, Notification {
		jsonrpc: Version::V2,
		method: "foobar".to_string(),
		params: None
	});

	let s = r#"{"jsonrpc": "2.0", "method": "update", "params": [1,2], "id": 1}"#;
	let deserialized: Result<Notification, _> = serde_json::from_str(s);
	assert!(deserialized.is_err())
}

#[test]
fn call_deserialize() {
	use serde_json;

	let s = r#"{"jsonrpc": "2.0", "method": "update", "params": [1]}"#;
	let deserialized: Call = serde_json::from_str(s).unwrap();
	assert_eq!(deserialized, Call::Notification(Notification {
		jsonrpc: Version::V2,
		method: "update".to_owned(),
		params: Some(Params::Array(vec![Value::U64(1)]))
	}));

	let s = r#"{"jsonrpc": "2.0", "method": "update", "params": [1], "id": 1}"#;
	let deserialized: Call = serde_json::from_str(s).unwrap();
	assert_eq!(deserialized, Call::MethodCall(MethodCall {
		jsonrpc: Version::V2,
		method: "update".to_owned(),
		params: Some(Params::Array(vec![Value::U64(1)])),
		id: Id::Num(1)
	}));
}

#[test]
fn request_deserialize_batch() {
	use serde_json;

	let s = r#"[1, {"jsonrpc": "2.0", "method": "update", "params": [1,2], "id": 1},{"jsonrpc": "2.0", "method": "update", "params": [1]}]"#;
	let deserialized: Request = serde_json::from_str(s).unwrap();
	assert_eq!(deserialized, Request::Batch(vec![
		Call::Invalid,
		Call::MethodCall(MethodCall {
			jsonrpc: Version::V2,
			method: "update".to_owned(),
			params: Some(Params::Array(vec![Value::U64(1), Value::U64(2)])),
			id: Id::Num(1)
		}),
		Call::Notification(Notification {
			jsonrpc: Version::V2,
			method: "update".to_owned(),
			params: Some(Params::Array(vec![Value::U64(1)]))
		})
	]))
}
<|endoftext|>


<commit_before>pub mod builtins;

use std::collections::HashMap;
use std::path::PathBuf;
use std::io;
use std::io::{Read, Write};
use std::collections::hash_map::Entry;

#[derive(PartialEq, Debug, Clone)]
pub struct State {
    cwd: PathBuf,
    environment: HashMap<String, String>,
    aliases: HashMap<String, String>,
    argv: Vec<String>,
    argc: usize,
}

impl State {
    pub fn new(cwd: String) -> State {
        State{
            cwd: PathBuf::from(cwd),
            environment: HashMap::new(),
            aliases: HashMap::new(),
            argv: Vec::new(),
            argc: 0,
        }
    }
}

pub fn run(initial_state: State) {
    let mut builtins = builtins::load();
    let mut s = initial_state.clone();

    println!("Welcome to rsh! {:?}", s);

    loop {

        print!("{} -> ", s.cwd.to_str().unwrap());

        // this forces the prompt to print
        io::stdout().flush();

        // read the user input
        let mut input = String::new();
        io::stdin().read_line(&mut input).unwrap();

        s.argv = input.split_whitespace().
            map(|s| s.to_string() ).
            collect();
        s.argc = s.argv.len();

        print!("\n");
        println!("Input: {}\nState: {:?}", input, s);

        let first_arg = s.argv.get(0).unwrap().clone();
        if let Entry::Occupied(f) = builtins.entry(String::from(first_arg)) {
            let bn = f.get();
            let newS = bn(s.clone());
        }
    }
}
<commit_msg>runs builtins and sets new state<commit_after>pub mod builtins;

use std::collections::HashMap;
use std::path::PathBuf;
use std::io;
use std::io::{Read, Write};
use std::collections::hash_map::Entry;

#[derive(PartialEq, Debug, Clone)]
pub struct State {
    cwd: PathBuf,
    environment: HashMap<String, String>,
    aliases: HashMap<String, String>,
    argv: Vec<String>,
    argc: usize,
}

impl State {
    pub fn new(cwd: String) -> State {
        State{
            cwd: PathBuf::from(cwd),
            environment: HashMap::new(),
            aliases: HashMap::new(),
            argv: Vec::new(),
            argc: 0,
        }
    }
}

pub fn run(initial_state: State) {
    let mut builtins = builtins::load();
    let mut s = initial_state.clone();

    println!("Welcome to rsh! {:?}", s);

    loop {

        print!("{} -> ", s.cwd.to_str().unwrap());

        // this forces the prompt to print
        io::stdout().flush();

        // read the user input
        let mut input = String::new();
        io::stdin().read_line(&mut input).unwrap();

        s.argv = input.split_whitespace().
            map(|s| s.to_string() ).
            collect();
        s.argc = s.argv.len();

        print!("\n");
        println!("Input: {}\nState: {:?}", input, s);

        let first_arg = s.argv.get(0).unwrap().clone();
        if let Entry::Occupied(f) = builtins.entry(String::from(first_arg)) {
            let bn = f.get();
            s = bn(s.clone());
        }
    }
}
<|endoftext|>