<commit_before>//! Data structures and methods for parsing and applying Knuth-Liang
//! hyphenation patterns.

use std::cmp::{max};
use std::collections::hash_map::{HashMap, Entry};
use std::iter::{once, repeat};

use unicode_normalization::{Recompositions, UnicodeNormalization};

/// A basic trie, used to associate patterns to their hyphenation scores.
#[derive(Clone, Debug)]
pub struct Patterns {
    pub tally: Option<Vec<u32>>,
    pub descendants: HashMap<char, Patterns>
}

impl Patterns {
    /// Creates an empty `Patterns` trie.
    pub fn empty() -> Patterns {
        Patterns {
            tally: None,
            descendants: HashMap::new()
        }
    }

    /// Inserts a standard Knuth-Liang hyphenation pattern into the trie.
    pub fn insert(&mut self, pattern: &str) {
        let p_norm = pattern.nfc();
        let tally = points(p_norm.clone());
        let cs = p_norm.filter(|c| !c.is_digit(10));

        let node = cs.fold(self, |t, c| {
            match t.descendants.entry(c) {
                Entry::Vacant(e) => e.insert(Patterns::empty()),
                Entry::Occupied(e) => e.into_mut()
            }
        });

        node.tally = Some(tally);
    }

    /// Assigns a score to each potential hyphenation point.
    ///
    /// All patterns matching a substring of `word` are compounded, and for
    /// each hyphenation point, the highest competing value is selected.
    pub fn score(&self, word: &str) -> Vec<u32> {
        let w = word.to_lowercase();
        let cs = once('.').chain(w.chars()).chain(once('.'));
        let length = cs.clone().count();
        let mut points: Vec<u32> = repeat(0).take(length + 1).collect();

        for i in 0..length {
            let mut m = &self.descendants;
            for c in cs.clone().skip(i) {
                match m.get(&c) {
                    Some(&Patterns { tally: Some(ref t), descendants: ref m1 }) =>
                        for (j, &p) in t.iter().enumerate() {
                            let p1 = points[i + j];
                            m = m1;
                            points[i + j] = max(p, p1)
                    },
                    Some(patterns) => m = &patterns.descendants,
                    _ => break
                }
            }
        }

        points.truncate(length - 1);
        points.remove(0);
        points
    }
}

#[derive(Clone)]
struct Tallying<I> where I: Iterator<Item = char> {
    inner: Recompositions<I>,
    skip_one: bool
}

impl<I> Iterator for Tallying<I> where I: Iterator<Item = char> {
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        for c in self.inner.by_ref() {
            match (c.to_digit(10), self.skip_one) {
                (n@Some(_), _) => {
                    self.skip_one = true;
                    return n;
                },
                (None, false) => return Some(0),
                (None, true) => self.skip_one = false
            }
        }

        if !self.skip_one {
            self.skip_one = true;
            Some(0)
        } else {
            None
        }
    }

}

fn points<I: Iterator<Item=char>>(cs: Recompositions<I>) -> Vec<u32> {
    Tallying { inner: cs, skip_one: false }.collect()
}
<commit_msg>Do introduce me to the charming stranger, answers to the name of `vec!`.<commit_after>//! Data structures and methods for parsing and applying Knuth-Liang
//! hyphenation patterns.

use std::cmp::{max};
use std::collections::hash_map::{HashMap, Entry};
use std::iter::{once};

use unicode_normalization::{Recompositions, UnicodeNormalization};

/// A basic trie, used to associate patterns to their hyphenation scores.
#[derive(Clone, Debug)]
pub struct Patterns {
    pub tally: Option<Vec<u32>>,
    pub descendants: HashMap<char, Patterns>
}

impl Patterns {
    /// Creates an empty `Patterns` trie.
    pub fn empty() -> Patterns {
        Patterns {
            tally: None,
            descendants: HashMap::new()
        }
    }

    /// Inserts a standard Knuth-Liang hyphenation pattern into the trie.
    pub fn insert(&mut self, pattern: &str) {
        let p_norm = pattern.nfc();
        let tally = points(p_norm.clone());
        let cs = p_norm.filter(|c| !c.is_digit(10));

        let node = cs.fold(self, |t, c| {
            match t.descendants.entry(c) {
                Entry::Vacant(e) => e.insert(Patterns::empty()),
                Entry::Occupied(e) => e.into_mut()
            }
        });

        node.tally = Some(tally);
    }

    /// Assigns a score to each potential hyphenation point.
    ///
    /// All patterns matching a substring of `word` are compounded, and for
    /// each hyphenation point, the highest competing value is selected.
    pub fn score(&self, word: &str) -> Vec<u32> {
        let w = word.to_lowercase();
        let cs = once('.').chain(w.chars()).chain(once('.'));
        let length = cs.clone().count();
        let mut points: Vec<u32> = vec![0; length + 1];

        for i in 0..length {
            let mut m = &self.descendants;
            for c in cs.clone().skip(i) {
                match m.get(&c) {
                    Some(&Patterns { tally: Some(ref t), descendants: ref m1 }) =>
                        for (j, &p) in t.iter().enumerate() {
                            let p1 = points[i + j];
                            m = m1;
                            points[i + j] = max(p, p1)
                    },
                    Some(patterns) => m = &patterns.descendants,
                    _ => break
                }
            }
        }

        points.truncate(length - 1);
        points.remove(0);
        points
    }
}

#[derive(Clone)]
struct Tallying<I> where I: Iterator<Item = char> {
    inner: Recompositions<I>,
    skip_one: bool
}

impl<I> Iterator for Tallying<I> where I: Iterator<Item = char> {
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        for c in self.inner.by_ref() {
            match (c.to_digit(10), self.skip_one) {
                (n@Some(_), _) => {
                    self.skip_one = true;
                    return n;
                },
                (None, false) => return Some(0),
                (None, true) => self.skip_one = false
            }
        }

