<commit_before>//! An rope.
//!
//! A rope is an efficient data structure for large mutable strings. It's
//! essentially a binary tree whose leaves are strings.
//!
//! For more information, see the following resources:
//! + http://scienceblogs.com/goodmath/2009/01/26/ropes-twining-together-strings/
//! + https://www.ibm.com/developerworks/library/j-ropes/
//! + http://citeseer.ist.psu.edu/viewdoc/download?doi=10.1.1.14.9450&rep=rep1&type=pdf

#![feature(const_fn)]
#![feature(box_syntax, box_patterns)]

use std::cmp;
use std::ops;
use std::convert;

#[derive(Debug)]
pub struct Rope<T> {
    // can we get away with having these be of &str or will they need
    // to be string?
    root: Node<T>
}

use self::Node::*;

/// A `Node` in the `Rope`'s tree.
///
/// A `Node` is either a `Leaf` holding a vector of `T`, or a
/// a `Branch` concatenating together two `Node`s.
#[derive(Debug)]
enum Node<T> {
    /// A leaf node
    Leaf(Vec<T>)
  , /// A branch concatenating together `l`eft and `r`ight nodes.
    Branch {
        /// The length of this node
        len: usize
      , /// The weight of a node is the summed weight of its left subtree
        weight: usize
      , /// The left branch node
        left: Option<Box<Node<T>>>
      , /// The right branch node
        right: Option<Box<Node<T>>>
    }
}

impl<T> Node<T> {
    const fn none() -> Self {
        Branch { len: 0
               , weight: 0
               , left: None
               , right: None
               }
    }

    /// Concatenate two `Node`s to return a new `Branch` node.
    fn branch(left: Self, right: Self) -> Self {
        Branch { len: left.len() + right.len()
               , weight: left.weight()
               , left: Some(box left)
               , right: Some(box right)
        }
    }

    #[inline]
    fn leaf(data: Vec<T>) -> Self {
        Leaf(data)
    }

    /// Returns the height in the tree of a node
    #[inline]
    fn height(&self) -> usize {
        use std::cmp::max;

        match self {
            &Node::Leaf(_) => 1
          , &Node::Branch { ref left, ref right, ..} =>
                max( left.as_ref().map(Box::as_ref).map_or(0, Node::height)
                   , right.as_ref().map(Box::as_ref).map_or(0, Node::height)
                   ) + 1
            }
    }

    /// Returns the length of a node
    //  TODO: do we want to cache this?
    fn len(&self) -> usize {
        match self { &Node::Leaf(ref v) => v.len()
                   , &Node::Branch { ref left, ref right, .. } =>
                        left.as_ref().map(Box::as_ref).map_or(0, Node::len) +
                        right.as_ref().map(Box::as_ref).map_or(0, Node::len)
                    }
    }

    /// Returns the weight of a node
    fn weight (&self) -> usize {
        match self { &Node::Leaf(ref v) => v.len()
                   , &Node::Branch { ref left, .. } =>
                        left.as_ref().map(Box::as_ref).map_or(0, Node::weight)
                    }
    }
}

impl<T> ops::Add for Node<T> {
    type Output = Self;
    /// Concatenate two `Node`s, returning a `Branch` node.
    fn add(self, right: Self) -> Self { Node::branch(self, right) }
}

impl<T> Rope<T> {

    /// Returns a new empty Rope
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::<u8>::new();
    /// assert_eq!(an_rope.len(), 0);
    /// ```
    pub const fn new() -> Rope<T> {
        Rope { root: Node::<T>::none() }
    }

    /// Returns the length of this Rope
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_empty_rope = Rope::new();
    /// assert_eq!(an_empty_rope.len(), 0);
    /// ```
    /// ```
    /// use an_rope::Rope;
    /// let mut an_empty_rope = Rope::from(String::from(""));
    /// assert_eq!(an_empty_rope.len(), 0);
    /// ```
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::from(String::from("a string"));
    /// assert_eq!(an_rope.len(), "a string".len());
    /// ```
    pub fn len(&self) -> usize {
        // self.root.len()
        unimplemented!()
    }

    /// Appends a `Rope` to the end of this `Rope`, returning a new `Rope`
    ///
    /// Note that this is equivalent to using the `+` operator.
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let an_rope = Rope::from(String::from("abcd"));
    /// let another_rope = an_rope.merge(Rope::from(String::from("efgh")))
    /// assert_eq!(another_rope, Rope::from(String::from("abcdefgh")));
    /// ```
    pub fn merge(&self, other: &Rope<T>) -> Rope<T> {
        unimplemented!()
    }

    /// Appends a `Rope` to the end of this `Rope`, updating it in place.
    ///
    /// Note that this is equivalent to using the `+=` operator.
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::from(String::from("abcd"));
    /// an_rope.update(Rope::from(String::from("efgh")))
    /// assert_eq!(an_rope, Rope::from(String::from("abcdefgh")));
    /// ```
    pub fn update(&mut self, other: Rope<T>) {
        unimplemented!()
    }

    /// Splits the rope into two ropes at the given index.
    ///
    /// Consumes this rope.
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::from(String::from("abcd"));
    /// let (ab, cd) = an_rope.split(2);
    /// assert_eq!(ab, Rope::from(String::from("ab")));
    /// assert_eq!(cd, Rope::from(String::from("cd")));
    /// ```
    pub fn split(self, index: usize) -> (Rope<T>, Rope<T>) {
        unimplemented!()
    }
}

impl<T> ops::Index<usize> for Node<T> {
    type Output = T;

    fn index(&self, i: usize) -> &T {
        // let len = self.len();
        // match self { &Node::Leaf(ref vec) => { &vec[i] }
        //             , &Node::Branch { right: Some(box ref r), .. } if len < i =>
        //                 &r[i - len]
        //             , &Node::Branch { left: Some(box ref l), .. } => &l[i]
        //             , &Node::Branch { left: None, right: None, .. } =>
        //                 panic!("Index out of bounds!")
        //             }
        unimplemented!()
    }
}

impl<T> convert::Into<Vec<T>> for Rope<T> {
    fn into(self) -> Vec<T> {
        unimplemented!()
    }

}

impl convert::From<String> for Rope<u8> {
    fn from(string: String) -> Rope<u8> {
        Rope {
            root: if string.len() == 0 { Node::none() }
                  else { Node::Leaf(string.into_bytes()) }
        }
    }
}

//-- comparisons ----------------------------------------------------
impl<T> cmp::PartialEq for Rope<T> {
    fn eq(&self, other: &Rope<T>) -> bool {
        unimplemented!()
    }
}

impl<T> cmp::PartialEq<str> for Rope<T> {
    fn eq(&self, other: &str) -> bool {
        unimplemented!()
    }
}

//-- concatenation --------------------------------------------------
impl<'a, T> ops::Add for &'a Rope<T> {
    type Output = Rope<T>;
    /// Non-destructively concatenate two `Rope`s, returning a new `Rope`.
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( &rope + &Rope::from(String::from("cd"))
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: Self) -> Rope<T> { self.merge(other) }

}

impl<T> ops::Add for Rope<T> {
    type Output = Rope<T>;
    /// Non-destructively concatenate two `Rope`s, returning a new `Rope`.
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( rope + Rope::from(String::from("cd"))
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: Self) -> Rope<T> { self.merge(&other) }
}

impl ops::Add<String> for Rope<u8> {
    type Output = Rope<u8>;
    /// Non-destructively concatenate a `Rope` and a `String`.
    ///
    /// Returns a new `Rope`
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( rope + String::from("cd"))
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: String) -> Rope<u8> {
         self.merge(&Rope::from(other))
    }
}

impl<'a, 'b> ops::Add<&'b str> for &'a Rope<u8> {
    type Output = Rope<u8>;
    /// Non-destructively concatenate a `Rope` and an `&str`.
    ///
    /// Returns a new `Rope`
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( &rope + "cd")
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: &'b str) -> Rope<u8> {
         self.merge(&Rope::from(other.to_owned()))
     }

}

impl<'a> ops::Add<&'a str> for Rope<u8> {
    type Output = Rope<u8>;
    /// Non-destructively concatenate a `Rope` and an `&str`.
    ///
    /// Returns a new `Rope`
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( rope + "cd")
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: &'a str) -> Rope<u8> {
         self.merge(&Rope::from(other.to_owned()))
     }

}

impl<T> ops::AddAssign for Rope<T> {

    /// Concatenate two `Rope`s mutably.
    ///
    /// # Examples
    /// ```
    /// let mut rope = Rope::from(String::from("ab"));
    /// rope += Rope::from(String::from("cd"));
    /// assert_eq!(rope, Rope::from(String::from("abcd")));
    /// ```
    #[inline]
    fn add_assign(&mut self, other: Rope<T>) {
        self.update(other)
    }
}

impl ops::AddAssign<String> for Rope<u8> {

    /// Concatenate a `String` onto a `Rope` mutably.
    ///
    /// # Examples
    /// ```
    /// let mut rope = Rope::from(String::from("ab"));
    /// rope += String::from("cd");
    /// assert_eq!(rope, Rope::from(String::from("abcd")));
    /// ```
    #[inline]
    fn add_assign(&mut self, string: String) {
        self.update(Rope::from(string))
    }
}

impl<'a> ops::AddAssign<&'a str> for Rope<u8> {

    /// Concatenate an `&str` onto a `Rope` mutably.
    ///
    /// # Examples
    /// ```
    /// let mut rope = Rope::from(String::from("ab"));
    /// rope += String::from("cd");
    /// assert_eq!(rope, Rope::from(String::from("abcd")));
    /// ```
    #[inline]
    fn add_assign(&mut self, string: &'a str) {
        self.update(Rope::from(string.to_owned()))
    }
}

impl<T> ops::Index<usize> for Rope<T> {
    type Output = T;

    /// Recursively index the Rope to return the `i` th character.
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let an_rope = Rope::from(String::from("abcd"));
    /// assert_eq!(&an_rope[0], "a");
    /// assert_eq!(&an_rope[1], "b");
    /// assert_eq!(&an_rope[2], "c");
    /// assert_eq!(&an_rope[3], "d");
    /// ```
    ///
    /// # Time complexity
    /// _O_(log _n_)
    ///
    #[inline]
    fn index(&self, i: usize) -> &T {
        &self.root[i]
    }
}

//-- slicing operators ----------------------------------------------
impl<T> ops::Index<ops::Range<usize>> for Rope<T> {
    type Output = [T];

    // Index a substring
    fn index(&self, i: ops::Range<usize>) -> &[T] {
        unimplemented!()
    }
}

impl<T> ops::Index<ops::RangeTo<usize>> for Rope<T> {
    type Output = [T];

    fn index(&self, i: ops::RangeTo<usize>) -> &[T] {
        unimplemented!()
    }
}

impl<T> ops::Index<ops::RangeFrom<usize>> for Rope<T> {
    type Output = [T];

    fn index(&self, i: ops::RangeFrom<usize>) -> &[T] {
        unimplemented!()
    }
}

impl<T> ops::IndexMut<ops::Range<usize>> for Rope<T> {
    fn index_mut(&mut self, i: ops::Range<usize>) -> &mut [T] {
        unimplemented!()
    }
}

impl<T> ops::IndexMut<ops::RangeTo<usize>> for Rope<T> {
    fn index_mut(&mut self, i: ops::RangeTo<usize>) -> &mut [T] {
        unimplemented!()
    }
}