        if !self.skip_one {
            self.skip_one = true;
            Some(0)
        } else {
            None
        }
    }

}

fn points<I: Iterator<Item=char>>(cs: Recompositions<I>) -> Vec<u32> {
    Tallying { inner: cs, skip_one: false }.collect()
}
<|endoftext|>


<commit_before>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

pub use surface::SurfaceExt;
<commit_msg>Add more traits to the prelude<commit_after>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

pub use matrices::MatrixTrait;
pub use patterns::{
    Gradient,
    Pattern,
};
pub use surface::SurfaceExt;
<|endoftext|>


<commit_before>use std::fmt::{Display, Formatter, Result};
use common::{Atom, Sexp};

impl Display for Atom {
    fn fmt(&self, f: &mut Formatter) -> Result {
        match *self {
            Atom::Number(n) => {
                write!(f, "{}", n)
            },
            Atom::Symbol(ref s) => {
                write!(f, "{}", s)
            },
            Atom::Nil => {
                write!(f, "nil")
            }
        }
    }
}

impl Display for Vec<Sexp> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "(");
        let i_last = self.len() - 1;
        for (i, s) in self.iter().enumerate() {
            if i < i_last {
                write!(f, "{} ", s);
            } else {
                write!(f, "{}", s);
            }
        }
        write!(f, ")")
    }
}

impl Display for Sexp {
    fn fmt(&self, f: &mut Formatter) -> Result {
        match *self {
            Sexp::Atom(ref atom) => {
                write!(f, "{}", atom)
            },
            Sexp::List(ref l) => {
                write!(f, "{}", l)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use common::Sexp::{List, Atom};
    use common::Atom::{Symbol, Number};

    #[test]
    fn test_format_list_with_nested_list_and_atoms() {
        let actual_input = List(vec![Atom(Symbol("def".to_string())),
                                     Atom(Symbol("a".to_string())),
                                     List(vec![Atom(Symbol("+".to_string())),
                                               Atom(Number(1f64)),
                                               Atom(Number(2f64))])]);
        let actual_result = format!("{}", actual_input);
        let expected_result = "(def a (+ 1 2))";
        assert_eq!(expected_result, actual_result);
    }
}
<commit_msg>Fix warnings about unused result<commit_after>use std::fmt::{Display, Formatter, Result};
use common::{Atom, Sexp};

impl Display for Atom {
    fn fmt(&self, f: &mut Formatter) -> Result {
        match *self {
            Atom::Number(n) => {
                write!(f, "{}", n)
            },
            Atom::Symbol(ref s) => {
                write!(f, "{}", s)
            },
            Atom::Nil => {
                write!(f, "nil")
            }
        }
    }
}

impl Display for Vec<Sexp> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let mut a = "(".to_string();
        let i_last = self.len() - 1;
        for (i, s) in self.iter().enumerate() {
            if i < i_last {
                a.push_str(&format!("{} ", s))
            } else {
                a.push_str(&format!("{}", s))
            }
        }
        a.push_str(")");
        write!(f, "{}", a)
    }
}

impl Display for Sexp {
    fn fmt(&self, f: &mut Formatter) -> Result {
        match *self {
            Sexp::Atom(ref atom) => {
                write!(f, "{}", atom)
            },
            Sexp::List(ref l) => {
                write!(f, "{}", l)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use common::Sexp::{List, Atom};
    use common::Atom::{Symbol, Number};

    #[test]
    fn test_format_list_with_nested_list_and_atoms() {
        let actual_input = List(vec![Atom(Symbol("def".to_string())),
                                     Atom(Symbol("a".to_string())),
                                     List(vec![Atom(Symbol("+".to_string())),
                                               Atom(Number(1f64)),
                                               Atom(Number(2f64))])]);
        let actual_result = format!("{}", actual_input);
        let expected_result = "(def a (+ 1 2))";
        assert_eq!(expected_result, actual_result);
    }
}
<|endoftext|>


<commit_before>//! Pattern-sequence data structures and implementations.

use std::ops::Index;
use std::iter::FromIterator;

use util::set::{self, Contains};
use super::{Anchor, Atom, Class, Element, Repetition, Union};
use super::{Reduce, flatten_and_reduce};

// To hide the implementation details, we wrap the type alias in
// a private submodule.
mod seq_impl {
    use ::pattern::Element;
    pub type Inner<T> = Vec<Element<T>>;
}

/// Sequence of patterns.
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct Sequence<T: Atom>(seq_impl::Inner<T>);

impl<T: Atom> Sequence<T> {
    /// Create a new sequence from the given vector.
    ///
    /// This method will **panic** if the given vector is not at least two
    /// elements long.
    pub fn new(v: Vec<Element<T>>) -> Self {
        if v.len() < 2 {
            panic!("Sequences must have at least two elements");
        }
        Sequence(v)
    }

    /// Get the number of elements in the sequence.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Fetch an iterator over the elements in the sequence
    pub fn iter<'a>(&'a self) -> impl Iterator<Item=&'a Element<T>> {
        self.0.iter()
    }

    fn into_inner(self) -> seq_impl::Inner<T> {
        self.0
    }

    /// Transforms each contained atom using the supplied function or closure
    /// to produce a new sequence.
    pub fn map_atoms<U, F>(self, f: F) -> Sequence<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        self.0.into_iter().map(|elt| elt.map_atoms(&f)).collect()
    }
}

impl<T: Atom> Reduce for Sequence<T> {
    type Output = Option<Element<T>>;

    /// Flatten the sequence and apply implementation-defined optimizations.
    fn reduce(mut self) -> Self::Output {
        // Flatten and reduce the vector *first* so we can reduce `self` based
        // on the size of the *reduced* vector.
       flatten_and_reduce(&mut self.0, Element::Wildcard,
                           |elt| match elt { &Element::Sequence(ref s) => Some(s.len()), _ => None },
                           |elt| match elt { Element::Sequence(s) => s.into_inner(), _ => unreachable!() });
        match self.0.len() {
            0 => None,
            1 => Some(self.0.swap_remove(0)),
            _ => Some(Element::Sequence(self))
        }
    }
}

impl<T: Atom> Index<usize> for Sequence<T> {
    type Output = Element<T>;
    fn index(&self, index: usize) -> &Self::Output {
        &self.0[index]
    }

}

impl<T: Atom> FromIterator<Element<T>> for Sequence<T> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item=Element<T>>
    {
        Sequence(iter.into_iter().collect())
    }
}

impl<T: Atom> set::Contains<T> for Sequence<T> {
    /// A sequence always contains at least two elements, and thus will never
    /// match a single atom.
    #[inline(always)]
    fn contains(&self, _: T) -> bool {
        false
    }
}

// ----------------------------------------------------------------
// set::IsSubsetOf

macro_rules! is_subset_if_length_1_and_first_element_is_subset {
    ($T: ident,$Other: ty, $name: ident; $doc: expr) => {
        impl<$T: Atom> set::IsSubsetOf<$Other> for Sequence<$T> {
            #[doc = $doc]
            #[inline]
            fn is_subset_of(&self, $name: &$Other) -> bool {
                self.len() == 1 && self[0].is_subset_of($name)
            }
        }}}

is_subset_if_length_1_and_first_element_is_subset! {
    T, T, atom;
    "A sequence is a subset of a particular atom whenever the sequence has length one, and the first element is a subset of that atom."}

is_subset_if_length_1_and_first_element_is_subset! {
    T, Anchor<T>, anchor;
    "A sequence is a subset of an anchor whenever the sequence has length one, and the first element is a subset of that atom."}

is_subset_if_length_1_and_first_element_is_subset! {
    T, Class<T>, class;
    "A sequence is a subset of an atom class whenever the sequence has length one, and the first element is a subset of that class."}

impl<T: Atom> set::IsSubsetOf<Sequence<T>> for Sequence<T> {
    /// A sequence `A` can be a subset of another sequence `B` *if* both have the
    /// same length and each element in `A` is a subset of the corresponding element
    /// in `B`:
    ///
    /// A ⊂ B ⇔ |A|=|B|=n ∧ Aᵢ ⊂ Bᵢ ∀ i∈[0,n]
    fn is_subset_of(&self, other: &Sequence<T>) -> bool {
        other.len() == self.len() &&
            self.iter().zip(other.iter()).all(|(u, v)| u.is_subset_of(v))
    }
}

impl<T: Atom> set::IsSubsetOf<Union<T>> for Sequence<T> {
    /// A sequence is a subset of a union whenever it is a subset of one of the
    /// union's members.
    fn is_subset_of(&self, union: &Union<T>) -> bool {
        union.iter().any(|m| self.is_subset_of(m))
    }
}

impl<T: Atom> set::IsSubsetOf<Repetition<T>> for Sequence<T> {
    /// A sequence is a subset of a repetition if the sequence's length is
    /// contained by the repetition's count and all members of the sequence are
    /// subsets of the repeated element.
    fn is_subset_of(&self, rep: &Repetition<T>) -> bool {
        rep.count().contains(self.len()) && self.iter().all(|elt| elt.is_subset_of(rep.element()))
    }
}

impl<T: Atom> set::IsSubsetOf<Element<T>> for Sequence<T> {
    fn is_subset_of(&self, elt: &Element<T>) -> bool {
        match elt {
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),
            &Element::Sequence(ref s) => self.is_subset_of(s),
            &Element::Union(ref u) => self.is_subset_of(u),
            &Element::Repeat(ref r) => self.is_subset_of(r),

            &Element::Anchor(ref a) => self.is_subset_of(a),
            &Element::Atom(ref a) => self.is_subset_of(a),
            &Element::Class(ref c) => self.is_subset_of(c),
            &Element::Wildcard => self.len() == 1 && self[0].is_subset_of(elt),
        }
    }
}
        }
    }
}
<commit_msg>pattern/sequence: implement IntoIterator for Sequence<T><commit_after>//! Pattern-sequence data structures and implementations.

use std;
use std::ops::Index;
use std::iter::FromIterator;

use util::set::{self, Contains};
use super::{Anchor, Atom, Class, Element, Repetition, Union};
use super::{Reduce, flatten_and_reduce};

// To hide the implementation details, we wrap the type alias in
// a private submodule.
mod seq_impl {
    use ::pattern::Element;
    pub type Inner<T> = Vec<Element<T>>;
}

/// Sequence of patterns.
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct Sequence<T: Atom>(seq_impl::Inner<T>);

impl<T: Atom> Sequence<T> {
    /// Create a new sequence from the given vector.
    ///
    /// This method will **panic** if the given vector is not at least two
    /// elements long.
    pub fn new(v: Vec<Element<T>>) -> Self {
        if v.len() < 2 {
            panic!("Sequences must have at least two elements");
        }
        Sequence(v)
    }

    /// Get the number of elements in the sequence.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Fetch an iterator over the elements in the sequence
    pub fn iter<'a>(&'a self) -> impl Iterator<Item=&'a Element<T>> {
        self.0.iter()
    }

    fn into_inner(self) -> seq_impl::Inner<T> {
        self.0
    }

    /// Transforms each contained atom using the supplied function or closure
    /// to produce a new sequence.
    pub fn map_atoms<U, F>(self, f: F) -> Sequence<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        self.0.into_iter().map(|elt| elt.map_atoms(&f)).collect()
    }
}

impl<T: Atom> Reduce for Sequence<T> {
    type Output = Option<Element<T>>;