impl<T> ops::IndexMut<ops::RangeFrom<usize>> for Rope<T> {
    fn index_mut(&mut self, i: ops::RangeFrom<usize>) -> &mut [T] {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>rope: add unimplemented rebalance function<commit_after>//! An rope.
//!
//! A rope is an efficient data structure for large mutable strings. It's
//! essentially a binary tree whose leaves are strings.
//!
//! For more information, see the following resources:
//! + http://scienceblogs.com/goodmath/2009/01/26/ropes-twining-together-strings/
//! + https://www.ibm.com/developerworks/library/j-ropes/
//! + http://citeseer.ist.psu.edu/viewdoc/download?doi=10.1.1.14.9450&rep=rep1&type=pdf

#![feature(const_fn)]
#![feature(box_syntax, box_patterns)]

use std::cmp;
use std::ops;
use std::convert;

#[derive(Debug)]
pub struct Rope<T> {
    // can we get away with having these be of &str or will they need
    // to be string?
    root: Node<T>
}

use self::Node::*;

/// A `Node` in the `Rope`'s tree.
///
/// A `Node` is either a `Leaf` holding a vector of `T`, or a
/// a `Branch` concatenating together two `Node`s.
#[derive(Debug)]
enum Node<T> {
    /// A leaf node
    Leaf(Vec<T>)
  , /// A branch concatenating together `l`eft and `r`ight nodes.
    Branch {
        /// The length of this node
        len: usize
      , /// The weight of a node is the summed weight of its left subtree
        weight: usize
      , /// The left branch node
        left: Option<Box<Node<T>>>
      , /// The right branch node
        right: Option<Box<Node<T>>>
    }
}

impl<T> Node<T> {
    const fn none() -> Self {
        Branch { len: 0
               , weight: 0
               , left: None
               , right: None
               }
    }

    /// Concatenate two `Node`s to return a new `Branch` node.
    fn branch(left: Self, right: Self) -> Self {
        Branch { len: left.len() + right.len()
               , weight: left.weight()
               , left: Some(box left)
               , right: Some(box right)
        }
    }

    #[inline]
    fn leaf(data: Vec<T>) -> Self {
        Leaf(data)
    }

    /// Returns the height in the tree of a node
    #[inline]
    fn height(&self) -> usize {
        use std::cmp::max;

        match self {
            &Node::Leaf(_) => 1
          , &Node::Branch { ref left, ref right, ..} =>
                max( left.as_ref().map(Box::as_ref).map_or(0, Node::height)
                   , right.as_ref().map(Box::as_ref).map_or(0, Node::height)
                   ) + 1
            }
    }

    /// Returns the length of a node
    //  TODO: do we want to cache this?
    fn len(&self) -> usize {
        match self { &Node::Leaf(ref v) => v.len()
                   , &Node::Branch { ref left, ref right, .. } =>
                        left.as_ref().map(Box::as_ref).map_or(0, Node::len) +
                        right.as_ref().map(Box::as_ref).map_or(0, Node::len)
                    }
    }

    /// Returns the weight of a node
    fn weight (&self) -> usize {
        match self { &Node::Leaf(ref v) => v.len()
                   , &Node::Branch { ref left, .. } =>
                        left.as_ref().map(Box::as_ref).map_or(0, Node::weight)
                    }
    }
}

impl<T> ops::Add for Node<T> {
    type Output = Self;
    /// Concatenate two `Node`s, returning a `Branch` node.
    fn add(self, right: Self) -> Self { Node::branch(self, right) }
}

impl<T> Rope<T> {

    /// Returns a new empty Rope
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::<u8>::new();
    /// assert_eq!(an_rope.len(), 0);
    /// ```
    pub const fn new() -> Rope<T> {
        Rope { root: Node::<T>::none() }
    }

    /// Returns the length of this Rope
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_empty_rope = Rope::new();
    /// assert_eq!(an_empty_rope.len(), 0);
    /// ```
    /// ```
    /// use an_rope::Rope;
    /// let mut an_empty_rope = Rope::from(String::from(""));
    /// assert_eq!(an_empty_rope.len(), 0);
    /// ```
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::from(String::from("a string"));
    /// assert_eq!(an_rope.len(), "a string".len());
    /// ```
    pub fn len(&self) -> usize {
        // self.root.len()
        unimplemented!()
    }

    /// Appends a `Rope` to the end of this `Rope`, returning a new `Rope`
    ///
    /// Note that this is equivalent to using the `+` operator.
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let an_rope = Rope::from(String::from("abcd"));
    /// let another_rope = an_rope.merge(Rope::from(String::from("efgh")))
    /// assert_eq!(another_rope, Rope::from(String::from("abcdefgh")));
    /// ```
    pub fn merge(&self, other: &Rope<T>) -> Rope<T> {
        unimplemented!()
    }

    /// Appends a `Rope` to the end of this `Rope`, updating it in place.
    ///
    /// Note that this is equivalent to using the `+=` operator.
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::from(String::from("abcd"));
    /// an_rope.update(Rope::from(String::from("efgh")))
    /// assert_eq!(an_rope, Rope::from(String::from("abcdefgh")));
    /// ```
    pub fn update(&mut self, other: Rope<T>) {
        unimplemented!()
    }

    /// Splits the rope into two ropes at the given index.
    ///
    /// Consumes this rope.
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::from(String::from("abcd"));
    /// let (ab, cd) = an_rope.split(2);
    /// assert_eq!(ab, Rope::from(String::from("ab")));
    /// assert_eq!(cd, Rope::from(String::from("cd")));
    /// ```
    pub fn split(self, index: usize) -> (Rope<T>, Rope<T>) {
        unimplemented!()
    }

    /// Rebalances this entire `Rope`, returning a balanced `Rope`.
    fn rebalance(self) -> Self {
        unimplemented!()
    }
}

impl<T> ops::Index<usize> for Node<T> {
    type Output = T;

    fn index(&self, i: usize) -> &T {
        // let len = self.len();
        // match self { &Node::Leaf(ref vec) => { &vec[i] }
        //             , &Node::Branch { right: Some(box ref r), .. } if len < i =>
        //                 &r[i - len]
        //             , &Node::Branch { left: Some(box ref l), .. } => &l[i]
        //             , &Node::Branch { left: None, right: None, .. } =>
        //                 panic!("Index out of bounds!")
        //             }
        unimplemented!()
    }
}

impl<T> convert::Into<Vec<T>> for Rope<T> {
    fn into(self) -> Vec<T> {
        unimplemented!()
    }

}

impl convert::From<String> for Rope<u8> {
    fn from(string: String) -> Rope<u8> {
        Rope {
            root: if string.len() == 0 { Node::none() }
                  else { Node::Leaf(string.into_bytes()) }
        }
    }
}

//-- comparisons ----------------------------------------------------
impl<T> cmp::PartialEq for Rope<T> {
    fn eq(&self, other: &Rope<T>) -> bool {
        unimplemented!()
    }
}

impl<T> cmp::PartialEq<str> for Rope<T> {
    fn eq(&self, other: &str) -> bool {
        unimplemented!()
    }
}

//-- concatenation --------------------------------------------------
impl<'a, T> ops::Add for &'a Rope<T> {
    type Output = Rope<T>;
    /// Non-destructively concatenate two `Rope`s, returning a new `Rope`.
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( &rope + &Rope::from(String::from("cd"))
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: Self) -> Rope<T> { self.merge(other) }

}

impl<T> ops::Add for Rope<T> {
    type Output = Rope<T>;
    /// Non-destructively concatenate two `Rope`s, returning a new `Rope`.
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( rope + Rope::from(String::from("cd"))
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: Self) -> Rope<T> { self.merge(&other) }
}

impl ops::Add<String> for Rope<u8> {
    type Output = Rope<u8>;
    /// Non-destructively concatenate a `Rope` and a `String`.
    ///
    /// Returns a new `Rope`
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( rope + String::from("cd"))
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: String) -> Rope<u8> {
         self.merge(&Rope::from(other))
    }
}

impl<'a, 'b> ops::Add<&'b str> for &'a Rope<u8> {
    type Output = Rope<u8>;
    /// Non-destructively concatenate a `Rope` and an `&str`.
    ///
    /// Returns a new `Rope`
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( &rope + "cd")
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: &'b str) -> Rope<u8> {
         self.merge(&Rope::from(other.to_owned()))
     }

}

impl<'a> ops::Add<&'a str> for Rope<u8> {
    type Output = Rope<u8>;
    /// Non-destructively concatenate a `Rope` and an `&str`.
    ///
    /// Returns a new `Rope`
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( rope + "cd")
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: &'a str) -> Rope<u8> {
         self.merge(&Rope::from(other.to_owned()))
     }

}

impl<T> ops::AddAssign for Rope<T> {

    /// Concatenate two `Rope`s mutably.
    ///
    /// # Examples
    /// ```
    /// let mut rope = Rope::from(String::from("ab"));
    /// rope += Rope::from(String::from("cd"));
    /// assert_eq!(rope, Rope::from(String::from("abcd")));
    /// ```
    #[inline]
    fn add_assign(&mut self, other: Rope<T>) {
        self.update(other)
    }
}

impl ops::AddAssign<String> for Rope<u8> {

    /// Concatenate a `String` onto a `Rope` mutably.
    ///
    /// # Examples
    /// ```
    /// let mut rope = Rope::from(String::from("ab"));
    /// rope += String::from("cd");
    /// assert_eq!(rope, Rope::from(String::from("abcd")));
    /// ```
    #[inline]
    fn add_assign(&mut self, string: String) {
        self.update(Rope::from(string))
    }
}

impl<'a> ops::AddAssign<&'a str> for Rope<u8> {

    /// Concatenate an `&str` onto a `Rope` mutably.
    ///
    /// # Examples
    /// ```
    /// let mut rope = Rope::from(String::from("ab"));
    /// rope += String::from("cd");
    /// assert_eq!(rope, Rope::from(String::from("abcd")));
    /// ```
    #[inline]
    fn add_assign(&mut self, string: &'a str) {
        self.update(Rope::from(string.to_owned()))
    }
}

impl<T> ops::Index<usize> for Rope<T> {
    type Output = T;

    /// Recursively index the Rope to return the `i` th character.
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let an_rope = Rope::from(String::from("abcd"));
    /// assert_eq!(&an_rope[0], "a");
    /// assert_eq!(&an_rope[1], "b");
    /// assert_eq!(&an_rope[2], "c");
    /// assert_eq!(&an_rope[3], "d");
    /// ```
    ///
    /// # Time complexity
    /// _O_(log _n_)
    ///
    #[inline]
    fn index(&self, i: usize) -> &T {
        &self.root[i]
    }
}

//-- slicing operators ----------------------------------------------
impl<T> ops::Index<ops::Range<usize>> for Rope<T> {
    type Output = [T];

    // Index a substring
    fn index(&self, i: ops::Range<usize>) -> &[T] {
        unimplemented!()
    }
}

impl<T> ops::Index<ops::RangeTo<usize>> for Rope<T> {
    type Output = [T];

    fn index(&self, i: ops::RangeTo<usize>) -> &[T] {
        unimplemented!()
    }
}

impl<T> ops::Index<ops::RangeFrom<usize>> for Rope<T> {
    type Output = [T];

    fn index(&self, i: ops::RangeFrom<usize>) -> &[T] {
        unimplemented!()
    }
}

impl<T> ops::IndexMut<ops::Range<usize>> for Rope<T> {
    fn index_mut(&mut self, i: ops::Range<usize>) -> &mut [T] {
        unimplemented!()
    }
}

impl<T> ops::IndexMut<ops::RangeTo<usize>> for Rope<T> {
    fn index_mut(&mut self, i: ops::RangeTo<usize>) -> &mut [T] {
        unimplemented!()
    }
}

impl<T> ops::IndexMut<ops::RangeFrom<usize>> for Rope<T> {
    fn index_mut(&mut self, i: ops::RangeFrom<usize>) -> &mut [T] {
        unimplemented!()
    }
}

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


<commit_before>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Mining plugin manager, using the cuckoo-miner crate to provide
//! a mining worker implementation
//!

use chrono::prelude::Utc;
use chrono::{Duration, MIN_DATE};
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{mpsc, Arc};
use std::{cmp, io, str, thread, time};

use p2p;
use pool::DandelionConfig;
use util::LOGGER;

// DNS Seeds with contact email associated
const DNS_SEEDS: &'static [&'static str] = &[
	"t3.seed.grin-tech.org",    // igno.peverell@protonmail.com
	"seed.grin.lesceller.com",  // q.lesceller@gmail.com
	"t3.grin-seed.prokapi.com", // info@prokapi.com
];