    /// Flatten the sequence and apply implementation-defined optimizations.
    fn reduce(mut self) -> Self::Output {
        // Flatten and reduce the vector *first* so we can reduce `self` based
        // on the size of the *reduced* vector.
       flatten_and_reduce(&mut self.0, Element::Wildcard,
                           |elt| match elt { &Element::Sequence(ref s) => Some(s.len()), _ => None },
                           |elt| match elt { Element::Sequence(s) => s.into_inner(), _ => unreachable!() });
        match self.0.len() {
            0 => None,
            1 => Some(self.0.swap_remove(0)),
            _ => Some(Element::Sequence(self))
        }
    }
}

impl<T: Atom> Index<usize> for Sequence<T> {
    type Output = Element<T>;
    fn index(&self, index: usize) -> &Self::Output {
        &self.0[index]
    }

}

impl<T: Atom> IntoIterator for Sequence<T> {
    type Item = Element<T>;
    type IntoIter = std::vec::IntoIter<Element<T>>;
    #[inline(always)]
    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl<T: Atom> FromIterator<Element<T>> for Sequence<T> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item=Element<T>>
    {
        Sequence(iter.into_iter().collect())
    }
}

impl<T: Atom> set::Contains<T> for Sequence<T> {
    /// A sequence always contains at least two elements, and thus will never
    /// match a single atom.
    #[inline(always)]
    fn contains(&self, _: T) -> bool {
        false
    }
}

// ----------------------------------------------------------------
// set::IsSubsetOf

macro_rules! is_subset_if_length_1_and_first_element_is_subset {
    ($T: ident,$Other: ty, $name: ident; $doc: expr) => {
        impl<$T: Atom> set::IsSubsetOf<$Other> for Sequence<$T> {
            #[doc = $doc]
            #[inline]
            fn is_subset_of(&self, $name: &$Other) -> bool {
                self.len() == 1 && self[0].is_subset_of($name)
            }
        }}}

is_subset_if_length_1_and_first_element_is_subset! {
    T, T, atom;
    "A sequence is a subset of a particular atom whenever the sequence has length one, and the first element is a subset of that atom."}

is_subset_if_length_1_and_first_element_is_subset! {
    T, Anchor<T>, anchor;
    "A sequence is a subset of an anchor whenever the sequence has length one, and the first element is a subset of that atom."}

is_subset_if_length_1_and_first_element_is_subset! {
    T, Class<T>, class;
    "A sequence is a subset of an atom class whenever the sequence has length one, and the first element is a subset of that class."}

impl<T: Atom> set::IsSubsetOf<Sequence<T>> for Sequence<T> {
    /// A sequence `A` can be a subset of another sequence `B` *if* both have the
    /// same length and each element in `A` is a subset of the corresponding element
    /// in `B`:
    ///
    /// A ⊂ B ⇔ |A|=|B|=n ∧ Aᵢ ⊂ Bᵢ ∀ i∈[0,n]
    fn is_subset_of(&self, other: &Sequence<T>) -> bool {
        other.len() == self.len() &&
            self.iter().zip(other.iter()).all(|(u, v)| u.is_subset_of(v))
    }
}

impl<T: Atom> set::IsSubsetOf<Union<T>> for Sequence<T> {
    /// A sequence is a subset of a union whenever it is a subset of one of the
    /// union's members.
    fn is_subset_of(&self, union: &Union<T>) -> bool {
        union.iter().any(|m| self.is_subset_of(m))
    }
}

impl<T: Atom> set::IsSubsetOf<Repetition<T>> for Sequence<T> {
    /// A sequence is a subset of a repetition if the sequence's length is
    /// contained by the repetition's count and all members of the sequence are
    /// subsets of the repeated element.
    fn is_subset_of(&self, rep: &Repetition<T>) -> bool {
        rep.count().contains(self.len()) && self.iter().all(|elt| elt.is_subset_of(rep.element()))
    }
}

impl<T: Atom> set::IsSubsetOf<Element<T>> for Sequence<T> {
    fn is_subset_of(&self, elt: &Element<T>) -> bool {
        match elt {
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),
            &Element::Sequence(ref s) => self.is_subset_of(s),
            &Element::Union(ref u) => self.is_subset_of(u),
            &Element::Repeat(ref r) => self.is_subset_of(r),

            &Element::Anchor(ref a) => self.is_subset_of(a),
            &Element::Atom(ref a) => self.is_subset_of(a),
            &Element::Class(ref c) => self.is_subset_of(c),
            &Element::Wildcard => self.len() == 1 && self[0].is_subset_of(elt),
        }
    }
}
        }
    }
}
<|endoftext|>


<commit_before>extern crate tokio_core;
extern crate futures;
extern crate tk_http;
extern crate tk_listen;
extern crate wonky_tanks_server;

use std::cell::RefCell;
use std::collections::hash_map::HashMap;
use std::fmt::Write;
use std::rc::Rc;

use tokio_core::reactor::Core;
use tokio_core::net::TcpListener;

use futures::{Stream, Future};
use futures::future::{FutureResult, ok};
use futures::sync::mpsc::{unbounded, UnboundedSender};

use tk_http::{Status};
use tk_http::server::buffered::{Request, BufferedDispatcher};
use tk_http::server::{Encoder, EncoderDone, Config as ServerConfig, Proto, Error as ServerError};
use tk_http::websocket::{Packet, Config as WebsocketConfig, Dispatcher, Frame, Loop, Error as WebsocketError};

use tk_listen::ListenExt;

use wonky_tanks_server::*;

const LOBBY: &'static str = "/";

type SharedData = Rc<RefCell<HashMap<CountedString, ChannelState>>>;

#[derive(Clone, Default)]
pub struct ChannelState {
    capacity: Option<u8>,
    participants: Vec<Rc<UnboundedSender<Packet>>>,
}

impl std::fmt::Debug for ChannelState {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f
            .debug_struct("ChannelState")
            .field("capacity", &self.capacity)
            .field(
                "participants",
                &format_args!(
                    "{:x}",
                    IterContentsDebug(||
                        self
                            .participants
                            .iter()
                            .map(|i| (&i) as &UnboundedSender<_> as *const _ as usize)
                    )
                )
            )
            .finish()
    }
}

fn service<S>(directory: &Directory, token: &mut Option<String>, req: Request, mut e: Encoder<S>) -> FutureResult<EncoderDone<S>, ServerError> {
    if let Some(ws) = req.websocket_handshake() {
        *token = Some(req.path().to_string());
        e.status(Status::SwitchingProtocol);
        e.add_header("Connection", "upgrade").unwrap();
        e.add_header("Upgrade", "websocket").unwrap();
        e.format_header("Sec-Websocket-Accept", &ws.accept).unwrap();
        e.done_headers().unwrap();
        return ok(e.done())
    }

    if let Some((ctype, data)) = directory.get(req.path()) {
        e.status(Status::Ok);
        e.add_length(data.len() as u64).unwrap();
        e.add_header("Content-Type", ctype).unwrap();
        if e.done_headers().unwrap() {
            e.write_body(&data);
        }
        return ok(e.done())
    }

    let not_found = "No data found".as_bytes();
    e.status(Status::NotFound);
    e.add_length(not_found.len() as u64).unwrap();
    e.add_header("Content-Type", "text/plain").unwrap();
    if e.done_headers().unwrap() {
        e.write_body(not_found);
    }
    ok(e.done())
}

struct WebsocketConnection {
    shared_data: SharedData,
    sender: Rc<UnboundedSender<Packet>>,
    token: CountedString,
}

impl WebsocketConnection {
    pub fn new(shared_data: SharedData, token: String, sender: Rc<UnboundedSender<Packet>>) -> Self {
        let token: CountedString  = token.into();
        let mut data: String = Default::default();
        match match {
            let shared_data = &mut *shared_data.borrow_mut();
            let shared_data = shared_data.entry(token.clone());
            #[cfg(debug_assertions)]
            println!("Previous data: {:?}", &shared_data);
            let &mut ChannelState { ref mut participants, capacity } = shared_data.or_insert_with(Default::default);
            participants.push(sender.clone());
            data.clear();
            write!(data, "count: {}", participants.len()).unwrap();
            let (last, participants) = participants.split_last().unwrap();
            for participant in participants {
                drop(participant.unbounded_send(Packet::Text(data.clone())));
            }
            drop(last.unbounded_send(Packet::Text(data.clone())));
            (capacity, participants.len())
        } {
            (Some(capacity), 1) if 1 < capacity => Some(true),
            (None, 1) => Some(true),
            (Some(capacity), count) if count == capacity as usize && count != 1 => Some(false),
            _ => None,
        } {
            Some(toggle) => {
                if let Some(lobby) = shared_data.try_borrow().unwrap().get(LOBBY) {
                    data.clear();
                    write!(data, "{}: {}", if toggle { "+" } else { "-" }, token).unwrap();
                    let (last, participants) = lobby.participants.split_last().unwrap();
                    for participant in participants {
                        drop(participant.unbounded_send(Packet::Text(data.clone())));
                    }
                    drop(last.unbounded_send(Packet::Text(data)));
                }
            },
            None => {},
        }
        #[cfg(debug_assertions)]
        println!("Created connection: {:x}/{}", (&sender) as &UnboundedSender<_> as *const _ as usize, token);
        WebsocketConnection { shared_data, sender, token }
    }

    fn is_lobby(&self) -> bool {
        LOBBY == &*self.token.0
    }
}

impl Drop for WebsocketConnection {
    fn drop(&mut self) {
        let &mut WebsocketConnection {
            ref mut shared_data,
            ref sender,
            ref token
        } = self;
        use std::collections::hash_map::Entry::Occupied;
        if Some(1) != {
            let mut map = shared_data.borrow_mut();
            let mut entry =
                if let Occupied(entry) = map.entry(token.clone()) {
                    entry
                } else {
                    panic!("Bad state; expected {} to be occupied: {:?}", token, shared_data)
                };
            if let (capacity, 0) = {
                let &mut ChannelState { ref mut participants, capacity } = entry.get_mut();
                participants.retain(|target| !Rc::ptr_eq(target, sender));
                (capacity, participants.len())
            } {
                entry.remove_entry();
                capacity
            } else {
                Some(1)
            }
        } {
            if let Some(lobby) = shared_data.try_borrow().unwrap().get(LOBBY) {
                let data = format!("-: {}", token);
                let (last, participants) = lobby.participants.split_last().unwrap();
                for participant in participants {
                    drop(participant.unbounded_send(Packet::Text(data.clone())));
                }
                drop(last.unbounded_send(Packet::Text(data)));
            }
        }
        #[cfg(debug_assertions)]
        println!("Dropped connection: {:x}/{}", (&self.sender) as &UnboundedSender<_> as *const _ as usize, token);
    }
}

impl Dispatcher for WebsocketConnection {
    type Future = FutureResult<(), WebsocketError>;

    fn frame(&mut self, frame: &Frame) -> FutureResult<(), WebsocketError> {
        if self.is_lobby() { return ok(()) }
        let &mut WebsocketConnection { ref shared_data, ref sender, ref token } = self;

        match frame {
            &Frame::Text(t) => {
                // FIXME - parse state changes
            },
            &Frame::Binary(b) => {
                let &ChannelState { ref participants, .. } = &(&*shared_data.borrow())[token];
                if participants.len() == 1 { return ok(()) }
                let mut participants = participants.iter().filter(|&participant| !Rc::ptr_eq(participant, sender));
                let last = participants.next_back().unwrap();
                let to_send = Packet::Binary(Vec::from(b));
                for participant in participants {
                    drop(participant.unbounded_send(to_send.clone()));
                }
                drop(last.unbounded_send(to_send));
            },
            _ => {},
        }

        ok(())
    }
}