pub fn connect_and_monitor(
	p2p_server: Arc<p2p::Server>,
	capabilities: p2p::Capabilities,
	dandelion_config: DandelionConfig,
	seed_list: Box<Fn() -> Vec<SocketAddr> + Send>,
	preferred_peers: Option<Vec<SocketAddr>>,
	stop: Arc<AtomicBool>,
) {
	let _ = thread::Builder::new()
		.name("seed".to_string())
		.spawn(move || {
			let peers = p2p_server.peers.clone();

			// open a channel with a listener that connects every peer address sent below
			// max peer count
			let (tx, rx) = mpsc::channel();

			// check seeds first
			connect_to_seeds_and_preferred_peers(
				peers.clone(),
				tx.clone(),
				seed_list,
				preferred_peers.clone(),
			);

			let mut prev = MIN_DATE.and_hms(0, 0, 0);
			let mut start_attempt = 0;

			while !stop.load(Ordering::Relaxed) {
				// make several attempts to get peers as quick as possible
				// with exponential backoff
				if Utc::now() - prev > Duration::seconds(cmp::min(20, 1 << start_attempt)) {
					// try to connect to any address sent to the channel
					listen_for_addrs(peers.clone(), p2p_server.clone(), capabilities, &rx);

					// monitor additional peers if we need to add more
					monitor_peers(
						peers.clone(),
						p2p_server.config.clone(),
						capabilities,
						tx.clone(),
						preferred_peers.clone(),
					);

					update_dandelion_relay(peers.clone(), dandelion_config.clone());

					prev = Utc::now();
					start_attempt = cmp::min(6, start_attempt + 1);
				}

				thread::sleep(time::Duration::from_secs(1));
			}
		});
}

fn monitor_peers(
	peers: Arc<p2p::Peers>,
	config: p2p::P2PConfig,
	capabilities: p2p::Capabilities,
	tx: mpsc::Sender<SocketAddr>,
	preferred_peers_list: Option<Vec<SocketAddr>>,
) {
	// regularly check if we need to acquire more peers  and if so, gets
	// them from db
	let total_count = peers.all_peers().len();
	let mut healthy_count = 0;
	let mut banned_count = 0;
	let mut defunct_count = 0;
	for x in peers.all_peers() {
		match x.flags {
			p2p::State::Banned => {
				let interval = Utc::now().timestamp() - x.last_banned;
				// Unban peer
				if interval >= config.ban_window() {
					peers.unban_peer(&x.addr);
					debug!(
						LOGGER,
						"monitor_peers: unbanned {} after {} seconds", x.addr, interval
					);
				} else {
					banned_count += 1;
				}
			}
			p2p::State::Healthy => healthy_count += 1,
			p2p::State::Defunct => defunct_count += 1,
		}
	}

	debug!(
		LOGGER,
		"monitor_peers: on {}:{}, {} connected ({} most_work). \
		 all {} = {} healthy + {} banned + {} defunct",
		config.host,
		config.port,
		peers.peer_count(),
		peers.most_work_peers().len(),
		total_count,
		healthy_count,
		banned_count,
		defunct_count,
	);

	// maintenance step first, clean up p2p server peers
	peers.clean_peers(config.peer_max_count() as usize);

	// not enough peers, getting more from db
	if peers.peer_count() >= config.peer_min_preferred_count() {
		return;
	}

	// loop over connected peers
	// ask them for their list of peers
	let mut connected_peers: Vec<SocketAddr> = vec![];
	for p in peers.connected_peers() {
		if let Ok(p) = p.try_read() {
			debug!(
				LOGGER,
				"monitor_peers: {}:{} ask {} for more peers", config.host, config.port, p.info.addr,
			);
			let _ = p.send_peer_request(capabilities);
			connected_peers.push(p.info.addr)
		} else {
			warn!(LOGGER, "monitor_peers: failed to get read lock on peer");
		}
	}

	// Attempt to connect to preferred peers if there is some
	match preferred_peers_list {
		Some(preferred_peers) => {
			for mut p in preferred_peers {
				if !connected_peers.is_empty() {
					if !connected_peers.contains(&p) {
						tx.send(p).unwrap();
					}
				} else {
					tx.send(p).unwrap();
				}
			}
		}
		None => debug!(LOGGER, "monitor_peers: no preferred peers"),
	}

	// find some peers from our db
	// and queue them up for a connection attempt
	let new_peers = peers.find_peers(
		p2p::State::Healthy,
		p2p::Capabilities::UNKNOWN,
		config.peer_max_count() as usize,
	);
	for p in new_peers.iter().filter(|p| !peers.is_known(&p.addr)) {
		debug!(
			LOGGER,
			"monitor_peers: on {}:{}, queue to soon try {}", config.host, config.port, p.addr,
		);
		tx.send(p.addr).unwrap();
	}
}

fn update_dandelion_relay(peers: Arc<p2p::Peers>, dandelion_config: DandelionConfig) {
	// Dandelion Relay Updater
	let dandelion_relay = peers.get_dandelion_relay();
	if dandelion_relay.is_empty() {
		debug!(LOGGER, "monitor_peers: no dandelion relay updating");
		peers.update_dandelion_relay();
	} else {
		for last_added in dandelion_relay.keys() {
			let dandelion_interval = Utc::now().timestamp() - last_added;
			if dandelion_interval >= dandelion_config.relay_secs.unwrap() as i64 {
				debug!(LOGGER, "monitor_peers: updating expired dandelion relay");
				peers.update_dandelion_relay();
			}
		}
	}
}

// Check if we have any pre-existing peer in db. If so, start with those,
// otherwise use the seeds provided.
fn connect_to_seeds_and_preferred_peers(
	peers: Arc<p2p::Peers>,
	tx: mpsc::Sender<SocketAddr>,
	seed_list: Box<Fn() -> Vec<SocketAddr>>,
	peers_preferred_list: Option<Vec<SocketAddr>>,
) {
	// check if we have some peers in db
	let peers = peers.find_peers(p2p::State::Healthy, p2p::Capabilities::FULL_HIST, 100);

	// if so, get their addresses, otherwise use our seeds
	let mut peer_addrs = if peers.len() > 3 {
		peers.iter().map(|p| p.addr).collect::<Vec<_>>()
	} else {
		seed_list()
	};

	// If we have preferred peers add them to the connection
	match peers_preferred_list {
		Some(mut peers_preferred) => peer_addrs.append(&mut peers_preferred),
		None => debug!(LOGGER, "No preferred peers"),
	};

	if peer_addrs.len() == 0 {
		warn!(LOGGER, "No seeds were retrieved.");
	}

	// connect to this first set of addresses
	for addr in peer_addrs {
		tx.send(addr).unwrap();
	}
}

/// Regularly poll a channel receiver for new addresses and initiate a
/// connection if the max peer count isn't exceeded. A request for more
/// peers is also automatically sent after connection.
fn listen_for_addrs(
	peers: Arc<p2p::Peers>,
	p2p: Arc<p2p::Server>,
	capab: p2p::Capabilities,
	rx: &mpsc::Receiver<SocketAddr>,
) {
	if peers.peer_count() >= p2p.config.peer_max_count() {
		// clean the rx messages to avoid accumulating
		for _ in rx.try_iter() {}
		return;
	}

	for addr in rx.try_iter() {
		let peers_c = peers.clone();
		let p2p_c = p2p.clone();
		let _ = thread::Builder::new()
			.name("peer_connect".to_string())
			.spawn(move || {
				// connect and retry on fail, but for 3 times at most
				for _ in 0..3 {
					match p2p_c.connect(&addr) {
						Ok(p) => {
							if let Ok(p) = p.try_read() {
								let _ = p.send_peer_request(capab);
							}
							let _ = peers_c.update_state(addr, p2p::State::Healthy);
							break;
						}
						Err(e) => {
							let _ = peers_c.update_state(addr, p2p::State::Defunct);

							// don't retry if connection refused or PeerWithSelf
							match e {
								p2p::Error::Connection(io_err) => {
									if io::ErrorKind::ConnectionRefused == io_err.kind() {
										break;
									}
								}
								p2p::Error::PeerWithSelf => break,
								_ => (), // allow to retry on any other error
							}
						}
					}

					thread::sleep(time::Duration::from_secs(1));
				}
			});
	}
}