fn main() {
    let directory = &Directory::new(std::env::current_dir().unwrap().as_path());
    let shared_data: SharedData = Default::default();
    let mut lp = Core::new().unwrap();
    let h1 = lp.handle();

    let addr = "0.0.0.0:5000".parse().unwrap();
    let listener = TcpListener::bind(&addr, &lp.handle()).unwrap();
    let cfg = ServerConfig::new().done();
    let wcfg = WebsocketConfig::new().done();

    let pipeline = listener.incoming();
    let pipeline =
        pipeline.map(
        move |(socket, addr)| {
            let wcfg = wcfg.clone();
            let h2 = h1.clone();

            let shared_data = shared_data.clone();
            let data = Rc::new(RefCell::new(None));
            let http_data = data.clone();
            let websocket_data = data;

            Proto::new(
                socket,
                &cfg,
                BufferedDispatcher::new_with_websockets(
                    addr,
                    &h1,
                    move |p1, p2| {
                        let mut http_data = http_data.borrow_mut();
                        let http_data: &mut Option<String> = &mut http_data;
                        if let Some(token) = http_data.take() {
                            panic!("http initializer called twice: {}", token);
                        }
                        let ret = service(
                            directory,
                            http_data,
                            p1,
                            p2
                        );
                        ret
                    },
                    move |outp, inp| {
                        let (sender, receiver) = unbounded();
                        let sender = Rc::new(sender);
                        Loop::server(
                            outp,
                            inp,
                            receiver.map_err(move |e| format!("{:?} : stream closed", e)),
                            WebsocketConnection::new(
                                shared_data.clone(),
                                websocket_data
                                    .borrow_mut()
                                    .take()
                                    .expect("http initializer not called yet"),
                                sender
                            ),
                            &wcfg,
                            &h2
                        )
                            .map_err(|e| println!("Websocket err: {:?}", e))
                    }
                ),
                &h1
            )
                .map_err(|e| {println!("Connection error: {:?}", e);})
                .then(|_| Ok(())) // don't fail, please
        }
    );
    let pipeline = pipeline.listen(1000);

    lp.run(pipeline).unwrap();
}<commit_msg>Report disconnects<commit_after>extern crate tokio_core;
extern crate futures;
extern crate tk_http;
extern crate tk_listen;
extern crate wonky_tanks_server;

use std::cell::RefCell;
use std::collections::hash_map::HashMap;
use std::fmt::Write;
use std::rc::Rc;

use tokio_core::reactor::Core;
use tokio_core::net::TcpListener;

use futures::{Stream, Future};
use futures::future::{FutureResult, ok};
use futures::sync::mpsc::{unbounded, UnboundedSender};

use tk_http::{Status};
use tk_http::server::buffered::{Request, BufferedDispatcher};
use tk_http::server::{Encoder, EncoderDone, Config as ServerConfig, Proto, Error as ServerError};
use tk_http::websocket::{Packet, Config as WebsocketConfig, Dispatcher, Frame, Loop, Error as WebsocketError};

use tk_listen::ListenExt;

use wonky_tanks_server::*;

const LOBBY: &'static str = "/";

type SharedData = Rc<RefCell<HashMap<CountedString, ChannelState>>>;

#[derive(Clone, Default)]
pub struct ChannelState {
    capacity: Option<u8>,
    participants: Vec<Rc<UnboundedSender<Packet>>>,
}

impl std::fmt::Debug for ChannelState {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f
            .debug_struct("ChannelState")
            .field("capacity", &self.capacity)
            .field(
                "participants",
                &format_args!(
                    "{:x}",
                    IterContentsDebug(||
                        self
                            .participants
                            .iter()
                            .map(|i| (&i) as &UnboundedSender<_> as *const _ as usize)
                    )
                )
            )
            .finish()
    }
}

fn service<S>(directory: &Directory, token: &mut Option<String>, req: Request, mut e: Encoder<S>) -> FutureResult<EncoderDone<S>, ServerError> {
    if let Some(ws) = req.websocket_handshake() {
        *token = Some(req.path().to_string());
        e.status(Status::SwitchingProtocol);
        e.add_header("Connection", "upgrade").unwrap();
        e.add_header("Upgrade", "websocket").unwrap();
        e.format_header("Sec-Websocket-Accept", &ws.accept).unwrap();
        e.done_headers().unwrap();
        return ok(e.done())
    }

    if let Some((ctype, data)) = directory.get(req.path()) {
        e.status(Status::Ok);
        e.add_length(data.len() as u64).unwrap();
        e.add_header("Content-Type", ctype).unwrap();
        if e.done_headers().unwrap() {
            e.write_body(&data);
        }
        return ok(e.done())
    }

    let not_found = "No data found".as_bytes();
    e.status(Status::NotFound);
    e.add_length(not_found.len() as u64).unwrap();
    e.add_header("Content-Type", "text/plain").unwrap();
    if e.done_headers().unwrap() {
        e.write_body(not_found);
    }
    ok(e.done())
}

struct WebsocketConnection {
    shared_data: SharedData,
    sender: Rc<UnboundedSender<Packet>>,
    token: CountedString,
}

impl WebsocketConnection {
    pub fn new(shared_data: SharedData, token: String, sender: Rc<UnboundedSender<Packet>>) -> Self {
        let token: CountedString  = token.into();
        let mut data: String = Default::default();
        match match {
            let shared_data = &mut *shared_data.borrow_mut();
            let shared_data = shared_data.entry(token.clone());
            #[cfg(debug_assertions)]
            println!("Previous data: {:?}", &shared_data);
            let &mut ChannelState { ref mut participants, capacity } = shared_data.or_insert_with(Default::default);
            participants.push(sender.clone());
            data.clear();
            write!(data, "count: {}", participants.len()).unwrap();
            let (last, participants) = participants.split_last().unwrap();
            for participant in participants {
                drop(participant.unbounded_send(Packet::Text(data.clone())));
            }
            drop(last.unbounded_send(Packet::Text(data.clone())));
            (capacity, participants.len())
        } {
            (Some(capacity), 1) if 1 < capacity => Some(true),
            (None, 1) => Some(true),
            (Some(capacity), count) if count == capacity as usize && count != 1 => Some(false),
            _ => None,
        } {
            Some(toggle) => {
                if let Some(lobby) = shared_data.try_borrow().unwrap().get(LOBBY) {
                    data.clear();
                    write!(data, "{}: {}", if toggle { "+" } else { "-" }, token).unwrap();
                    let (last, participants) = lobby.participants.split_last().unwrap();
                    for participant in participants {
                        drop(participant.unbounded_send(Packet::Text(data.clone())));
                    }
                    drop(last.unbounded_send(Packet::Text(data)));
                }
            },
            None => {},
        }
        #[cfg(debug_assertions)]
        println!("Created connection: {:x}/{}", (&sender) as &UnboundedSender<_> as *const _ as usize, token);
        WebsocketConnection { shared_data, sender, token }
    }

    fn is_lobby(&self) -> bool {
        LOBBY == &*self.token.0
    }
}

impl Drop for WebsocketConnection {
    fn drop(&mut self) {
        let &mut WebsocketConnection {
            ref mut shared_data,
            ref sender,
            ref token
        } = self;
        use std::collections::hash_map::Entry::Occupied;
        if Some(1) != {
            let mut map = shared_data.borrow_mut();
            let mut entry =
                if let Occupied(entry) = map.entry(token.clone()) {
                    entry
                } else {
                    panic!("Bad state; expected {} to be occupied: {:?}", token, shared_data)
                };
            if let (capacity, 0) = {
                let &mut ChannelState { ref mut participants, capacity } = entry.get_mut();
                participants.retain(|target| !Rc::ptr_eq(target, sender));
                if !participants.is_empty() {
                    let data = format!("count: {}", participants.len());
                    let (last, participants) = participants.split_last().unwrap();
                    for participant in participants {
                        drop(participant.unbounded_send(Packet::Text(data.clone())));
                    }
                    drop(last.unbounded_send(Packet::Text(data)));
                }
                (capacity, participants.len())
            } {
                entry.remove_entry();
                capacity
            } else {
                Some(1)
            }
        } {
            if let Some(lobby) = shared_data.try_borrow().unwrap().get(LOBBY) {
                let data = format!("-: {}", token);
                let (last, participants) = lobby.participants.split_last().unwrap();
                for participant in participants {
                    drop(participant.unbounded_send(Packet::Text(data.clone())));
                }
                drop(last.unbounded_send(Packet::Text(data)));
            }
        }
        #[cfg(debug_assertions)]
        println!("Dropped connection: {:x}/{}", (&self.sender) as &UnboundedSender<_> as *const _ as usize, token);
    }
}

impl Dispatcher for WebsocketConnection {
    type Future = FutureResult<(), WebsocketError>;

    fn frame(&mut self, frame: &Frame) -> FutureResult<(), WebsocketError> {
        if self.is_lobby() { return ok(()) }
        let &mut WebsocketConnection { ref shared_data, ref sender, ref token } = self;

        match frame {
            &Frame::Text(t) => {
                // FIXME - parse state changes
            },
            &Frame::Binary(b) => {
                let &ChannelState { ref participants, .. } = &(&*shared_data.borrow())[token];
                if participants.len() == 1 { return ok(()) }
                let mut participants = participants.iter().filter(|&participant| !Rc::ptr_eq(participant, sender));
                let last = participants.next_back().unwrap();
                let to_send = Packet::Binary(Vec::from(b));
                for participant in participants {
                    drop(participant.unbounded_send(to_send.clone()));
                }
                drop(last.unbounded_send(to_send));
            },
            _ => {},
        }

        ok(())
    }
}

fn main() {
    let directory = &Directory::new(std::env::current_dir().unwrap().as_path());
    let shared_data: SharedData = Default::default();
    let mut lp = Core::new().unwrap();
    let h1 = lp.handle();

    let addr = "0.0.0.0:5000".parse().unwrap();
    let listener = TcpListener::bind(&addr, &lp.handle()).unwrap();
    let cfg = ServerConfig::new().done();
    let wcfg = WebsocketConfig::new().done();

    let pipeline = listener.incoming();
    let pipeline =
        pipeline.map(
        move |(socket, addr)| {
            let wcfg = wcfg.clone();
            let h2 = h1.clone();

            let shared_data = shared_data.clone();
            let data = Rc::new(RefCell::new(None));
            let http_data = data.clone();
            let websocket_data = data;

            Proto::new(
                socket,
                &cfg,
                BufferedDispatcher::new_with_websockets(
                    addr,
                    &h1,
                    move |p1, p2| {
                        let mut http_data = http_data.borrow_mut();
                        let http_data: &mut Option<String> = &mut http_data;
                        if let Some(token) = http_data.take() {
                            panic!("http initializer called twice: {}", token);
                        }
                        let ret = service(
                            directory,
                            http_data,
                            p1,
                            p2
                        );
                        ret
                    },
                    move |outp, inp| {
                        let (sender, receiver) = unbounded();
                        let sender = Rc::new(sender);
                        Loop::server(
                            outp,
                            inp,
                            receiver.map_err(move |e| format!("{:?} : stream closed", e)),
                            WebsocketConnection::new(
                                shared_data.clone(),
                                websocket_data
                                    .borrow_mut()
                                    .take()
                                    .expect("http initializer not called yet"),
                                sender
                            ),
                            &wcfg,
                            &h2
                        )
                            .map_err(|e| println!("Websocket err: {:?}", e))
                    }
                ),
                &h1
            )
                .map_err(|e| {println!("Connection error: {:?}", e);})
                .then(|_| Ok(())) // don't fail, please
        }
    );
    let pipeline = pipeline.listen(1000);

    lp.run(pipeline).unwrap();
}<|endoftext|>