pub fn dns_seeds() -> Box<Fn() -> Vec<SocketAddr> + Send> {
	Box::new(|| {
		let mut addresses: Vec<SocketAddr> = vec![];
		for dns_seed in DNS_SEEDS {
			let temp_addresses = addresses.clone();
			debug!(LOGGER, "Retrieving seed nodes from dns {}", dns_seed);
			match (dns_seed.to_owned(), 0).to_socket_addrs() {
				Ok(addrs) => addresses.append(
					&mut (addrs
						.map(|mut addr| {
							addr.set_port(13414);
							addr
						})
						.filter(|addr| !temp_addresses.contains(addr))
						.collect()),
				),
				Err(e) => debug!(
					LOGGER,
					"Failed to resolve seed {:?} got error {:?}", dns_seed, e
				),
			}
		}
		debug!(LOGGER, "Retrieved seed addresses: {:?}", addresses);
		addresses
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn predefined_seeds(addrs_str: Vec<String>) -> Box<Fn() -> Vec<SocketAddr> + Send> {
	Box::new(move || {
		addrs_str
			.iter()
			.map(|s| s.parse().unwrap())
			.collect::<Vec<_>>()
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn preferred_peers(addrs_str: Vec<String>) -> Option<Vec<SocketAddr>> {
	if addrs_str.is_empty() {
		None
	} else {
		Some(
			addrs_str
				.iter()
				.map(|s| s.parse().unwrap())
				.collect::<Vec<_>>(),
		)
	}
}
<commit_msg>Resurrect a random peer on every monitor (#1646)<commit_after>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Mining plugin manager, using the cuckoo-miner crate to provide
//! a mining worker implementation
//!

use chrono::prelude::Utc;
use chrono::{Duration, MIN_DATE};
use rand::{thread_rng, Rng};
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{mpsc, Arc};
use std::{cmp, io, str, thread, time};

use p2p;
use pool::DandelionConfig;
use util::LOGGER;

// DNS Seeds with contact email associated
const DNS_SEEDS: &'static [&'static str] = &[
	"t3.seed.grin-tech.org",    // igno.peverell@protonmail.com
	"seed.grin.lesceller.com",  // q.lesceller@gmail.com
	"t3.grin-seed.prokapi.com", // info@prokapi.com
];

pub fn connect_and_monitor(
	p2p_server: Arc<p2p::Server>,
	capabilities: p2p::Capabilities,
	dandelion_config: DandelionConfig,
	seed_list: Box<Fn() -> Vec<SocketAddr> + Send>,
	preferred_peers: Option<Vec<SocketAddr>>,
	stop: Arc<AtomicBool>,
) {
	let _ = thread::Builder::new()
		.name("seed".to_string())
		.spawn(move || {
			let peers = p2p_server.peers.clone();

			// open a channel with a listener that connects every peer address sent below
			// max peer count
			let (tx, rx) = mpsc::channel();

			// check seeds first
			connect_to_seeds_and_preferred_peers(
				peers.clone(),
				tx.clone(),
				seed_list,
				preferred_peers.clone(),
			);

			let mut prev = MIN_DATE.and_hms(0, 0, 0);
			let mut start_attempt = 0;

			while !stop.load(Ordering::Relaxed) {
				// make several attempts to get peers as quick as possible
				// with exponential backoff
				if Utc::now() - prev > Duration::seconds(cmp::min(20, 1 << start_attempt)) {
					// try to connect to any address sent to the channel
					listen_for_addrs(peers.clone(), p2p_server.clone(), capabilities, &rx);

					// monitor additional peers if we need to add more
					monitor_peers(
						peers.clone(),
						p2p_server.config.clone(),
						capabilities,
						tx.clone(),
						preferred_peers.clone(),
					);

					update_dandelion_relay(peers.clone(), dandelion_config.clone());

					prev = Utc::now();
					start_attempt = cmp::min(6, start_attempt + 1);
				}

				thread::sleep(time::Duration::from_secs(1));
			}
		});
}

fn monitor_peers(
	peers: Arc<p2p::Peers>,
	config: p2p::P2PConfig,
	capabilities: p2p::Capabilities,
	tx: mpsc::Sender<SocketAddr>,
	preferred_peers_list: Option<Vec<SocketAddr>>,
) {
	// regularly check if we need to acquire more peers  and if so, gets
	// them from db
	let total_count = peers.all_peers().len();
	let mut healthy_count = 0;
	let mut banned_count = 0;
	let mut defuncts = vec![];
	for x in peers.all_peers() {
		match x.flags {
			p2p::State::Banned => {
				let interval = Utc::now().timestamp() - x.last_banned;
				// Unban peer
				if interval >= config.ban_window() {
					peers.unban_peer(&x.addr);
					debug!(
						LOGGER,
						"monitor_peers: unbanned {} after {} seconds", x.addr, interval
					);
				} else {
					banned_count += 1;
				}
			}
			p2p::State::Healthy => healthy_count += 1,
			p2p::State::Defunct => defuncts.push(x),
		}
	}

	debug!(
		LOGGER,
		"monitor_peers: on {}:{}, {} connected ({} most_work). \
		 all {} = {} healthy + {} banned + {} defunct",
		config.host,
		config.port,
		peers.peer_count(),
		peers.most_work_peers().len(),
		total_count,
		healthy_count,
		banned_count,
		defuncts.len(),
	);

	// maintenance step first, clean up p2p server peers
	peers.clean_peers(config.peer_max_count() as usize);

	// not enough peers, getting more from db
	if peers.peer_count() >= config.peer_min_preferred_count() {
		return;
	}

	// loop over connected peers
	// ask them for their list of peers
	let mut connected_peers: Vec<SocketAddr> = vec![];
	for p in peers.connected_peers() {
		if let Ok(p) = p.try_read() {
			debug!(
				LOGGER,
				"monitor_peers: {}:{} ask {} for more peers", config.host, config.port, p.info.addr,
			);
			let _ = p.send_peer_request(capabilities);
			connected_peers.push(p.info.addr)
		} else {
			warn!(LOGGER, "monitor_peers: failed to get read lock on peer");
		}
	}

	// Attempt to connect to preferred peers if there is some
	match preferred_peers_list {
		Some(preferred_peers) => {
			for mut p in preferred_peers {
				if !connected_peers.is_empty() {
					if !connected_peers.contains(&p) {
						tx.send(p).unwrap();
					}
				} else {
					tx.send(p).unwrap();
				}
			}
		}
		None => debug!(LOGGER, "monitor_peers: no preferred peers"),
	}

	// take a random defunct peer and mark it healthy: over a long period any
	// peer will see another as defunct eventually, gives us a chance to retry
	if defuncts.len() > 0 {
		thread_rng().shuffle(&mut defuncts);
		let _ = peers.update_state(defuncts[0].addr, p2p::State::Healthy);
	}

	// find some peers from our db
	// and queue them up for a connection attempt
	let new_peers = peers.find_peers(
		p2p::State::Healthy,
		p2p::Capabilities::UNKNOWN,
		config.peer_max_count() as usize,
	);
	for p in new_peers.iter().filter(|p| !peers.is_known(&p.addr)) {
		debug!(
			LOGGER,
			"monitor_peers: on {}:{}, queue to soon try {}", config.host, config.port, p.addr,
		);
		tx.send(p.addr).unwrap();
	}
}

fn update_dandelion_relay(peers: Arc<p2p::Peers>, dandelion_config: DandelionConfig) {
	// Dandelion Relay Updater
	let dandelion_relay = peers.get_dandelion_relay();
	if dandelion_relay.is_empty() {
		debug!(LOGGER, "monitor_peers: no dandelion relay updating");
		peers.update_dandelion_relay();
	} else {
		for last_added in dandelion_relay.keys() {
			let dandelion_interval = Utc::now().timestamp() - last_added;
			if dandelion_interval >= dandelion_config.relay_secs.unwrap() as i64 {
				debug!(LOGGER, "monitor_peers: updating expired dandelion relay");
				peers.update_dandelion_relay();
			}
		}
	}
}

// Check if we have any pre-existing peer in db. If so, start with those,
// otherwise use the seeds provided.
fn connect_to_seeds_and_preferred_peers(
	peers: Arc<p2p::Peers>,
	tx: mpsc::Sender<SocketAddr>,
	seed_list: Box<Fn() -> Vec<SocketAddr>>,
	peers_preferred_list: Option<Vec<SocketAddr>>,
) {
	// check if we have some peers in db
	let peers = peers.find_peers(p2p::State::Healthy, p2p::Capabilities::FULL_HIST, 100);

	// if so, get their addresses, otherwise use our seeds
	let mut peer_addrs = if peers.len() > 3 {
		peers.iter().map(|p| p.addr).collect::<Vec<_>>()
	} else {
		seed_list()
	};

	// If we have preferred peers add them to the connection
	match peers_preferred_list {
		Some(mut peers_preferred) => peer_addrs.append(&mut peers_preferred),
		None => debug!(LOGGER, "No preferred peers"),
	};

	if peer_addrs.len() == 0 {
		warn!(LOGGER, "No seeds were retrieved.");
	}

	// connect to this first set of addresses
	for addr in peer_addrs {
		tx.send(addr).unwrap();
	}
}

/// Regularly poll a channel receiver for new addresses and initiate a
/// connection if the max peer count isn't exceeded. A request for more
/// peers is also automatically sent after connection.
fn listen_for_addrs(
	peers: Arc<p2p::Peers>,
	p2p: Arc<p2p::Server>,
	capab: p2p::Capabilities,
	rx: &mpsc::Receiver<SocketAddr>,
) {
	if peers.peer_count() >= p2p.config.peer_max_count() {
		// clean the rx messages to avoid accumulating
		for _ in rx.try_iter() {}
		return;
	}

	for addr in rx.try_iter() {
		let peers_c = peers.clone();
		let p2p_c = p2p.clone();
		let _ = thread::Builder::new()
			.name("peer_connect".to_string())
			.spawn(move || {
				// connect and retry on fail, but for 3 times at most
				for _ in 0..3 {
					match p2p_c.connect(&addr) {
						Ok(p) => {
							if let Ok(p) = p.try_read() {
								let _ = p.send_peer_request(capab);
							}
							let _ = peers_c.update_state(addr, p2p::State::Healthy);
							break;
						}
						Err(e) => {
							let _ = peers_c.update_state(addr, p2p::State::Defunct);

							// don't retry if connection refused or PeerWithSelf
							match e {
								p2p::Error::Connection(io_err) => {
									if io::ErrorKind::ConnectionRefused == io_err.kind() {
										break;
									}
								}
								p2p::Error::PeerWithSelf => break,
								_ => (), // allow to retry on any other error
							}
						}
					}

					thread::sleep(time::Duration::from_secs(1));
				}
			});
	}
}

pub fn dns_seeds() -> Box<Fn() -> Vec<SocketAddr> + Send> {
	Box::new(|| {
		let mut addresses: Vec<SocketAddr> = vec![];
		for dns_seed in DNS_SEEDS {
			let temp_addresses = addresses.clone();
			debug!(LOGGER, "Retrieving seed nodes from dns {}", dns_seed);
			match (dns_seed.to_owned(), 0).to_socket_addrs() {
				Ok(addrs) => addresses.append(
					&mut (addrs
						.map(|mut addr| {
							addr.set_port(13414);
							addr
						})
						.filter(|addr| !temp_addresses.contains(addr))
						.collect()),
				),
				Err(e) => debug!(
					LOGGER,
					"Failed to resolve seed {:?} got error {:?}", dns_seed, e
				),
			}
		}
		debug!(LOGGER, "Retrieved seed addresses: {:?}", addresses);
		addresses
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn predefined_seeds(addrs_str: Vec<String>) -> Box<Fn() -> Vec<SocketAddr> + Send> {
	Box::new(move || {
		addrs_str
			.iter()
			.map(|s| s.parse().unwrap())
			.collect::<Vec<_>>()
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn preferred_peers(addrs_str: Vec<String>) -> Option<Vec<SocketAddr>> {
	if addrs_str.is_empty() {
		None
	} else {
		Some(
			addrs_str
				.iter()
				.map(|s| s.parse().unwrap())
				.collect::<Vec<_>>(),
		)
	}
}
<|endoftext|>


<commit_before>mod page;
pub use self::page::Page;

use std::env;
use std::io::Read;
use std::ascii::AsciiExt;
use std::default::Default;
use std::collections::BTreeMap;

use url::Url;
use reqwest::Client as HttpClient;
use reqwest::header::UserAgent;
use reqwest::StatusCode;
use reqwest::Response as HttpResponse;
use robotparser::RobotFileParser;
use html5ever::tokenizer::Tokenizer;
use html5ever::tokenizer::buffer_queue::BufferQueue;
use sidekiq::Client as SidekiqClient;
use sidekiq::ClientOpts as SidekiqClientOpts;
use sidekiq::RedisPool;
use encoding::{Encoding, DecoderTrap};
use encoding::all::UTF_8;
use url_serde::Serde;

const MAMAN_ENV: &'static str = "MAMAN_ENV";

pub struct Spider<'a> {
    pub base_url: Url,
    pub visited_urls: Vec<Serde<Url>>,
    pub unvisited_urls: Vec<Serde<Url>>,
    pub env: String,
    pub limit: isize,
    sidekiq: SidekiqClient,
    robot_parser: RobotFileParser<'a>,
}

impl<'a> Spider<'a> {
    pub fn new(redis_pool: RedisPool, base_url: Url, limit: isize) -> Spider<'a> {
        let maman_env = env::var(&MAMAN_ENV.to_string()).unwrap_or("development".to_string());
        let robots_txt = base_url.join("/robots.txt").unwrap();
        let robot_file_parser = RobotFileParser::new(robots_txt);
        let client_opts = SidekiqClientOpts {
            namespace: Some(maman_env.to_string()),
            ..Default::default()
        };
        let sidekiq = SidekiqClient::new(redis_pool, client_opts);
        Spider {
            base_url: base_url,
            visited_urls: Vec::new(),
            unvisited_urls: Vec::new(),
            sidekiq: sidekiq,
            env: maman_env,
            robot_parser: robot_file_parser,
            limit: limit,
        }
    }

    pub fn visit_page(&mut self, page: Page) {
        self.visited_urls.push(page.url.clone());
        for u in page.urls.iter() {
            self.unvisited_urls.push(u.clone());
        }
        match self.sidekiq.push(page.to_job()) {
            Err(err) => {
                error!("SidekiqClient push failed: {}", err);
            }
            Ok(_) => {}
        }
    }

    pub fn crawl(&mut self) {
        self.robot_parser.read();
        let base_url = self.base_url.clone();
        if let Some(response) = Spider::load_url(self.base_url.as_ref()) {
            self.visit(&base_url, response);
            while let Some(url) = self.unvisited_urls.pop() {
                if self.continue_to_crawl() {
                    if !self.visited_urls.contains(&url) {
                        if let Some(response) = Spider::load_url(url.as_ref()) {
                            self.visit(&url, response);
                        }
                    }
                } else {
                    break;
                }
            }
        }
    }

    pub fn read_page(page: Page, document: &str) -> Tokenizer<Page> {
        let mut tok = Tokenizer::new(page, Default::default());
        let mut input = BufferQueue::new();
        input.push_back(String::from(document).into());
        let _ = tok.feed(&mut input);
        tok.end();
        tok
    }

    fn visit(&mut self, page_url: &Url, response: HttpResponse) {
        if self.can_visit(page_url) {
            info!("{}", page_url);
            if let Some(page) = Spider::read_response(page_url, response) {
                self.visit_page(page);
            }
        }
    }

    fn continue_to_crawl(&self) -> bool {
        self.limit == 0 || (self.visited_urls.len() as isize) < self.limit
    }

    fn can_visit(&self, page_url: &Url) -> bool {
        self.robot_parser
            .can_fetch(maman_name!(), page_url.path())
    }

    fn read_response(page_url: &Url, mut response: HttpResponse) -> Option<Page> {
        let mut headers = BTreeMap::new();
        {
            for h in response.headers().iter() {
                headers.insert(h.name().to_ascii_lowercase(), h.value_string());
            }
        }
        let mut document = vec![];
        let _ = response.read_to_end(&mut document);
        match UTF_8.decode(&document, DecoderTrap::Ignore) {
            Ok(doc) => {
                let page = Page::new(page_url.clone(), doc.to_string(), headers.clone());
                let read = Spider::read_page(page, &doc).unwrap();
                Some(read)
            }
            Err(_) => None,
        }
    }

    fn load_url(url: &str) -> Option<HttpResponse> {
        let client = HttpClient::new().expect("HttpClient failed to construct");
        let request = client
            .get(url)
            .header(UserAgent(maman_user_agent!().to_owned()));
        match request.send() {
            Ok(response) => {
                match response.status() {
                    &StatusCode::Ok |
                    &StatusCode::NotModified => Some(response),
                    _ => None,
                }
            }
            Err(_) => None,
        }
    }
}
<commit_msg>Fix `unwrap_or` followed by a function call<commit_after>mod page;
pub use self::page::Page;

use std::env;
use std::io::Read;
use std::ascii::AsciiExt;
use std::default::Default;
use std::collections::BTreeMap;

use url::Url;
use reqwest::Client as HttpClient;
use reqwest::header::UserAgent;
use reqwest::StatusCode;
use reqwest::Response as HttpResponse;
use robotparser::RobotFileParser;
use html5ever::tokenizer::Tokenizer;
use html5ever::tokenizer::buffer_queue::BufferQueue;
use sidekiq::Client as SidekiqClient;
use sidekiq::ClientOpts as SidekiqClientOpts;
use sidekiq::RedisPool;
use encoding::{Encoding, DecoderTrap};
use encoding::all::UTF_8;
use url_serde::Serde;

const MAMAN_ENV: &'static str = "MAMAN_ENV";
const MAMAN_ENV_DEFAULT: &'static str = "development";

pub struct Spider<'a> {
    pub base_url: Url,
    pub visited_urls: Vec<Serde<Url>>,
    pub unvisited_urls: Vec<Serde<Url>>,
    pub env: String,
    pub limit: isize,
    sidekiq: SidekiqClient,
    robot_parser: RobotFileParser<'a>,
}

impl<'a> Spider<'a> {
    pub fn new(redis_pool: RedisPool, base_url: Url, limit: isize) -> Spider<'a> {
        let maman_env = env::var(&MAMAN_ENV.to_owned()).unwrap_or_else(|_| MAMAN_ENV_DEFAULT.to_owned());
        let robots_txt = base_url.join("/robots.txt").unwrap();
        let robot_file_parser = RobotFileParser::new(robots_txt);
        let client_opts = SidekiqClientOpts {
            namespace: Some(maman_env.to_string()),
            ..Default::default()
        };
        let sidekiq = SidekiqClient::new(redis_pool, client_opts);
        Spider {
            base_url: base_url,
            visited_urls: Vec::new(),
            unvisited_urls: Vec::new(),
            sidekiq: sidekiq,
            env: maman_env,
            robot_parser: robot_file_parser,
            limit: limit,
        }
    }

    pub fn visit_page(&mut self, page: Page) {
        self.visited_urls.push(page.url.clone());
        for u in page.urls.iter() {
            self.unvisited_urls.push(u.clone());
        }
        match self.sidekiq.push(page.to_job()) {
            Err(err) => {
                error!("SidekiqClient push failed: {}", err);
            }
            Ok(_) => {}
        }
    }

    pub fn crawl(&mut self) {
        self.robot_parser.read();
        let base_url = self.base_url.clone();
        if let Some(response) = Spider::load_url(self.base_url.as_ref()) {
            self.visit(&base_url, response);
            while let Some(url) = self.unvisited_urls.pop() {
                if self.continue_to_crawl() {
                    if !self.visited_urls.contains(&url) {
                        if let Some(response) = Spider::load_url(url.as_ref()) {
                            self.visit(&url, response);
                        }
                    }
                } else {
                    break;
                }
            }
        }
    }

    pub fn read_page(page: Page, document: &str) -> Tokenizer<Page> {
        let mut tok = Tokenizer::new(page, Default::default());
        let mut input = BufferQueue::new();
        input.push_back(String::from(document).into());
        let _ = tok.feed(&mut input);
        tok.end();
        tok
    }

    fn visit(&mut self, page_url: &Url, response: HttpResponse) {
        if self.can_visit(page_url) {
            info!("{}", page_url);
            if let Some(page) = Spider::read_response(page_url, response) {
                self.visit_page(page);
            }
        }
    }

    fn continue_to_crawl(&self) -> bool {
        self.limit == 0 || (self.visited_urls.len() as isize) < self.limit
    }

    fn can_visit(&self, page_url: &Url) -> bool {
        self.robot_parser
            .can_fetch(maman_name!(), page_url.path())
    }

    fn read_response(page_url: &Url, mut response: HttpResponse) -> Option<Page> {
        let mut headers = BTreeMap::new();
        {
            for h in response.headers().iter() {
                headers.insert(h.name().to_ascii_lowercase(), h.value_string());
            }
        }
        let mut document = vec![];
        let _ = response.read_to_end(&mut document);
        match UTF_8.decode(&document, DecoderTrap::Ignore) {
            Ok(doc) => {
                let page = Page::new(page_url.clone(), doc.to_string(), headers.clone());
                let read = Spider::read_page(page, &doc).unwrap();
                Some(read)
            }
            Err(_) => None,
        }
    }

    fn load_url(url: &str) -> Option<HttpResponse> {
        let client = HttpClient::new().expect("HttpClient failed to construct");
        let request = client
            .get(url)
            .header(UserAgent(maman_user_agent!().to_owned()));
        match request.send() {
            Ok(response) => {
                match response.status() {
                    &StatusCode::Ok |
                    &StatusCode::NotModified => Some(response),
                    _ => None,
                }
            }
            Err(_) => None,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Sam Payson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::io;
use std::mem;

pub enum Primitive {
    UInt8(u8),
    UInt16(u16),
    UInt32(u32),
    UInt64(u64),

    Int8(i8),
    Int16(i16),
    Int32(i32),
    Int64(i64),

    Fixed32(u32),
    Fixed64(u64),

    Float32(f32),
    Float64(f64),

    Bool(bool),

    Bytes(Vec<u8>),
    String(String),

    Enum(i64),
}

pub fn uvarint_size(x: u64) -> usize {
    if x < 0x80 {
        1
    } else if x < 0x80 << 7 {
        2
    } else if x < 0x80 << 14 {
        3
    } else if x < 0x80 << 21 {
        4
    } else if x < 0x80 << 28 {
        5
    } else if x < 0x80 << 35 {
        6
    } else if x < 0x80 << 42 {
        7
    } else if x < 0x80 << 49 {
        8
    } else if x < 0x80 << 56 {
        9
    } else {
        10
    }
}

pub fn varint_size(x: i64) -> usize {
    let ux = (x as u64) << 1;

    uvarint_size(if x < 0 { !ux } else { ux })
}

pub fn write_uvarint<W>(w: &mut W, mut x: u64) -> io::Result<usize>
    where W: io::Write {

    // A 64-bit varint can be at most 10 bytes long.
    let mut buf = [0u8; 10];
    let mut idx = 0;

    while x > 0x7F {
        buf[idx] = 0x80 | (x & 0x7F) as u8;
        x = x >> 7;
        idx += 1;
    }

    buf[idx] = x as u8;

    try!(w.write_all(&buf[idx..]));

    Ok((idx + 1) as usize)
}

pub fn write_varint<W>(w: &mut W, x: i64) -> io::Result<usize>
    where W: io::Write {

    let ux = (x as u64) << 1;

    write_uvarint(w, if x < 0 { !ux } else { ux })
}

pub fn write_le_u8<W>(w: &mut W, x: u8) -> io::Result<usize>
    where W: io::Write {

    let buf = [x];
    try!(w.write_all(&buf));
    Ok(1)
}

pub fn write_le_u16<W>(w: &mut W, x: u16) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >> 0) & 0xFF) as u8,
        ((x >> 8) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(2)
}

pub fn write_le_u32<W>(w: &mut W, x: u32) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >>  0) & 0xFF) as u8,
        ((x >>  8) & 0xFF) as u8,
        ((x >> 16) & 0xFF) as u8,
        ((x >> 24) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(4)
}

pub fn write_le_u64<W>(w: &mut W, x: u64) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >>  0) & 0xFF) as u8,
        ((x >>  8) & 0xFF) as u8,
        ((x >> 16) & 0xFF) as u8,
        ((x >> 24) & 0xFF) as u8,
        ((x >> 32) & 0xFF) as u8,
        ((x >> 40) & 0xFF) as u8,
        ((x >> 48) & 0xFF) as u8,
        ((x >> 56) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(8)
}

pub fn write_le_i8<W>(w: &mut W, x: i8) -> io::Result<usize>
    where W: io::Write {

    write_le_u8(w, x as u8)
}

pub fn write_le_i16<W>(w: &mut W, x: i16) -> io::Result<usize>
    where W: io::Write {

    write_le_u16(w, x as u16)
}

pub fn write_le_i32<W>(w: &mut W, x: i32) -> io::Result<usize>
    where W: io::Write {

    write_le_u32(w, x as u32)
}

pub fn write_le_i64<W>(w: &mut W, x: i64) -> io::Result<usize>
    where W: io::Write {

    write_le_u64(w, x as u64)
}

pub fn write_le_f32<W>(w: &mut W, x: f32) -> io::Result<usize>
    where W: io::Write {

    write_le_u32(w, unsafe { mem::transmute(x) })
}

pub fn write_le_f64<W>(w: &mut W, x: f64) -> io::Result<usize>
    where W: io::Write {

    write_le_u64(w, unsafe { mem::transmute(x) })
}
<commit_msg>Added the `has_type' method to Primitive.<commit_after>// Copyright (c) 2015, Sam Payson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::io;
use std::mem;

use encoding::Type;

// Hopefully we can remove this annotation eventually. Not sure why it's yelling at us about this
// of all things.
#[allow(dead_code)]
pub enum Primitive {
    UInt8(u8),
    UInt16(u16),
    UInt32(u32),
    UInt64(u64),

    Int8(i8),
    Int16(i16),
    Int32(i32),
    Int64(i64),

    Fixed32(u32),
    Fixed64(u64),

    Float32(f32),
    Float64(f64),

    Bool(bool),

    Bytes(Vec<u8>),
    String(String),

    Enum(i64),
}

impl Primitive {
    pub fn has_type(&self, t: Type) -> bool {
        use encoding::Type::*;

        match (self, t) {
            (&Primitive::UInt8(..),  UInt8)  => true,
            (&Primitive::UInt16(..), UInt8)  => true,
            (&Primitive::UInt32(..), UInt32) => true,
            (&Primitive::UInt64(..), UInt64) => true,

            (&Primitive::Int8(..),  Int8)  => true,
            (&Primitive::Int16(..), Int8)  => true,
            (&Primitive::Int32(..), Int32) => true,
            (&Primitive::Int64(..), Int64) => true,

            (&Primitive::Fixed32(..), Fixed32) => true,
            (&Primitive::Fixed64(..), Fixed64) => true,

            (&Primitive::Float32(..), Float32) => true,
            (&Primitive::Float64(..), Float64) => true,

            (&Primitive::Bool(..), Bool) => true,

            (&Primitive::Bytes(..), Bytes)   => true,
            (&Primitive::String(..), String) => true,

            (&Primitive::Enum(..), Enum) => true,

            _ => false,
        }
    }
}

pub fn uvarint_size(x: u64) -> usize {
    if x < 0x80 {
        1
    } else if x < 0x80 << 7 {
        2
    } else if x < 0x80 << 14 {
        3
    } else if x < 0x80 << 21 {
        4
    } else if x < 0x80 << 28 {
        5
    } else if x < 0x80 << 35 {
        6
    } else if x < 0x80 << 42 {
        7
    } else if x < 0x80 << 49 {
        8
    } else if x < 0x80 << 56 {
        9
    } else {
        10
    }
}

pub fn varint_size(x: i64) -> usize {
    let ux = (x as u64) << 1;

    uvarint_size(if x < 0 { !ux } else { ux })
}

pub fn write_uvarint<W>(w: &mut W, mut x: u64) -> io::Result<usize>
    where W: io::Write {

    // A 64-bit varint can be at most 10 bytes long.
    let mut buf = [0u8; 10];
    let mut idx = 0;

    while x > 0x7F {
        buf[idx] = 0x80 | (x & 0x7F) as u8;
        x = x >> 7;
        idx += 1;
    }

    buf[idx] = x as u8;

    try!(w.write_all(&buf[idx..]));

    Ok((idx + 1) as usize)
}

pub fn write_varint<W>(w: &mut W, x: i64) -> io::Result<usize>
    where W: io::Write {

    let ux = (x as u64) << 1;

    write_uvarint(w, if x < 0 { !ux } else { ux })
}

pub fn write_le_u8<W>(w: &mut W, x: u8) -> io::Result<usize>
    where W: io::Write {

    let buf = [x];
    try!(w.write_all(&buf));
    Ok(1)
}

pub fn write_le_u16<W>(w: &mut W, x: u16) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >> 0) & 0xFF) as u8,
        ((x >> 8) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(2)
}

pub fn write_le_u32<W>(w: &mut W, x: u32) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >>  0) & 0xFF) as u8,
        ((x >>  8) & 0xFF) as u8,
        ((x >> 16) & 0xFF) as u8,
        ((x >> 24) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(4)
}

pub fn write_le_u64<W>(w: &mut W, x: u64) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >>  0) & 0xFF) as u8,
        ((x >>  8) & 0xFF) as u8,
        ((x >> 16) & 0xFF) as u8,
        ((x >> 24) & 0xFF) as u8,
        ((x >> 32) & 0xFF) as u8,
        ((x >> 40) & 0xFF) as u8,
        ((x >> 48) & 0xFF) as u8,
        ((x >> 56) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(8)
}

pub fn write_le_i8<W>(w: &mut W, x: i8) -> io::Result<usize>
    where W: io::Write {

    write_le_u8(w, x as u8)
}

pub fn write_le_i16<W>(w: &mut W, x: i16) -> io::Result<usize>
    where W: io::Write {

    write_le_u16(w, x as u16)
}

pub fn write_le_i32<W>(w: &mut W, x: i32) -> io::Result<usize>
    where W: io::Write {

    write_le_u32(w, x as u32)
}

pub fn write_le_i64<W>(w: &mut W, x: i64) -> io::Result<usize>
    where W: io::Write {

    write_le_u64(w, x as u64)
}

pub fn write_le_f32<W>(w: &mut W, x: f32) -> io::Result<usize>
    where W: io::Write {

    write_le_u32(w, unsafe { mem::transmute(x) })
}

pub fn write_le_f64<W>(w: &mut W, x: f64) -> io::Result<usize>
    where W: io::Write {

    write_le_u64(w, unsafe { mem::transmute(x) })
}
<|endoftext|>


<commit_before>#[derive(PartialEq, Debug)]
pub enum Token {
    Word(String),

    //characters
    LeftParenthesis,
    RightParenthesis,
    SemiColon,
    SingleQuote,
    Colon
}

#[derive(PartialEq, Debug)]
enum QueryParseStatus {
    EmptyLine,
    StringExpression,
    QueryBody
}

pub struct Lexer {
    src: Vec<char>,
    status: QueryParseStatus
}

impl Lexer {

    pub fn new(line: &str) -> Lexer {
        let src = line.chars().collect::<Vec<char>>();
        Lexer {
            src: src,
            status: if line.is_empty() { QueryParseStatus::EmptyLine } else { QueryParseStatus::QueryBody }
        }
    }

    pub fn next_lexem(&mut self) -> Option<Token> {
        match self.status {
            QueryParseStatus::EmptyLine => None,
            QueryParseStatus::StringExpression => self.parse_word_token(),
            QueryParseStatus::QueryBody => self.parse_non_word_token(),
        }
    }

    fn parse_word_token(&mut self) -> Option<Token> {
        let mut i = 0;
        while i < self.src.len()
                && !self.is_string_expression_delimeter(i) {
            if self.is_single_quote_escape(i) {
                self.src.remove(i);
            }
            i += 1;
        }
        Some(Token::Word(self.parse_word_lexem(i)))
    }

    fn parse_word_lexem(&mut self, index: usize) -> String {
        let mut v = self.src.clone();
        self.src = v.split_off(index);
        self.change_query_status(None);
        v.iter().map(|c| *c).collect::<String>().to_lowercase()
    }

    fn change_query_status(&mut self, symbol: Option<char>) {
        if self.src.is_empty() {
            self.status = QueryParseStatus::EmptyLine;
        }
        else if symbol == Some('\'') {
            self.status = QueryParseStatus::StringExpression;
        }
        else {
            self.status = QueryParseStatus::QueryBody;
        }
    }

    fn is_single_quote_escape(&self, index: usize) -> bool {
        self.src.len() - index > 1
            && self.src[index] == '\''
            && self.src[index + 1] == '\''
    }

    fn is_string_expression_delimeter(&self, index: usize) -> bool {
        self.src.len() - index <= 1
            && self.src[index] == '\''
    }

    fn parse_non_word_token(&mut self) -> Option<Token> {
        self.remove_front_spaces();
        self.change_query_status(None);
        if self.status == QueryParseStatus::EmptyLine {
            None
        }
        else {
            self.parse_lexem()
        }
    }

    fn parse_lexem(&mut self) -> Option<Token> {
        if self.has_lexem_in_begining() {
            let s = self.src.remove(0);
            self.change_query_status(Some(s));
            match s {
                '(' => return Some(Token::LeftParenthesis),
                ',' => return Some(Token::Colon),
                ')' => return Some(Token::RightParenthesis),
                ';' => return Some(Token::SemiColon),
                '\'' => return Some(Token::SingleQuote),
                _ => {}
            }
        }
        let mut i = 0;
        while i < self.src.len() {
            let s = self.src[i];
            match s {
                'a'...'z' |
                'A'...'Z' |
                '0'...'9' |
                '_' => i += 1,
                ' ' | '\t' | '\n' => {
                    if i == 0 {
                        self.remove_front_spaces();
                    }
                    else {
                        break;
                    }
                },
                '-' => {
                    if i == 0 && self.src[1] == '-' {
                        let comment_length = self.src.iter().take_while(|c| **c != '\n').count();
                        self.src = self.src.split_off(comment_length);
                    }
                },
                _ => break,
            }
        }
        Some(Token::Word(self.parse_word_lexem(i)))
    }

    fn has_lexem_in_begining(&self) -> bool {
        match self.src[0] {
            '(' | ')' | ',' | ';' | '\'' => true,
            _ => false,
        }
    }

    fn remove_front_spaces(&mut self) {
        while !self.src.is_empty()
                && (self.src[0] == ' '
                || self.src[0] == '\t'
                || self.src[0] == '\n') {
            self.src.remove(0);
        }
    }
}
<commit_msg>impl: exclude multy lines comments<commit_after>#[derive(PartialEq, Debug)]
pub enum Token {
    Word(String),

    //characters
    LeftParenthesis,
    RightParenthesis,
    SemiColon,
    SingleQuote,
    Colon
}

#[derive(PartialEq, Debug)]
enum QueryParseStatus {
    EmptyLine,
    StringExpression,
    QueryBody
}

pub struct Lexer {
    src: Vec<char>,
    status: QueryParseStatus
}

impl Lexer {

    pub fn new(line: &str) -> Lexer {
        let src = line.chars().collect::<Vec<char>>();
        Lexer {
            src: src,
            status: if line.is_empty() { QueryParseStatus::EmptyLine } else { QueryParseStatus::QueryBody }
        }
    }

    pub fn next_lexem(&mut self) -> Option<Token> {
        match self.status {
            QueryParseStatus::EmptyLine => None,
            QueryParseStatus::StringExpression => self.parse_word_token(),
            QueryParseStatus::QueryBody => self.parse_non_word_token(),
        }
    }

    fn parse_word_token(&mut self) -> Option<Token> {
        let mut i = 0;
        while i < self.src.len()
                && !self.is_string_expression_delimeter(i) {
            if self.is_single_quote_escape(i) {
                self.src.remove(i);
            }
            i += 1;
        }
        Some(Token::Word(self.parse_word_lexem(i)))
    }

    fn parse_word_lexem(&mut self, index: usize) -> String {
        let mut v = self.src.clone();
        self.src = v.split_off(index);
        self.change_query_status(None);
        v.iter().map(|c| *c).collect::<String>().to_lowercase()
    }

    fn change_query_status(&mut self, symbol: Option<char>) {
        if self.src.is_empty() {
            self.status = QueryParseStatus::EmptyLine;
        }
        else if symbol == Some('\'') {
            self.status = QueryParseStatus::StringExpression;
        }
        else {
            self.status = QueryParseStatus::QueryBody;
        }
    }

    fn is_single_quote_escape(&self, index: usize) -> bool {
        self.src.len() - index > 1
            && self.src[index] == '\''
            && self.src[index + 1] == '\''
    }

    fn is_string_expression_delimeter(&self, index: usize) -> bool {
        self.src.len() - index <= 1
            && self.src[index] == '\''
    }

    fn parse_non_word_token(&mut self) -> Option<Token> {
        self.remove_front_spaces();
        self.change_query_status(None);
        if self.status == QueryParseStatus::EmptyLine {
            None
        }
        else {
            self.parse_lexem()
        }
    }

    fn parse_lexem(&mut self) -> Option<Token> {
        if self.has_lexem_in_begining() {
            let s = self.src.remove(0);
            self.change_query_status(Some(s));
            match s {
                '(' => return Some(Token::LeftParenthesis),
                ',' => return Some(Token::Colon),
                ')' => return Some(Token::RightParenthesis),
                ';' => return Some(Token::SemiColon),
                '\'' => return Some(Token::SingleQuote),
                _ => {}
            }
        }
        let mut i = 0;
        while i < self.src.len() {
            let s = self.src[i];
            match s {
                'a'...'z' |
                'A'...'Z' |
                '0'...'9' |
                '_' => i += 1,
                ' ' | '\t' | '\n' => {
                    if i == 0 {
                        println!("119 going to remove spaces");
                        self.remove_front_spaces();
                    }
                    else {
                        break;
                    }
                },
                '-' => {
                    if i == 0 && self.src[1] == '-' {
                        let comment_length = self.src.iter().take_while(|c| **c != '\n').count();
                        self.src = self.src.split_off(comment_length);
                    }
                },
                '/' => {
                    if i == 0 && self.src[1] == '*' {
                        let mut comment_length = 2;
                        let mut c = self.src[comment_length];
                        let mut c_next = self.src[comment_length+1];
                        while c != '*'
                                && c_next != '/' {
                            comment_length += 1;
                            c = self.src[comment_length];
                            c_next = self.src[comment_length+1];
                        }
                        self.src = self.src.split_off(comment_length+2);
                    }
                },
                _ => break,
            }
        }
        Some(Token::Word(self.parse_word_lexem(i)))
    }

    fn has_lexem_in_begining(&self) -> bool {
        match self.src[0] {
            '(' | ')' | ',' | ';' | '\'' => true,
            _ => false,
        }
    }

    fn remove_front_spaces(&mut self) {
        while !self.src.is_empty()
                && (self.src[0] == ' '
                || self.src[0] == '\t'
                || self.src[0] == '\n') {
            self.src.remove(0);
        }
    }
}
<|endoftext|>


<commit_before>use op;
use regex;

pub trait OpTransform {
    fn transform(&self, op: op::Op) -> op::Op;
}

pub struct NsFilterTransform {
    allowed_pattern: regex::Regex
}

impl NsFilterTransform {
    pub fn new(patten: regex::Regex) -> NsFilterTransform {
        NsFilterTransform {
            allowed_pattern: patten
        }
    }
}

impl OpTransform for NsFilterTransform {
    fn transform(&self, op: op::Op) -> op::Op {
        // TODO: there's got to be a better way
        let mut is_match = false;
        if let Some(ns) = op.get_ns() {
            is_match = self.allowed_pattern.is_match(ns);
        }
        if is_match {
            return op;
        }
        op::Op::NoOp {
            ts: op.get_ts().clone(),
            h: op.get_h().clone(),
        }
    }
}
<commit_msg>OPLOG-5: refactor a bit<commit_after>use op;
use regex;

pub trait OpTransform {
    fn transform(&self, op: op::Op) -> op::Op;
}

pub struct NsFilterTransform {
    allowed_pattern: regex::Regex,
}

impl NsFilterTransform {
    pub fn new(patten: regex::Regex) -> NsFilterTransform {
        NsFilterTransform { allowed_pattern: patten }
    }
}

impl OpTransform for NsFilterTransform {
    fn transform(&self, op: op::Op) -> op::Op {
        let is_match = {
            if let Some(ns) = op.get_ns() {
                self.allowed_pattern.is_match(ns)
            } else {
                false
            }
        };

        if is_match {
            return op;
        }
        op::Op::NoOp {
            ts: op.get_ts().clone(),
            h: op.get_h().clone(),
        }
    }
}
<|endoftext|>


<commit_before>use Request;

use std::io::Read;
use std::error::Error;

/// Request and response transport abstraction.
///
/// The `Transport` trait provides a way to send a `Request` to a server and to receive the
/// corresponding response. A `Transport` implementor is passed to [`Request::call`] in order to use
/// it to perform that request.
///
/// The most commonly used transport is simple HTTP: If the `reqwest` feature is enabled (it is by
/// default), the reqwest `RequestBuilder` will implement this trait and send the XML-RPC
/// [`Request`] via HTTP.
///
/// You can implement this trait for your own types if you want to customize how requests are sent.
/// You can modify HTTP headers or wrap requests in a completely different protocol.
///
/// [`Request::call`]: struct.Request.html#method.call
/// [`Request`]: struct.Request.html
pub trait Transport {
    // FIXME replace with `impl Trait` when stable
    /// The response stream returned by `transmit`.
    type Stream: Read;

    /// Transmits an XML-RPC request and returns the server's response.
    ///
    /// The response is returned as a `Self::Stream` - some type implementing the `Read` trait. The
    /// library will read all of the data and parse it as a response. It must be UTF-8 encoded XML,
    /// otherwise the call will fail.
    ///
    /// # Errors
    ///
    /// If a transport error occurs, it should be returned as a boxed error - the library will then
    /// return an appropriate [`Error`] to the caller.
    ///
    /// [`Error`]: struct.Error.html
    fn transmit(self, request: &Request) -> Result<Self::Stream, Box<Error + Send + Sync>>;
}

// FIXME: Link to `Transport` and `RequestBuilder` using intra-rustdoc links. Relative links break
// everything and abs. links don't work locally.
/// Provides helpers for implementing custom `Transport`s using reqwest.
///
/// This module will be disabled if the `reqwest` feature is not enabled.
///
/// The default [`Transport`] implementation for `RequestBuilder` looks roughly like
/// this:
///
/// ```notrust
/// // serialize request into `body` (a `Vec<u8>`)
///
/// build_headers(builder, body.len());
///
/// // send `body` using `builder` and get response
///
/// check_response(&response)?;
/// ```
///
/// From this, you can build your own custom transports.
///
/// [`Transport`]: ../trait.Transport.html
#[cfg(feature = "reqwest")]
pub mod http {
    extern crate reqwest;

    use {Request, Transport};
    use self::reqwest::{RequestBuilder, mime};
    use self::reqwest::header::{ContentType, ContentLength, UserAgent};

    use std::error::Error;

    /// Appends all HTTP headers required by the XML-RPC specification to the `RequestBuilder`.
    ///
    /// More specifically, the following headers are set:
    ///
    /// ```notrust
    /// User-Agent: Rust xmlrpc
    /// Content-Type: text/xml; charset=utf-8
    /// Content-Length: $body_len
    /// ```
    pub fn build_headers(builder: &mut RequestBuilder, body_len: u64) {
        // Set all required request headers
        // NB: The `Host` header is also required, but reqwest adds it automatically, since
        // HTTP/1.1 requires it.
        builder
            .header(UserAgent::new("Rust xmlrpc"))
            .header(ContentType("text/xml; charset=utf-8".parse().unwrap()))
            .header(ContentLength(body_len));
    }

    /// Checks that a reqwest `Response` has a status code indicating success and contains all
    /// required headers.
    ///
    /// In particular, the following headers must be present:
    ///
    /// ```notrust
    /// Content-Type: text/xml
    /// Content-Length: <body length>
    /// ```
    pub fn check_response(response: &reqwest::Response) -> Result<(), Box<Error + Send + Sync>> {
        // This is essentially an open-coded version of `Response::error_for_status` that does not
        // consume the response.
        if response.status().is_client_error() || response.status().is_server_error() {
            return Err(format!("server response indicates error: {}", response.status()).into());
        }

        // Check response headers
        // "The Content-Type is text/xml. Content-Length must be present and correct."
        if let Some(content) = response.headers().get::<ContentType>() {
            // (we ignore this if the header is missing completely)
            match (content.type_(), content.subtype()) {
                (mime::TEXT, mime::XML) => {},
                (ty, sub) => return Err(
                    format!("expected Content-Type 'text/xml', got '{}/{}'", ty, sub).into()
                ),
            }
        }

        response.headers().get::<ContentLength>()
            .ok_or_else(|| Box::<Error + Send + Sync>::from(format!("expected Content-Length header, but none was found")))?;

        Ok(())
    }

    /// Use a `RequestBuilder` as the transport.
    ///
    /// The request will be sent as specified in the XML-RPC specification: A default `User-Agent`
    /// will be set, along with the correct `Content-Type` and `Content-Length`.
    impl Transport for RequestBuilder {
        type Stream = reqwest::Response;

        fn transmit(mut self, request: &Request) -> Result<Self::Stream, Box<Error + Send + Sync>> {
            // First, build the body XML
            let mut body = Vec::new();
            // This unwrap never panics as we are using `Vec<u8>` as a `Write` implementor,
            // and not doing anything else that could return an `Err` in `write_as_xml()`.
            request.write_as_xml(&mut body).unwrap();

            build_headers(&mut self, body.len() as u64);

            let response = self
                .body(body)
                .send()?;

            check_response(&response)?;

            Ok(response)
        }
    }
}
<commit_msg>Remove strict check for Content-Length header<commit_after>use Request;

use std::io::Read;
use std::error::Error;

/// Request and response transport abstraction.
///
/// The `Transport` trait provides a way to send a `Request` to a server and to receive the
/// corresponding response. A `Transport` implementor is passed to [`Request::call`] in order to use
/// it to perform that request.
///
/// The most commonly used transport is simple HTTP: If the `reqwest` feature is enabled (it is by
/// default), the reqwest `RequestBuilder` will implement this trait and send the XML-RPC
/// [`Request`] via HTTP.
///
/// You can implement this trait for your own types if you want to customize how requests are sent.
/// You can modify HTTP headers or wrap requests in a completely different protocol.
///
/// [`Request::call`]: struct.Request.html#method.call
/// [`Request`]: struct.Request.html
pub trait Transport {
    // FIXME replace with `impl Trait` when stable
    /// The response stream returned by `transmit`.
    type Stream: Read;

    /// Transmits an XML-RPC request and returns the server's response.
    ///
    /// The response is returned as a `Self::Stream` - some type implementing the `Read` trait. The
    /// library will read all of the data and parse it as a response. It must be UTF-8 encoded XML,
    /// otherwise the call will fail.
    ///
    /// # Errors
    ///
    /// If a transport error occurs, it should be returned as a boxed error - the library will then
    /// return an appropriate [`Error`] to the caller.
    ///
    /// [`Error`]: struct.Error.html
    fn transmit(self, request: &Request) -> Result<Self::Stream, Box<Error + Send + Sync>>;
}

// FIXME: Link to `Transport` and `RequestBuilder` using intra-rustdoc links. Relative links break
// everything and abs. links don't work locally.
/// Provides helpers for implementing custom `Transport`s using reqwest.
///
/// This module will be disabled if the `reqwest` feature is not enabled.
///
/// The default [`Transport`] implementation for `RequestBuilder` looks roughly like
/// this:
///
/// ```notrust
/// // serialize request into `body` (a `Vec<u8>`)
///
/// build_headers(builder, body.len());
///
/// // send `body` using `builder` and get response
///
/// check_response(&response)?;
/// ```
///
/// From this, you can build your own custom transports.
///
/// [`Transport`]: ../trait.Transport.html
#[cfg(feature = "reqwest")]
pub mod http {
    extern crate reqwest;

    use {Request, Transport};
    use self::reqwest::{RequestBuilder, mime};
    use self::reqwest::header::{ContentType, ContentLength, UserAgent};

    use std::error::Error;

    /// Appends all HTTP headers required by the XML-RPC specification to the `RequestBuilder`.
    ///
    /// More specifically, the following headers are set:
    ///
    /// ```notrust
    /// User-Agent: Rust xmlrpc
    /// Content-Type: text/xml; charset=utf-8
    /// Content-Length: $body_len
    /// ```
    pub fn build_headers(builder: &mut RequestBuilder, body_len: u64) {
        // Set all required request headers
        // NB: The `Host` header is also required, but reqwest adds it automatically, since
        // HTTP/1.1 requires it.
        builder
            .header(UserAgent::new("Rust xmlrpc"))
            .header(ContentType("text/xml; charset=utf-8".parse().unwrap()))
            .header(ContentLength(body_len));
    }

    /// Checks that a reqwest `Response` has a status code indicating success and verifies certain
    /// headers.
    pub fn check_response(response: &reqwest::Response) -> Result<(), Box<Error + Send + Sync>> {
        // This is essentially an open-coded version of `Response::error_for_status` that does not
        // consume the response.
        if response.status().is_client_error() || response.status().is_server_error() {
            return Err(format!("server response indicates error: {}", response.status()).into());
        }

        // Check response headers
        // "The Content-Type is text/xml. Content-Length must be present and correct."
        if let Some(content) = response.headers().get::<ContentType>() {
            // (we ignore this if the header is missing completely)
            match (content.type_(), content.subtype()) {
                (mime::TEXT, mime::XML) => {},
                (ty, sub) => return Err(
                    format!("expected Content-Type 'text/xml', got '{}/{}'", ty, sub).into()
                ),
            }
        }

        Ok(())
    }

    /// Use a `RequestBuilder` as the transport.
    ///
    /// The request will be sent as specified in the XML-RPC specification: A default `User-Agent`
    /// will be set, along with the correct `Content-Type` and `Content-Length`.
    impl Transport for RequestBuilder {
        type Stream = reqwest::Response;

        fn transmit(mut self, request: &Request) -> Result<Self::Stream, Box<Error + Send + Sync>> {
            // First, build the body XML
            let mut body = Vec::new();
            // This unwrap never panics as we are using `Vec<u8>` as a `Write` implementor,
            // and not doing anything else that could return an `Err` in `write_as_xml()`.
            request.write_as_xml(&mut body).unwrap();

            build_headers(&mut self, body.len() as u64);

            let response = self
                .body(body)
                .send()?;

            check_response(&response)?;

            Ok(response)
        }
    }
}
<|endoftext|>


<commit_before>use std::char;
use adivon::queue::Queue;

const R: usize = 256;

/// 245-Way trie
pub struct Node<V> {
    val: Option<V>,
    next: Vec<Option<Node<V>>>
}

impl<V> Node<V> {
    fn new() -> Node<V> {
        Node {
            val: None,
            next: {
                let mut next = Vec::with_capacity(R);
                for _ in 0 .. R { next.push(None) }
                next
            }
        }
    }

    fn put(mut x: Option<Node<V>>, key: &str, val: V, d: usize) -> Option<Node<V>> {
        if x.is_none() {
            x = Some(Node::new());
        }
        if d == key.bytes().len() {
            x.as_mut().map(|n| n.val = Some(val));
            return x
        }
        let c = key.as_bytes()[d] as usize;
        x.as_mut().map(|n| n.next[c] = Node::put(n.next[c].take(), key, val, d+1));
        x
    }

    fn get<'a>(x: Option<&'a Node<V>>, key: &str, d: usize) -> Option<&'a Node<V>> {
        if x.is_none() {
            None
        } else if d == key.bytes().len() {
            x
        } else {
            let c = key.as_bytes()[d] as usize;
            x.as_ref().map(|n| Node::get(n.next[c].as_ref(), key, d+1)).unwrap()
        }
    }

    fn delete(mut x: Option<Node<V>>, key: &str, d: usize) -> (Option<Node<V>>, Option<V>) {
        let mut deleted = None;
        if x.is_none() {
            return (None, deleted);
        }
        if d == key.bytes().len() {
            if x.as_ref().map_or(false, |n| n.val.is_some()) {
                deleted = x.as_mut().map(|n| n.val.take()).unwrap();
            }
        } else {
            let c = key.as_bytes()[d] as usize;
            x.as_mut().map(|n| {
                // FIXME: https://github.com/rust-lang/rfcs/issues/372
                let (nx, nd) = Node::delete(n.next[c].take(), key, d+1);
                n.next[c] = nx;
                deleted = nd;
            });
        }
        if x.as_ref().map_or(false, |n| n.val.is_some()) {
            return (x, deleted);
        }
        for c in 0 .. R {
            if x.as_ref().map_or(false, |n| n.next[c].is_some()) {
                return (x, deleted);
            }
        }
        return (None, deleted);
    }

    // use '?' as pattern
    fn collect_by_pattern(x: Option<&Node<V>>, mut prefix: String, pattern: &str, results: &mut Queue<String>) {
        if x.is_none() {
            return;
        }
        let d = prefix.bytes().len();
        if d == pattern.bytes().len() {
            if x.map_or(false, |n| n.val.is_some()) {
                results.enqueue(prefix.clone());
            }
            return;
        }
        let c = pattern.as_bytes()[d];
        if c == '?' as u8 {
            for ch in 0 .. R {
                prefix.push(char::from_u32(ch as u32).unwrap());
                Node::collect_by_pattern(x.unwrap().next[ch].as_ref(),
                                         prefix.clone(), pattern, results);
                prefix.pop();
            }
        } else {
            prefix.push(c as char);
            Node::collect_by_pattern(x.unwrap().next[c as usize].as_ref(),
                                     prefix.clone(), pattern, results);
            prefix.pop();
        }
    }

    fn collect(x: Option<&Node<V>>, mut prefix: String, results: &mut Queue<String>) {
        if x.is_none() {
            return;
        }
        if x.unwrap().val.is_some() {
            results.enqueue(prefix.clone());
        }
        for c in 0 .. R {
            prefix.push(char::from_u32(c as u32).unwrap());
            Node::collect(x.unwrap().next[c].as_ref(), prefix.clone(), results);
            prefix.pop();
        }
    }
}

pub struct TrieST<V> {
    root: Option<Node<V>>,
    n: usize
}

impl<V> TrieST<V> {
    pub fn new() -> TrieST<V> {
        TrieST {
            root: None,
            n: 0
        }
    }

    pub fn put(&mut self, key: &str, val: V) {
        self.root = Node::put(self.root.take(), key, val, 0);
        self.n += 1;
    }

    pub fn get(&self, key: &str) -> Option<&V> {
        Node::get(self.root.as_ref(), key, 0).map(|n| n.val.as_ref()).unwrap_or(None)
    }

    pub fn delete(&mut self, key: &str) {
        let (root, deleted) = Node::delete(self.root.take(), key, 0);
        self.root = root;
        if deleted.is_some() {
            self.n -= 1;
        }
    }

    pub fn size(&self) -> usize {
        self.n
    }

    pub fn is_empty(&self) -> bool {
        self.n == 0
    }

    pub fn contains(&self, key: &str) -> bool {
        Node::get(self.root.as_ref(), key, 0).map(|n| n.val.is_some()).unwrap_or(false)
    }

    pub fn keys_with_prefix(&self, prefix: &str) -> Vec<String> {
        let mut results = Queue::new();
        let x = Node::get(self.root.as_ref(), prefix, 0);
        Node::collect(x, prefix.into(), &mut results);
        results.into_iter().collect()
    }

    pub fn keys(&self) -> Vec<String> {
        self.keys_with_prefix("")
    }

    pub fn keys_that_match(&self, pattern: &str) -> Vec<String> {
        let mut results = Queue::new();
        Node::collect_by_pattern(self.root.as_ref(), "".into(), pattern, &mut results);
        results.into_iter().collect()
    }
    // TODO:
    // longest_prefix_of()
}

#[test]
fn test_tries() {
    let mut t = TrieST::new();
    assert_eq!(t.size(), 0);
    t.put("name", "Andelf");
    t.put("tel", "110");
    t.put("addr1", "Shaanxi");
    t.put("addr long", "Beijing Haidian");
    t.put("addr2", "Beijing");

    assert_eq!(t.size(), 5);
    assert_eq!(t.get("addr2"), Some(&"Beijing"));
    assert_eq!(t.get("non-exists-key"), None);
    assert!(t.contains("tel"));
    t.delete("tel");
    assert_eq!(t.size(), 4);
    assert!(!t.contains("tel"));
    assert_eq!(vec!["addr long", "addr1", "addr2", "name"], t.keys());

    t.put("addrs", "Beijing, Tianjin, Xi'an");
    t.put("addr22", "Sanya");
    assert_eq!(t.keys_that_match("addr?").len(), 3);
    assert_eq!(t.keys_that_match("addr??"), vec!["addr22"]);
}

// TST
// pub struct TernarySearchTrie { }
<commit_msg>tries: implement longest_prefix_of() for TrieST<commit_after>use std::char;
use std::usize;
use adivon::queue::Queue;

const R: usize = 256;

/// 245-Way trie
pub struct Node<V> {
    val: Option<V>,
    next: Vec<Option<Node<V>>>
}

impl<V> Node<V> {
    fn new() -> Node<V> {
        Node {
            val: None,
            next: {
                let mut next = Vec::with_capacity(R);
                for _ in 0 .. R { next.push(None) }
                next
            }
        }
    }

    fn put(mut x: Option<Node<V>>, key: &str, val: V, d: usize) -> Option<Node<V>> {
        if x.is_none() {
            x = Some(Node::new());
        }
        if d == key.bytes().len() {
            x.as_mut().map(|n| n.val = Some(val));
            return x
        }
        let c = key.as_bytes()[d] as usize;
        x.as_mut().map(|n| n.next[c] = Node::put(n.next[c].take(), key, val, d+1));
        x
    }

    fn get<'a>(x: Option<&'a Node<V>>, key: &str, d: usize) -> Option<&'a Node<V>> {
        if x.is_none() {
            None
        } else if d == key.bytes().len() {
            x
        } else {
            let c = key.as_bytes()[d] as usize;
            x.as_ref().map(|n| Node::get(n.next[c].as_ref(), key, d+1)).unwrap()
        }
    }

    fn delete(mut x: Option<Node<V>>, key: &str, d: usize) -> (Option<Node<V>>, Option<V>) {
        let mut deleted = None;
        if x.is_none() {
            return (None, deleted);
        }
        if d == key.bytes().len() {
            if x.as_ref().map_or(false, |n| n.val.is_some()) {
                deleted = x.as_mut().map(|n| n.val.take()).unwrap();
            }
        } else {
            let c = key.as_bytes()[d] as usize;
            x.as_mut().map(|n| {
                // FIXME: https://github.com/rust-lang/rfcs/issues/372
                let (nx, nd) = Node::delete(n.next[c].take(), key, d+1);
                n.next[c] = nx;
                deleted = nd;
            });
        }
        if x.as_ref().map_or(false, |n| n.val.is_some()) {
            return (x, deleted);
        }
        for c in 0 .. R {
            if x.as_ref().map_or(false, |n| n.next[c].is_some()) {
                return (x, deleted);
            }
        }
        return (None, deleted);
    }

    // use '?' as pattern
    fn collect_by_pattern(x: Option<&Node<V>>, mut prefix: String, pattern: &str, results: &mut Queue<String>) {
        if x.is_none() {
            return;
        }
        let d = prefix.bytes().len();
        if d == pattern.bytes().len() {
            if x.map_or(false, |n| n.val.is_some()) {
                results.enqueue(prefix.clone());
            }
            return;
        }
        let c = pattern.as_bytes()[d];
        if c == '?' as u8 {
            for ch in 0 .. R {
                prefix.push(char::from_u32(ch as u32).unwrap());
                Node::collect_by_pattern(x.unwrap().next[ch].as_ref(),
                                         prefix.clone(), pattern, results);
                prefix.pop();
            }
        } else {
            prefix.push(c as char);
            Node::collect_by_pattern(x.unwrap().next[c as usize].as_ref(),
                                     prefix.clone(), pattern, results);
            prefix.pop();
        }
    }

    fn collect(x: Option<&Node<V>>, mut prefix: String, results: &mut Queue<String>) {
        if x.is_none() {
            return;
        }
        if x.unwrap().val.is_some() {
            results.enqueue(prefix.clone());
        }
        for c in 0 .. R {
            prefix.push(char::from_u32(c as u32).unwrap());
            Node::collect(x.unwrap().next[c].as_ref(), prefix.clone(), results);
            prefix.pop();
        }
    }

    fn longest_prefix_of(x: Option<&Node<V>>, query: &str, d: usize, mut length: usize) -> usize {
        if x.is_none() {
            return length;
        }
        if x.unwrap().val.is_some() {
            length = d;
        }
        if d == query.len() {
            return length;
        }
        let c = query.as_bytes()[d];
        Node::longest_prefix_of(x.as_ref().unwrap().next[c as usize].as_ref(), query, d+1, length)
    }
}

pub struct TrieST<V> {
    root: Option<Node<V>>,
    n: usize
}

impl<V> TrieST<V> {
    pub fn new() -> TrieST<V> {
        TrieST {
            root: None,
            n: 0
        }
    }

    pub fn put(&mut self, key: &str, val: V) {
        self.root = Node::put(self.root.take(), key, val, 0);
        self.n += 1;
    }

    pub fn get(&self, key: &str) -> Option<&V> {
        Node::get(self.root.as_ref(), key, 0).map(|n| n.val.as_ref()).unwrap_or(None)
    }

    pub fn delete(&mut self, key: &str) {
        let (root, deleted) = Node::delete(self.root.take(), key, 0);
        self.root = root;
        if deleted.is_some() {
            self.n -= 1;
        }
    }

    pub fn size(&self) -> usize {
        self.n
    }

    pub fn is_empty(&self) -> bool {
        self.n == 0
    }

    pub fn contains(&self, key: &str) -> bool {
        Node::get(self.root.as_ref(), key, 0).map(|n| n.val.is_some()).unwrap_or(false)
    }

    pub fn keys_with_prefix(&self, prefix: &str) -> Vec<String> {
        let mut results = Queue::new();
        let x = Node::get(self.root.as_ref(), prefix, 0);
        Node::collect(x, prefix.into(), &mut results);
        results.into_iter().collect()
    }

    pub fn keys(&self) -> Vec<String> {
        self.keys_with_prefix("")
    }

    pub fn keys_that_match(&self, pattern: &str) -> Vec<String> {
        let mut results = Queue::new();
        Node::collect_by_pattern(self.root.as_ref(), "".into(), pattern, &mut results);
        results.into_iter().collect()
    }

    pub fn longest_prefix_of<'a>(&self, query: &'a str) -> Option<&'a str> {
        let length = Node::longest_prefix_of(self.root.as_ref(), query, 0, usize::MAX);
        if length == usize::MAX {
            None
        } else {
            Some(&query[..length])
        }

    }
}

#[test]
fn test_tries() {
    let mut t = TrieST::new();
    assert_eq!(t.size(), 0);
    t.put("name", "Andelf");
    t.put("tel", "110");
    t.put("addr1", "Shaanxi");
    t.put("addr long", "Beijing Haidian");
    t.put("addr2", "Beijing");
    assert_eq!(t.size(), 5);
    assert_eq!(t.get("addr2"), Some(&"Beijing"));
    assert_eq!(t.get("non-exists-key"), None);
    assert!(t.contains("tel"));
    t.delete("tel");
    assert_eq!(t.size(), 4);
    assert!(!t.contains("tel"));
    assert_eq!(vec!["addr long", "addr1", "addr2", "name"], t.keys());
    t.put("addrs", "Beijing, Tianjin, Xi'an");
    t.put("addr22", "Sanya");
    assert_eq!(t.keys_that_match("addr?").len(), 3);
    assert_eq!(t.keys_that_match("addr??"), vec!["addr22"]);
    assert_eq!(t.longest_prefix_of("addr22222"), Some("addr22"));
}

// TST
// pub struct TernarySearchTrie { }
<|endoftext|>