<commit_before>//! Types for the *m.receipt* event.

use std::collections::HashMap;

use ruma_identifiers::{EventId, RoomId, UserId};

event! {
    /// Informs the client of new receipts.
    pub struct ReceiptEvent(ReceiptEventContent) {
        /// The unique identifier for the room associated with this event.
        pub room_id: RoomId
    }
}

/// The payload of a `ReceiptEvent`.
///
/// A mapping of event ID to a collection of receipts for this event ID. The event ID is the ID of
/// the event being acknowledged and *not* an ID for the receipt itself.
pub type ReceiptEventContent = HashMap<EventId, Receipts>;

/// A collection of receipts.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Receipts {
    /// A collection of users who have sent *m.read* receipts for this event.
    pub m_read: UserReceipts,
}

/// A mapping of user ID to receipt.
///
/// The user ID is the entity who sent this receipt.
pub type UserReceipts = HashMap<UserId, Receipt>;

/// An acknowledgement of an event.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Receipt {
    /// The timestamp the receipt was sent at.
    pub ts: u64,
}
<commit_msg>Fix wrong json key in receipt event<commit_after>//! Types for the *m.receipt* event.

use std::collections::HashMap;

use ruma_identifiers::{EventId, RoomId, UserId};

event! {
    /// Informs the client of new receipts.
    pub struct ReceiptEvent(ReceiptEventContent) {
        /// The unique identifier for the room associated with this event.
        pub room_id: RoomId
    }
}

/// The payload of a `ReceiptEvent`.
///
/// A mapping of event ID to a collection of receipts for this event ID. The event ID is the ID of
/// the event being acknowledged and *not* an ID for the receipt itself.
pub type ReceiptEventContent = HashMap<EventId, Receipts>;

/// A collection of receipts.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Receipts {
    /// A collection of users who have sent *m.read* receipts for this event.
    #[serde(rename="m.read")]
    pub m_read: UserReceipts,
}

/// A mapping of user ID to receipt.
///
/// The user ID is the entity who sent this receipt.
pub type UserReceipts = HashMap<UserId, Receipt>;

/// An acknowledgement of an event.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Receipt {
    /// The timestamp the receipt was sent at.
    pub ts: u64,
}
<|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 {
            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`.
    ///
    /// ## Panics
    /// Panics if serialization is not successful.
    #[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`.
    ///
    /// ## Panics
    /// Panics if serialization is not successful.
    #[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.
    ///
    /// ## Panics
    /// Panics in case of native exceptions in cURL.
    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.
    ///
    /// ## Panics
    /// Panics in case of native exceptions in cURL.
    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_err(|err| err.into_error())
                            .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<_>>();
                                Response::new(ez, headers, body)
                            })
                            .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]
    #[cfg(any(feature = "rustc-serialization", feature = "serde-serialization"))]
    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>Accept request body by value<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<B: Into<Vec<u8>>>(mut self, body: B) -> Self {
        self.body = Some(body.into());
        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`.
    ///
    /// ## Panics
    /// Panics if serialization is not successful.
    #[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`.
    ///
    /// ## Panics
    /// Panics if serialization is not successful.
    #[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.
    ///
    /// ## Panics
    /// Panics in case of native exceptions in cURL.
    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.
    ///
    /// ## Panics
    /// Panics in case of native exceptions in cURL.
    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_err(|err| err.into_error())
                            .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<_>>();
                                Response::new(ez, headers, body)
                            })
                            .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]
    #[cfg(any(feature = "rustc-serialization", feature = "serde-serialization"))]
    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>extern crate chrono;
extern crate pink_spider;

use std::time::Instant;
use chrono::Duration;
use pink_spider::model::Playlist;

pub fn main() {
    println!("Start crawling playlists...");
    let now = Instant::now();
    let mut playlists = Playlist::find_actives();
    println!("{} playlists", playlists.len());
    let total = playlists.len();
    let mut index = 0;
    for playlist in playlists.iter_mut() {
        println!("[{}/{}] Fetch latest tracks of [{}] {}: {}",
                 index,
                 total,
                 playlist.provider,
                 playlist.id,
                 playlist.title);
        let tracks = match playlist.fetch_tracks() {
            Ok(tracks) => tracks,
            Err(e)     => {
                println!("{}", e);
                vec![]
            }
        };
        println!("{} tracks are added", tracks.len());
        index += 1;
    }

    println!("Complete crawling playlists... total {} ms",
             Duration::from_std(now.elapsed()).unwrap().num_milliseconds());
}
<commit_msg>Add prefix to playlist_crawler log<commit_after>extern crate chrono;
extern crate pink_spider;

use std::time::Instant;
use chrono::Duration;
use pink_spider::model::Playlist;

pub fn main() {
    println!("Start crawling playlists...");
    let now = Instant::now();
    let mut playlists = Playlist::find_actives();
    println!("[pl_cralwer]{} playlists", playlists.len());
    let total = playlists.len();
    let mut index = 0;
    for playlist in playlists.iter_mut() {
        println!("[pl_cralwer][{}/{}] Fetch latest tracks of [{}] {}: {}",
                 index,
                 total,
                 playlist.provider,
                 playlist.id,
                 playlist.title);
        let tracks = match playlist.fetch_tracks() {
            Ok(tracks) => tracks,
            Err(e)     => {
                println!("[pl_cralwer]{}", e);
                vec![]
            }
        };
        println!("[pl_cralwer]{} tracks are added", tracks.len());
        index += 1;
    }

    println!("[pl_cralwer]Complete crawling playlists... total {} ms",
             Duration::from_std(now.elapsed()).unwrap().num_milliseconds());
}
<|endoftext|>