<commit_before>mod interval;
mod adjacent_bound;

pub use adjacent_bound::AdjacentBound;

use interval::Interval;
use std::collections::VecDeque;
use std::iter::FromIterator;

#[derive(Debug)]
struct DietNode<T> {
    interval: Interval<T>,
    left: Option<Box<DietNode<T>>>,
    right: Option<Box<DietNode<T>>>,
}

#[derive(Debug)]
pub struct Diet<T> {
    root: Option<Box<DietNode<T>>>,
}

#[derive(Debug)]
struct DietNodeIterator<T> {
    pending: VecDeque<T>
}

trait DietNodeRelationshipOps {
    type Bound : AdjacentBound;

    fn max_parent_mut(&mut self) -> &mut Self;

    fn min_parent_mut(&mut self) -> &mut Self;

    fn traverse_to_node_containing(&self, value: &Self::Bound) -> &Self;

    fn traverse_to_node_containing_mut(&mut self, value: &Self::Bound) -> &mut Self;

    fn insert(&mut self, value: Self::Bound) -> bool;

    fn remove(&mut self, value: &Self::Bound) -> bool;
}

impl<T : AdjacentBound> DietNodeRelationshipOps for Option<Box<DietNode<T>>> {
    type Bound = T;

    fn max_parent_mut(&mut self) -> &mut Self {
        let mut parent = self;

        loop {
            let move_next = parent.as_ref().map_or(false, |c|c.right.is_some());
            if move_next {
                parent = &mut {parent}.as_mut().unwrap().right
            } else {
                return parent;
            }
        }
    }

    fn min_parent_mut(&mut self) ->  &mut Self {
        let mut parent = self;

        loop {
            let move_next = parent.as_ref().map_or(false, |c|c.left.is_some());
            if move_next {
                parent = &mut {parent}.as_mut().unwrap().left
            } else {
                return parent;
            }
        }
    }

    fn traverse_to_node_containing(&self, value: &Self::Bound) -> &Self {
        let mut current = self;

        while let Some(ref node) = *current {
            if node.interval.contains(value) {
                break;
            }

            if value < node.interval.inclusive_start() {
                current = &node.left
            } else {
                debug_assert!(value >= node.interval.exclusive_end());
                current = &node.right
            }
        }

        current
    }

    fn traverse_to_node_containing_mut(&mut self, value: &Self::Bound) -> &mut Self {
        let mut current = self;

        loop {

            match current.as_ref().map(|n| n.interval.contains(value)) {
                None | Some(true) => {
                    // If there is no current or current contains the value then return it
                    return current;
                }
                _ => { }
            }

            let node = {current}.as_mut().unwrap();
            if value < node.interval.inclusive_start() {
                current = &mut node.left;
            } else {
                debug_assert!(value >= node.interval.exclusive_end());

                current = &mut node.right;
            }
        }
    }

    fn insert(&mut self, value: Self::Bound) -> bool {
        let mut current = self;
        loop {
            let local_current = current;
            if let Some(ref mut node) = *local_current {
                if value.comes_before(node.interval.inclusive_start()) {

                    node.interval.set_inclusive_start(value);
                    node.join_left();

                    return true;

                } else if &value == node.interval.exclusive_end() {

                    node.interval.set_exclusive_end(value.increment());
                    node.join_right();

                    return true;

                } if &value < node.interval.inclusive_start() {
                    current = &mut node.left;
                } else if &value > node.interval.exclusive_end() {
                    current = &mut node.right;
                }  else {
                    debug_assert!(node.interval.contains(&value), "the value should already be contained within the interval");
                    return false;
                }
            } else {
                let new_exclusive_end = value.increment();

                *local_current = Some(Box::new(DietNode {
                    interval: Interval::from(value..new_exclusive_end),
                    left: None,
                    right: None
                }));

                return true;
            }
        }
    }

    fn remove(&mut self, value: &Self::Bound) -> bool {
        let containing_node = self.traverse_to_node_containing_mut(value);

        let mut delete_node = false;

        let removed = if let Some(ref mut node) = *containing_node {
            if value == node.interval.inclusive_start() {
                if value.comes_before(node.interval.exclusive_end()) {
                    // The entire node needs to be removed but any children should be moved up
                    match (node.left.take(), node.right.take()) {
                        (None, None) => {
                            delete_node = true
                        }
                        (Some(child), None) | (None, Some(child)) => {
                            *node = child;
                        }
                        (mut left @ Some(_), right @ Some(_)) => {
                            let max = *(left.max_parent_mut().take().unwrap());

                            node.interval = max.interval;
                            node.left = left;
                            node.right = right;
                        }
                    }
                } else {
                    node.interval.inclusive_start_mut().increment_ref();
                }
            } else if value.comes_before(node.interval.exclusive_end()) {
                node.interval.exclusive_end_mut().decrement_ref();
            } else {
                node.split_on_value(value);
            };
            true
        } else {
            false
        };

        if delete_node {
            *containing_node = None;
        }

        removed
    }
}

impl<'a, T> Iterator for DietNodeIterator<&'a DietNode<T>> {
    type Item = &'a DietNode<T>;

    fn next(&mut self) -> Option<&'a DietNode<T>> {
        self.pending.pop_front()
            .map(|current| {
                let children = [&current.left, &current.right];
                for child in children.into_iter().flat_map(|x| x.as_ref()) {
                    self.pending.push_back(child);

                }
                current
            })
    }
}

impl<T> DietNode<T> {
    pub fn nodes(&self) -> DietNodeIterator<&DietNode<T>> {
        let mut pending = VecDeque::new();
        pending.push_back(self);

        DietNodeIterator {
            pending: pending
        }
    }

    pub fn len(&self) -> usize {
        self.nodes().count()
    }
}

impl<T: AdjacentBound> DietNode<T> {

    pub fn split_on_value(&mut self, value: &T) {
        debug_assert!(self.interval.contains(value), "the value should be contained within the interval");

        let old_exclusive_end = self.interval.set_exclusive_end(value.to_owned());

        let new_right_interval = Interval::from(value.increment()..old_exclusive_end);

        let right = self.right.take();
        self.right = Some(Box::new(DietNode {
            interval: new_right_interval,
            left: None,
            right: right
        }));
    }

    fn join_left(&mut self) {
        let max_parent_mut = self.left.max_parent_mut();

        let interval = &mut self.interval;

        let should_merge = max_parent_mut.as_ref().map_or(false, |c| c.interval.exclusive_end() == interval.inclusive_start());

        if should_merge {
            let max = *max_parent_mut.take().unwrap();
            *max_parent_mut = max.left;
            interval.set_inclusive_start(max.interval.take_inclusive_start());
        }
    }

    fn join_right(&mut self) {
        let min_parent_mut = self.right.min_parent_mut();

        let interval = &mut self.interval;

        let should_merge = min_parent_mut.as_ref().map_or(false, |c| c.interval.inclusive_start() == interval.exclusive_end());

        if should_merge {
            let min = *min_parent_mut.take().unwrap();
            *min_parent_mut = min.right;
            interval.set_exclusive_end(min.interval.take_exclusive_end());
        }
    }
}

impl<T> Diet<T> {
    pub fn len(&self) -> usize {
        self.root.as_ref().map_or(0, |n| n.len())
    }
}

impl<T: AdjacentBound> Diet<T> {

    pub fn insert(&mut self, value: T) -> bool {
        self.root.insert(value)
    }

    pub fn remove(&mut self, value: &T) -> bool {
        self.root.remove(value)
    }

    pub fn contains(&self, value: &T) -> bool {
        self.root.traverse_to_node_containing(value).is_some()
    }
}

// TODO LH Implement iterators which traverse the intervals in the tree

impl<T> Default for Diet<T>{
    fn default() -> Self {
        Self {
            root: None
        }
    }
}

impl<A : AdjacentBound> FromIterator<A> for Diet<A> {
    fn from_iter<T>(iter: T) -> Self where T: IntoIterator<Item = A> {
        let mut diet = Diet::default();

        for value in iter {
            diet.insert(value);
        }

        diet
    }
}

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

    #[test]
    fn contains_returns_false_for_default(){
        let diet = Diet::<u32>::default();

        assert!(!diet.contains(&5));
    }

    #[test]
    fn contains_returns_true_for_existing_value(){
        let diet = Diet::from_iter([3, 1, 5].iter().cloned());

        assert!(diet.contains(&5));
    }

    #[test]
    fn len_returns_zero_for_default() {
        let diet = Diet::<u32>::default();

        assert_eq!(diet.len(), 0);
    }

    #[test]
    fn insert_returns_true_for_new_value() {
        let mut diet = Diet::default();

        assert!(diet.insert(1));
    }

    #[test]
    fn insert_returns_false_for_existing_value() {
        let mut diet = Diet::default();

        diet.insert(1);
        assert!(!diet.insert(1));
    }

    #[test]
    fn insert_extends_existing_ranges() {
        let mut diet = Diet::from_iter([1, 5].iter().cloned());

        diet.insert(2);
        diet.insert(4);

        assert_eq!(diet.len(), 2);
    }

    #[test]
    fn insert_combines_ranges() {
        let mut diet = Diet::from_iter([3, 1, 5, 8].iter().cloned());

        diet.insert(2);
        diet.insert(4);
        diet.insert(6);
        diet.insert(7);

        assert_eq!(diet.len(), 1);
    }

    #[test]
    fn remove_returns_false_for_default(){
        let mut diet = Diet::<u32>::default();

        assert!(!diet.remove(&5));
    }

    #[test]
    fn remove_returns_false_for_non_existant_value(){
        let mut diet = Diet::from_iter([1, 2, 3, 6].iter().cloned());

        assert!(!diet.remove(&10));
    }

    #[test]
    fn remove_of_adjacent_returns_false() {
        let mut diet = Diet::from_iter([4, 5, 6].iter().cloned());

        assert!(!diet.remove(&3));
    }

    #[test]
    fn remove_of_lower_bounds() {
        let mut diet = Diet::from_iter([50, 51, 52, 1, 2, 20, 21].iter().cloned());

        assert!(diet.remove(&50));
        assert!(!diet.contains(&50));

        assert!(diet.remove(&51));
        assert!(!diet.contains(&51));

        assert!(diet.remove(&1));
        assert!(!diet.contains(&1));

        assert!(diet.remove(&20));
        assert!(!diet.contains(&20));

        assert_eq!(diet.len(), 3);
    }

    #[test]
    fn remove_of_upper_bounds() {
        let mut diet = Diet::from_iter([50, 51, 52, 1, 2, 20, 21].iter().cloned());

        assert!(diet.remove(&52));
        assert!(!diet.contains(&52));

        assert!(diet.remove(&51));
        assert!(!diet.contains(&51));

        assert!(diet.remove(&2));
        assert!(!diet.contains(&2));

        assert!(diet.remove(&21));
        assert!(!diet.contains(&21));

        assert_eq!(diet.len(), 3);
    }

    #[test]
    fn remove_root_node() {
        let mut diet = Diet::from_iter([50, 51, 1, 2, 10, 20, 21].iter().cloned());

        assert!(diet.remove(&50));
        assert!(!diet.contains(&50));
        assert!(diet.remove(&51));
        assert!(!diet.contains(&51));

        assert_eq!(diet.len(), 3);

        assert!(diet.contains(&1));
        assert!(diet.contains(&2));
        assert!(diet.contains(&10));
        assert!(diet.contains(&20));
        assert!(diet.contains(&21));
    }

    #[test]
    fn remove_within_interval() {
        let mut diet = Diet::from_iter([1, 2, 3].iter().cloned());

        assert!(diet.remove(&2));
        assert!(!diet.contains(&2));

        assert!(diet.contains(&1));
        assert!(diet.contains(&3));

        assert_eq!(diet.len(), 2);
    }

}
<commit_msg>Implemented an in-order iterator<commit_after>mod interval;
mod adjacent_bound;

pub use adjacent_bound::AdjacentBound;

use interval::Interval;
use std::collections::VecDeque;
use std::iter::FromIterator;

#[derive(Debug)]
struct DietNode<T> {
    interval: Interval<T>,
    left: Option<Box<DietNode<T>>>,
    right: Option<Box<DietNode<T>>>,
}

#[derive(Debug)]
pub struct Diet<T> {
    root: Option<Box<DietNode<T>>>,
}

#[derive(Debug)]
struct DietNodeBreadthIterator<T> {
    pending: VecDeque<T>
}

#[derive(Debug)]
struct DietNodeOrderedIterator<T> {
    current: Option<T>,
    stack: Vec<T>,
}

trait DietNodeRelationshipOps {
    type Bound : AdjacentBound;

    fn max_parent_mut(&mut self) -> &mut Self;

    fn min_parent_mut(&mut self) -> &mut Self;

    fn traverse_to_node_containing(&self, value: &Self::Bound) -> &Self;

    fn traverse_to_node_containing_mut(&mut self, value: &Self::Bound) -> &mut Self;

    fn insert(&mut self, value: Self::Bound) -> bool;

    fn remove(&mut self, value: &Self::Bound) -> bool;
}

impl<T : AdjacentBound> DietNodeRelationshipOps for Option<Box<DietNode<T>>> {
    type Bound = T;

    fn max_parent_mut(&mut self) -> &mut Self {
        let mut parent = self;

        loop {
            let move_next = parent.as_ref().map_or(false, |c|c.right.is_some());
            if move_next {
                parent = &mut {parent}.as_mut().unwrap().right
            } else {
                return parent;
            }
        }
    }

    fn min_parent_mut(&mut self) ->  &mut Self {
        let mut parent = self;

        loop {
            let move_next = parent.as_ref().map_or(false, |c|c.left.is_some());
            if move_next {
                parent = &mut {parent}.as_mut().unwrap().left
            } else {
                return parent;
            }
        }
    }

    fn traverse_to_node_containing(&self, value: &Self::Bound) -> &Self {
        let mut current = self;

        while let Some(ref node) = *current {
            if node.interval.contains(value) {
                break;
            }

            if value < node.interval.inclusive_start() {
                current = &node.left
            } else {
                debug_assert!(value >= node.interval.exclusive_end());
                current = &node.right
            }
        }

        current
    }

    fn traverse_to_node_containing_mut(&mut self, value: &Self::Bound) -> &mut Self {
        let mut current = self;

        loop {

            match current.as_ref().map(|n| n.interval.contains(value)) {
                None | Some(true) => {
                    // If there is no current or current contains the value then return it
                    return current;
                }
                _ => { }
            }

            let node = {current}.as_mut().unwrap();
            if value < node.interval.inclusive_start() {
                current = &mut node.left;
            } else {
                debug_assert!(value >= node.interval.exclusive_end());

                current = &mut node.right;
            }
        }
    }

    fn insert(&mut self, value: Self::Bound) -> bool {
        let mut current = self;
        loop {
            let local_current = current;
            if let Some(ref mut node) = *local_current {
                if value.comes_before(node.interval.inclusive_start()) {

                    node.interval.set_inclusive_start(value);
                    node.join_left();

                    return true;

                } else if &value == node.interval.exclusive_end() {

                    node.interval.set_exclusive_end(value.increment());
                    node.join_right();

                    return true;

                } if &value < node.interval.inclusive_start() {
                    current = &mut node.left;
                } else if &value > node.interval.exclusive_end() {
                    current = &mut node.right;
                }  else {
                    debug_assert!(node.interval.contains(&value), "the value should already be contained within the interval");
                    return false;
                }
            } else {
                let new_exclusive_end = value.increment();

                *local_current = Some(Box::new(DietNode {
                    interval: Interval::from(value..new_exclusive_end),
                    left: None,
                    right: None
                }));

                return true;
            }
        }
    }

    fn remove(&mut self, value: &Self::Bound) -> bool {
        let containing_node = self.traverse_to_node_containing_mut(value);

        let mut delete_node = false;

        let removed = if let Some(ref mut node) = *containing_node {
            if value == node.interval.inclusive_start() {
                if value.comes_before(node.interval.exclusive_end()) {
                    // The entire node needs to be removed but any children should be moved up
                    match (node.left.take(), node.right.take()) {
                        (None, None) => {
                            delete_node = true
                        }
                        (Some(child), None) | (None, Some(child)) => {
                            *node = child;
                        }
                        (mut left @ Some(_), right @ Some(_)) => {
                            let max = *(left.max_parent_mut().take().unwrap());

                            node.interval = max.interval;
                            node.left = left;
                            node.right = right;
                        }
                    }
                } else {
                    node.interval.inclusive_start_mut().increment_ref();
                }
            } else if value.comes_before(node.interval.exclusive_end()) {
                node.interval.exclusive_end_mut().decrement_ref();
            } else {
                node.split_on_value(value);
            };
            true
        } else {
            false
        };

        if delete_node {
            *containing_node = None;
        }

        removed
    }
}

impl<'a, T> Iterator for DietNodeBreadthIterator<&'a DietNode<T>> {
    type Item = &'a DietNode<T>;

    fn next(&mut self) -> Option<&'a DietNode<T>> {
        self.pending.pop_front()
            .map(|current| {
                let children = [&current.left, &current.right];
                for child in children.into_iter().flat_map(|x| x.as_ref()) {
                    self.pending.push_back(child);

                }
                current
            })
    }
}

impl<'a, T> Iterator for DietNodeOrderedIterator<&'a DietNode<T>> {
    type Item = &'a DietNode<T>;

    fn next(&mut self) -> Option<&'a DietNode<T>> {

        let mut current = self.current.take();

        // Move to the left-most node
        while let Some(node) = current {
            // As we pass each node push it to the stack to be returned and right-traversed later
            self.stack.push(node);

            current = node.left.as_ref().map(Box::as_ref);
        }

        let result = self.stack.pop();

        // Attempt to move the iterator to the right node
        self.current = result.and_then(|n| n.right.as_ref()).map(Box::as_ref);

        result
    }
}

impl<T> DietNode<T> {
    pub fn nodes(&self) -> DietNodeBreadthIterator<&DietNode<T>> {
        let mut pending = VecDeque::new();
        pending.push_back(self);

        DietNodeBreadthIterator {
            pending: pending
        }
    }

    pub fn ordered_nodes(&self) -> DietNodeOrderedIterator<&DietNode<T>> {
        DietNodeOrderedIterator {
            current: Some(self),
            stack: Default::default()
        }
    }

    pub fn len(&self) -> usize {
        self.nodes().count()
    }
}

impl<T: AdjacentBound> DietNode<T> {

    pub fn split_on_value(&mut self, value: &T) {
        debug_assert!(self.interval.contains(value), "the value should be contained within the interval");

        let old_exclusive_end = self.interval.set_exclusive_end(value.to_owned());

        let new_right_interval = Interval::from(value.increment()..old_exclusive_end);

        let right = self.right.take();
        self.right = Some(Box::new(DietNode {
            interval: new_right_interval,
            left: None,
            right: right
        }));
    }

    fn join_left(&mut self) {
        let max_parent_mut = self.left.max_parent_mut();

        let interval = &mut self.interval;

        let should_merge = max_parent_mut.as_ref().map_or(false, |c| c.interval.exclusive_end() == interval.inclusive_start());

        if should_merge {
            let max = *max_parent_mut.take().unwrap();
            *max_parent_mut = max.left;
            interval.set_inclusive_start(max.interval.take_inclusive_start());
        }
    }

    fn join_right(&mut self) {
        let min_parent_mut = self.right.min_parent_mut();

        let interval = &mut self.interval;

        let should_merge = min_parent_mut.as_ref().map_or(false, |c| c.interval.inclusive_start() == interval.exclusive_end());

        if should_merge {
            let min = *min_parent_mut.take().unwrap();
            *min_parent_mut = min.right;
            interval.set_exclusive_end(min.interval.take_exclusive_end());
        }
    }
}

impl<T> Diet<T> {
    pub fn len(&self) -> usize {
        self.root.as_ref().map_or(0, |n| n.len())
    }
}

impl<T: AdjacentBound> Diet<T> {

    pub fn insert(&mut self, value: T) -> bool {
        self.root.insert(value)
    }

    pub fn remove(&mut self, value: &T) -> bool {
        self.root.remove(value)
    }

    pub fn contains(&self, value: &T) -> bool {
        self.root.traverse_to_node_containing(value).is_some()
    }
}

// TODO LH Implement iterators which traverse the intervals in the tree

impl<T> Default for Diet<T>{
    fn default() -> Self {
        Self {
            root: None
        }
    }
}

impl<A : AdjacentBound> FromIterator<A> for Diet<A> {
    fn from_iter<T>(iter: T) -> Self where T: IntoIterator<Item = A> {
        let mut diet = Diet::default();

        for value in iter {
            diet.insert(value);
        }

        diet
    }
}

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

    #[test]
    fn contains_returns_false_for_default(){
        let diet = Diet::<u32>::default();

        assert!(!diet.contains(&5));
    }

    #[test]
    fn contains_returns_true_for_existing_value(){
        let diet = Diet::from_iter([3, 1, 5].iter().cloned());

        assert!(diet.contains(&5));
    }

    #[test]
    fn len_returns_zero_for_default() {
        let diet = Diet::<u32>::default();

        assert_eq!(diet.len(), 0);
    }

    #[test]
    fn insert_returns_true_for_new_value() {
        let mut diet = Diet::default();

        assert!(diet.insert(1));
    }

    #[test]
    fn insert_returns_false_for_existing_value() {
        let mut diet = Diet::default();

        diet.insert(1);
        assert!(!diet.insert(1));
    }

    #[test]
    fn insert_extends_existing_ranges() {
        let mut diet = Diet::from_iter([1, 5].iter().cloned());

        diet.insert(2);
        diet.insert(4);

        assert_eq!(diet.len(), 2);
    }

    #[test]
    fn insert_combines_ranges() {
        let mut diet = Diet::from_iter([3, 1, 5, 8].iter().cloned());

        diet.insert(2);
        diet.insert(4);
        diet.insert(6);
        diet.insert(7);

        assert_eq!(diet.len(), 1);
    }

    #[test]
    fn remove_returns_false_for_default(){
        let mut diet = Diet::<u32>::default();

        assert!(!diet.remove(&5));
    }

    #[test]
    fn remove_returns_false_for_non_existant_value(){
        let mut diet = Diet::from_iter([1, 2, 3, 6].iter().cloned());

        assert!(!diet.remove(&10));
    }

    #[test]
    fn remove_of_adjacent_returns_false() {
        let mut diet = Diet::from_iter([4, 5, 6].iter().cloned());

        assert!(!diet.remove(&3));
    }

    #[test]
    fn remove_of_lower_bounds() {
        let mut diet = Diet::from_iter([50, 51, 52, 1, 2, 20, 21].iter().cloned());

        assert!(diet.remove(&50));
        assert!(!diet.contains(&50));

        assert!(diet.remove(&51));
        assert!(!diet.contains(&51));

        assert!(diet.remove(&1));
        assert!(!diet.contains(&1));

        assert!(diet.remove(&20));
        assert!(!diet.contains(&20));

        assert_eq!(diet.len(), 3);
    }

    #[test]
    fn remove_of_upper_bounds() {
        let mut diet = Diet::from_iter([50, 51, 52, 1, 2, 20, 21].iter().cloned());

        assert!(diet.remove(&52));
        assert!(!diet.contains(&52));

        assert!(diet.remove(&51));
        assert!(!diet.contains(&51));

        assert!(diet.remove(&2));
        assert!(!diet.contains(&2));

        assert!(diet.remove(&21));
        assert!(!diet.contains(&21));

        assert_eq!(diet.len(), 3);
    }

    #[test]
    fn remove_root_node() {
        let mut diet = Diet::from_iter([50, 51, 1, 2, 10, 20, 21].iter().cloned());

        assert!(diet.remove(&50));
        assert!(!diet.contains(&50));
        assert!(diet.remove(&51));
        assert!(!diet.contains(&51));

        assert_eq!(diet.len(), 3);

        assert!(diet.contains(&1));
        assert!(diet.contains(&2));
        assert!(diet.contains(&10));
        assert!(diet.contains(&20));
        assert!(diet.contains(&21));
    }

    #[test]
    fn remove_within_interval() {
        let mut diet = Diet::from_iter([1, 2, 3].iter().cloned());

        assert!(diet.remove(&2));
        assert!(!diet.contains(&2));

        assert!(diet.contains(&1));
        assert!(diet.contains(&3));

        assert_eq!(diet.len(), 2);
    }

}
<|endoftext|>


<commit_before>#![feature(slicing_syntax)]

extern crate lzf;
use std::str;
use lzf::decompress;
use std::io::MemReader;
use std::io;

mod version {
    pub const SUPPORTED_MINIMUM : u32 = 1;
    pub const SUPPORTED_MAXIMUM : u32 = 6;
}

mod constants {
    pub const RDB_6BITLEN : u8 = 0;
    pub const RDB_14BITLEN : u8 = 1;
    pub const RDB_ENCVAL : u8 = 3;
    pub const RDB_MAGIC : &'static str = "REDIS";
}

mod op_codes {
    pub const EXPIRETIME_MS : u8 = 252;
    pub const EXPIRETIME : u8 = 253;
    pub const SELECTDB   : u8 = 254;
    pub const EOF : u8 = 255;
}

mod types {
    pub const STRING : u8 = 0;
    pub const LIST : u8 = 1;
    pub const SET : u8 = 2;
    pub const ZSET : u8 = 3;
    pub const HASH : u8 = 4;
    pub const HASH_ZIPMAP : u8 = 9;
    pub const LIST_ZIPLIST : u8 = 10;
    pub const SET_INTSET : u8 = 11;
    pub const ZSET_ZIPLIST : u8 = 12;
    pub const HASH_ZIPLIST : u8 = 13;
}

mod encoding {
    pub const INT8 : u32 = 0;
    pub const INT16 : u32 = 1;
    pub const INT32 : u32 = 2;
    pub const LZF : u32 = 3;
}

#[derive(Show)]
pub enum DataType {
    String(Vec<u8>),
    Number(i64),
    ListOfTypes(Vec<DataType>),
    HashOfTypes(Vec<DataType>),
    SortedSetOfTypes(Vec<DataType>),
    Intset(Vec<i64>),
    List(Vec<Vec<u8>>),
    Set(Vec<Vec<u8>>),
    SortedSet(Vec<(f64,Vec<u8>)>),
    Hash(Vec<Vec<u8>>),
    Unknown
}

#[derive(Show,PartialEq,Copy)]
pub enum LengthEncoded {
    LE(u32, bool)
}

pub struct RdbParser<'a, T: 'a + Reader> {
    input: &'a mut T
}

impl<'a, T: Reader> RdbParser<'a, T> {
    pub fn new(input: &mut T) -> RdbParser<T> {
        RdbParser{input: input}
    }

    pub fn parse(&mut self) {
        assert!(self.verify_magic());
        assert!(self.verify_version());

        let mut out = io::stdout();
        loop {
            let next_op = self.input.read_byte().unwrap();

            match next_op {
                op_codes::SELECTDB => {
                    let db = self.input.read_byte().unwrap();
                    println!("SELECTDB: {}", db);
                },
                op_codes::EOF => {
                    println!("EOF");
                    break ;
                },
                op_codes::EXPIRETIME_MS => {
                    let expiretime_ms = self.input.read_le_u64().unwrap();
                    println!("EXPIRETIME_MS: {}", expiretime_ms);
                },
                op_codes::EXPIRETIME => {
                    let expiretime = self.input.read_be_u32().unwrap();
                    println!("EXPIRETIME: {}", expiretime);
                }
                _ => {
                    let key = read_blob(self.input);
                    let _ = out.write(key[]);
                    let _ = out.write_str(": ");
                    let _ = out.flush();

                    match read_type(next_op, self.input) {
                        DataType::String(t) => {
                            let _ = out.write(t[]);
                            let _ = out.write_str("\n");
                        },
                        DataType::Number(t) => { println!("{}", t) },
                        DataType::ListOfTypes(t) => { println!("{}", t) },
                        DataType::Intset(t) => { println!("{}", t) },
                        DataType::Hash(t) => {
                            for val in t.iter() {
                                let _ = out.write(val[]);
                                let _ = out.write_str(", ");
                            }
                            let _ = out.write_str("\n");
                        },
                        DataType::HashOfTypes(t) => { println!("{}", t) },
                        _ => {}
                    }
                }
            }

        }

        return;

    }

    pub fn verify_magic(&mut self) -> bool {
        let magic = self.input.read_exact(5).unwrap();

        // Meeeeeh.
        magic[0] == constants::RDB_MAGIC.as_bytes()[0] &&
            magic[1] == constants::RDB_MAGIC.as_bytes()[1] &&
            magic[2] == constants::RDB_MAGIC.as_bytes()[2] &&
            magic[3] == constants::RDB_MAGIC.as_bytes()[3] &&
            magic[4] == constants::RDB_MAGIC.as_bytes()[4]
    }

    pub fn verify_version(&mut self) -> bool {
        let version = self.input.read_exact(4).unwrap();

        let version = (version[0]-48) as u32 * 1000 +
            (version[1]-48) as u32 * 100 +
            (version[2]-48) as u32 * 10 +
            (version[3]-48) as u32;

        version >= version::SUPPORTED_MINIMUM &&
            version <= version::SUPPORTED_MAXIMUM
    }
}

fn read_linked_list<T: Reader>(input: &mut T) -> Vec<Vec<u8>> {
    let mut len = read_length(input);
    let mut list = vec![];

    while len > 0 {
        let blob = read_blob(input);
        list.push(blob);
        len -= 1;
    }

    list
}

fn read_sorted_set<T: Reader>(input: &mut T) -> Vec<(f64,Vec<u8>)> {
    let mut set = vec![];
    let mut set_items = read_length(input);

    while set_items > 0 {
        let val = read_blob(input);
        let score_length = input.read_byte().unwrap();
        let score = input.read_exact(score_length as uint).unwrap();
        let score = unsafe{str::from_utf8_unchecked(score[])}.
            parse::<f64>().unwrap();

        set.push((score, val));

        set_items -= 1;
    }

    set
}

fn read_hash<T: Reader>(input: &mut T) -> Vec<Vec<u8>> {
    let mut hash = vec![];
    let mut hash_items = read_length(input);
    hash_items = 2*hash_items;

    while hash_items > 0 {
        let val = read_blob(input);
        hash.push(val);

        hash_items -= 1;
    }

    hash
}

fn read_list_ziplist<T: Reader>(input: &mut T) -> Vec<DataType> {
    let mut list = vec![];

    let ziplist = read_blob(input);

    let mut reader = MemReader::new(ziplist);

    let _zlbytes = reader.read_le_u32().unwrap();
    let _zltail = reader.read_le_u32().unwrap();
    let zllen = reader.read_le_u16().unwrap();

    for _ in range(0, zllen) {
        // 1. 1 or 5 bytes length of previous entry
        match reader.read_byte().unwrap() {
            254 => {
                let _ = reader.read_exact(4).unwrap();
            },
            _ => {}
        }

        let mut length : u64;
        let mut number_value : i64;

        // 2. Read flag or number value
        let flag = reader.read_byte().unwrap();

        match (flag & 0xC0) >> 6 {
            0 => { length = (flag & 0x3F) as u64 },
            1 => {
                let next_byte = reader.read_byte().unwrap();
                length = (((flag & 0x3F) as u64) << 8) | next_byte as u64;
            },
            2 => {
                length = reader.read_be_u32().unwrap() as u64;
            },
            _ => {
                match (flag & 0xF0) >> 4 {
                    0xC => {
                        number_value = reader.read_le_i16().unwrap() as i64 },
                    0xD => {
                        number_value = reader.read_le_i32().unwrap() as i64 },
                    0xE => {
                        number_value = reader.read_le_i64().unwrap() as i64 },
                    0xF => {
                        match flag & 0xF {
                            0 => {
                                let bytes = reader.read_exact(3).unwrap();
                                number_value = ((bytes[0] as i64) << 16) ^
                                    ((bytes[1] as i64) << 8) ^
                                    (bytes[2] as i64);
                            },
                            0xE => {
                                number_value = reader.read_byte().unwrap() as i64 },
                            _ => { number_value = (flag & 0xF) as i64 - 1; }
                        }
                    },
                    _ => {
                        println!("Flag not handled: {}", flag);
                        continue;
                    }

                }

                list.push(DataType::Number(number_value));
                continue;
            }
        }

        // 3. Read value
        let rawval = reader.read_exact(length as uint).unwrap();
        list.push(DataType::String(rawval));
    }
    assert!(reader.read_byte().unwrap() == 0xFF);

    list
}

fn read_hash_zipmap<T: Reader>(input: &mut T) -> Vec<Vec<u8>> {
    let zipmap = read_blob(input);

    let mut reader = MemReader::new(zipmap);

    let zmlen = reader.read_byte().unwrap();

    let mut length;
    let mut hash;
    if zmlen <= 254 {
        length = zmlen as uint;
        hash = Vec::with_capacity(length);
    } else {
        length = -1;
        hash = Vec::with_capacity(255);
    }

    loop {
        let next_byte = reader.read_byte().unwrap();

        if next_byte == 0xFF {
            break; // End of list.
        }

        let mut elem_len;
        match next_byte {
            253 => { elem_len = reader.read_le_u32().unwrap() },
            254 | 255 => { panic!("Invalid length value in zipmap: {}", next_byte) },
            _ => { elem_len = next_byte as u32 }
        }

        let key = reader.read_exact(elem_len as uint).unwrap();
        hash.push(key);

        let next_byte = reader.read_byte().unwrap();
        match next_byte {
            253 => { elem_len = reader.read_le_u32().unwrap() },
            254 | 255 => { panic!("Invalid length value in zipmap: {}", next_byte) },
            _ => { elem_len = next_byte as u32 }
        }

        let _free = reader.read_byte().unwrap();
        let value = reader.read_exact(elem_len as uint).unwrap();
        hash.push(value);

        if length > 0 {
            length -= 1;
        }

        if length == 0 {
            assert!(reader.read_byte().unwrap() == 0xFF);
            break;
        }
    }

    hash
}

fn read_set_intset<T: Reader>(input: &mut T) -> Vec<i64> {
    let mut set = vec![];

    let intset = read_blob(input);

    let mut reader = MemReader::new(intset);
    let byte_size = reader.read_le_u32().unwrap();
    let intset_length = reader.read_le_u32().unwrap();

    for _ in range(0, intset_length) {
        let val = match byte_size {
            2 => reader.read_le_i16().unwrap() as i64,
            4 => reader.read_le_i32().unwrap() as i64,
            8 => reader.read_le_i64().unwrap(),
            _ => panic!("unhandled byte size in intset: {}", byte_size)
        };

        set.push(val);
    }

    set
}

fn read_type<T: Reader>(value_type: u8, input: &mut T) -> DataType {
    match value_type {
        types::STRING => {
            DataType::String(read_blob(input))
        },
        types::LIST => {
            DataType::List(read_linked_list(input))
        },
        types::SET => {
            DataType::Set(read_linked_list(input))
        },
        types::ZSET => {
            DataType::SortedSet(read_sorted_set(input))
        },
        types::HASH => {
            DataType::Hash(read_hash(input))
        },
        types::HASH_ZIPMAP => {
            DataType::Hash(read_hash_zipmap(input))
        },
        types::LIST_ZIPLIST => {
            DataType::ListOfTypes(read_list_ziplist(input))
        },
        types::SET_INTSET => {
            DataType::Intset(read_set_intset(input))
        },
        types::ZSET_ZIPLIST => {
            DataType::SortedSetOfTypes(read_list_ziplist(input))
        },
        types::HASH_ZIPLIST => {
            DataType::ListOfTypes(read_list_ziplist(input))
        },
        _ => { panic!("Value Type not implemented: {}", value_type) }
    }
}

pub fn read_length_with_encoding<T: Reader>(input: &mut T) -> LengthEncoded {
    let mut length;
    let mut is_encoded = false;

    let enc_type = input.read_byte().unwrap();

    match (enc_type & 0xC0) >> 6 {
        constants::RDB_ENCVAL => {
            is_encoded = true;
            length = (enc_type & 0x3F) as u32;
        },
        constants::RDB_6BITLEN => {
            length = (enc_type & 0x3F) as u32;
        },
        constants::RDB_14BITLEN => {
            let next_byte = input.read_byte().unwrap();
            length = (((enc_type & 0x3F) as u32) <<8) | next_byte as u32;
        },
        _ => {
            length = input.read_be_u32().unwrap();
        }
    }

    LengthEncoded::LE(length, is_encoded)
}

pub fn read_length<T: Reader>(input: &mut T) -> u32 {
    let LengthEncoded::LE(length, _) = read_length_with_encoding(input);
    length
}

fn int_to_vec(number: i32) -> Vec<u8> {
    let number = number.to_string();
    let mut result = Vec::with_capacity(number.len());
    for &c in number.as_bytes().iter() {
        result.push(c);
    }
    result
}

pub fn read_blob<T: Reader>(input: &mut T) -> Vec<u8> {
    let LengthEncoded::LE(length, is_encoded) = read_length_with_encoding(input);

    if is_encoded {
        match length {
            encoding::INT8 => { int_to_vec(input.read_i8().unwrap() as i32) },
            encoding::INT16 => { int_to_vec(input.read_le_i16().unwrap() as i32) },
            encoding::INT32 => { int_to_vec(input.read_le_i32().unwrap() as i32) },
            encoding::LZF => {
                let compressed_length = read_length(input);
                let real_length = read_length(input);
                let data = input.read_exact(compressed_length as uint).unwrap();
                lzf::decompress(data.as_slice(), real_length as uint).unwrap()
            },
            _ => { panic!("Unknown encoding: {}", length) }
        }
    } else {
        input.read_exact(length as uint).unwrap()
    }
}
<commit_msg>Read the database number from length encoded format<commit_after>#![feature(slicing_syntax)]

extern crate lzf;
use std::str;
use lzf::decompress;
use std::io::MemReader;
use std::io;

mod version {
    pub const SUPPORTED_MINIMUM : u32 = 1;
    pub const SUPPORTED_MAXIMUM : u32 = 6;
}

mod constants {
    pub const RDB_6BITLEN : u8 = 0;
    pub const RDB_14BITLEN : u8 = 1;
    pub const RDB_ENCVAL : u8 = 3;
    pub const RDB_MAGIC : &'static str = "REDIS";
}

mod op_codes {
    pub const EXPIRETIME_MS : u8 = 252;
    pub const EXPIRETIME : u8 = 253;
    pub const SELECTDB   : u8 = 254;
    pub const EOF : u8 = 255;
}

mod types {
    pub const STRING : u8 = 0;
    pub const LIST : u8 = 1;
    pub const SET : u8 = 2;
    pub const ZSET : u8 = 3;
    pub const HASH : u8 = 4;
    pub const HASH_ZIPMAP : u8 = 9;
    pub const LIST_ZIPLIST : u8 = 10;
    pub const SET_INTSET : u8 = 11;
    pub const ZSET_ZIPLIST : u8 = 12;
    pub const HASH_ZIPLIST : u8 = 13;
}

mod encoding {
    pub const INT8 : u32 = 0;
    pub const INT16 : u32 = 1;
    pub const INT32 : u32 = 2;
    pub const LZF : u32 = 3;
}

#[derive(Show)]
pub enum DataType {
    String(Vec<u8>),
    Number(i64),
    ListOfTypes(Vec<DataType>),
    HashOfTypes(Vec<DataType>),
    SortedSetOfTypes(Vec<DataType>),
    Intset(Vec<i64>),
    List(Vec<Vec<u8>>),
    Set(Vec<Vec<u8>>),
    SortedSet(Vec<(f64,Vec<u8>)>),
    Hash(Vec<Vec<u8>>),
    Unknown
}

#[derive(Show,PartialEq,Copy)]
pub enum LengthEncoded {
    LE(u32, bool)
}

pub struct RdbParser<'a, T: 'a + Reader> {
    input: &'a mut T
}

impl<'a, T: Reader> RdbParser<'a, T> {
    pub fn new(input: &mut T) -> RdbParser<T> {
        RdbParser{input: input}
    }

    pub fn parse(&mut self) {
        assert!(self.verify_magic());
        assert!(self.verify_version());

        let mut out = io::stdout();
        loop {
            let next_op = self.input.read_byte().unwrap();

            match next_op {
                op_codes::SELECTDB => {
                    let db = read_length(self.input);
                    println!("SELECTDB: {}", db);
                },
                op_codes::EOF => {
                    println!("EOF");
                    break ;
                },
                op_codes::EXPIRETIME_MS => {
                    let expiretime_ms = self.input.read_le_u64().unwrap();
                    println!("EXPIRETIME_MS: {}", expiretime_ms);
                },
                op_codes::EXPIRETIME => {
                    let expiretime = self.input.read_be_u32().unwrap();
                    println!("EXPIRETIME: {}", expiretime);
                }
                _ => {
                    let key = read_blob(self.input);
                    let _ = out.write(key[]);
                    let _ = out.write_str(": ");
                    let _ = out.flush();

                    match read_type(next_op, self.input) {
                        DataType::String(t) => {
                            let _ = out.write(t[]);
                            let _ = out.write_str("\n");
                        },
                        DataType::Number(t) => { println!("{}", t) },
                        DataType::ListOfTypes(t) => { println!("{}", t) },
                        DataType::Intset(t) => { println!("{}", t) },
                        DataType::Hash(t) => {
                            for val in t.iter() {
                                let _ = out.write(val[]);
                                let _ = out.write_str(", ");
                            }
                            let _ = out.write_str("\n");
                        },
                        DataType::HashOfTypes(t) => { println!("{}", t) },
                        _ => {}
                    }
                }
            }

        }

        return;

    }

    pub fn verify_magic(&mut self) -> bool {
        let magic = self.input.read_exact(5).unwrap();

        // Meeeeeh.
        magic[0] == constants::RDB_MAGIC.as_bytes()[0] &&
            magic[1] == constants::RDB_MAGIC.as_bytes()[1] &&
            magic[2] == constants::RDB_MAGIC.as_bytes()[2] &&
            magic[3] == constants::RDB_MAGIC.as_bytes()[3] &&
            magic[4] == constants::RDB_MAGIC.as_bytes()[4]
    }

    pub fn verify_version(&mut self) -> bool {
        let version = self.input.read_exact(4).unwrap();

        let version = (version[0]-48) as u32 * 1000 +
            (version[1]-48) as u32 * 100 +
            (version[2]-48) as u32 * 10 +
            (version[3]-48) as u32;

        version >= version::SUPPORTED_MINIMUM &&
            version <= version::SUPPORTED_MAXIMUM
    }
}

fn read_linked_list<T: Reader>(input: &mut T) -> Vec<Vec<u8>> {
    let mut len = read_length(input);
    let mut list = vec![];

    while len > 0 {
        let blob = read_blob(input);
        list.push(blob);
        len -= 1;
    }

    list
}

fn read_sorted_set<T: Reader>(input: &mut T) -> Vec<(f64,Vec<u8>)> {
    let mut set = vec![];
    let mut set_items = read_length(input);

    while set_items > 0 {
        let val = read_blob(input);
        let score_length = input.read_byte().unwrap();
        let score = input.read_exact(score_length as uint).unwrap();
        let score = unsafe{str::from_utf8_unchecked(score[])}.
            parse::<f64>().unwrap();

        set.push((score, val));

        set_items -= 1;
    }

    set
}

fn read_hash<T: Reader>(input: &mut T) -> Vec<Vec<u8>> {
    let mut hash = vec![];
    let mut hash_items = read_length(input);
    hash_items = 2*hash_items;

    while hash_items > 0 {
        let val = read_blob(input);
        hash.push(val);

        hash_items -= 1;
    }

    hash
}

fn read_list_ziplist<T: Reader>(input: &mut T) -> Vec<DataType> {
    let mut list = vec![];

    let ziplist = read_blob(input);

    let mut reader = MemReader::new(ziplist);

    let _zlbytes = reader.read_le_u32().unwrap();
    let _zltail = reader.read_le_u32().unwrap();
    let zllen = reader.read_le_u16().unwrap();

    for _ in range(0, zllen) {
        // 1. 1 or 5 bytes length of previous entry
        match reader.read_byte().unwrap() {
            254 => {
                let _ = reader.read_exact(4).unwrap();
            },
            _ => {}
        }

        let mut length : u64;
        let mut number_value : i64;

        // 2. Read flag or number value
        let flag = reader.read_byte().unwrap();

        match (flag & 0xC0) >> 6 {
            0 => { length = (flag & 0x3F) as u64 },
            1 => {
                let next_byte = reader.read_byte().unwrap();
                length = (((flag & 0x3F) as u64) << 8) | next_byte as u64;
            },
            2 => {
                length = reader.read_be_u32().unwrap() as u64;
            },
            _ => {
                match (flag & 0xF0) >> 4 {
                    0xC => {
                        number_value = reader.read_le_i16().unwrap() as i64 },
                    0xD => {
                        number_value = reader.read_le_i32().unwrap() as i64 },
                    0xE => {
                        number_value = reader.read_le_i64().unwrap() as i64 },
                    0xF => {
                        match flag & 0xF {
                            0 => {
                                let bytes = reader.read_exact(3).unwrap();
                                number_value = ((bytes[0] as i64) << 16) ^
                                    ((bytes[1] as i64) << 8) ^
                                    (bytes[2] as i64);
                            },
                            0xE => {
                                number_value = reader.read_byte().unwrap() as i64 },
                            _ => { number_value = (flag & 0xF) as i64 - 1; }
                        }
                    },
                    _ => {
                        println!("Flag not handled: {}", flag);
                        continue;
                    }

                }

                list.push(DataType::Number(number_value));
                continue;
            }
        }

        // 3. Read value
        let rawval = reader.read_exact(length as uint).unwrap();
        list.push(DataType::String(rawval));
    }
    assert!(reader.read_byte().unwrap() == 0xFF);

    list
}

fn read_hash_zipmap<T: Reader>(input: &mut T) -> Vec<Vec<u8>> {
    let zipmap = read_blob(input);

    let mut reader = MemReader::new(zipmap);

    let zmlen = reader.read_byte().unwrap();

    let mut length;
    let mut hash;
    if zmlen <= 254 {
        length = zmlen as uint;
        hash = Vec::with_capacity(length);
    } else {
        length = -1;
        hash = Vec::with_capacity(255);
    }

    loop {
        let next_byte = reader.read_byte().unwrap();

        if next_byte == 0xFF {
            break; // End of list.
        }

        let mut elem_len;
        match next_byte {
            253 => { elem_len = reader.read_le_u32().unwrap() },
            254 | 255 => { panic!("Invalid length value in zipmap: {}", next_byte) },
            _ => { elem_len = next_byte as u32 }
        }

        let key = reader.read_exact(elem_len as uint).unwrap();
        hash.push(key);

        let next_byte = reader.read_byte().unwrap();
        match next_byte {
            253 => { elem_len = reader.read_le_u32().unwrap() },
            254 | 255 => { panic!("Invalid length value in zipmap: {}", next_byte) },
            _ => { elem_len = next_byte as u32 }
        }

        let _free = reader.read_byte().unwrap();
        let value = reader.read_exact(elem_len as uint).unwrap();
        hash.push(value);

        if length > 0 {
            length -= 1;
        }

        if length == 0 {
            assert!(reader.read_byte().unwrap() == 0xFF);
            break;
        }
    }

    hash
}

fn read_set_intset<T: Reader>(input: &mut T) -> Vec<i64> {
    let mut set = vec![];

    let intset = read_blob(input);

    let mut reader = MemReader::new(intset);
    let byte_size = reader.read_le_u32().unwrap();
    let intset_length = reader.read_le_u32().unwrap();

    for _ in range(0, intset_length) {
        let val = match byte_size {
            2 => reader.read_le_i16().unwrap() as i64,
            4 => reader.read_le_i32().unwrap() as i64,
            8 => reader.read_le_i64().unwrap(),
            _ => panic!("unhandled byte size in intset: {}", byte_size)
        };

        set.push(val);
    }

    set
}

fn read_type<T: Reader>(value_type: u8, input: &mut T) -> DataType {
    match value_type {
        types::STRING => {
            DataType::String(read_blob(input))
        },
        types::LIST => {
            DataType::List(read_linked_list(input))
        },
        types::SET => {
            DataType::Set(read_linked_list(input))
        },
        types::ZSET => {
            DataType::SortedSet(read_sorted_set(input))
        },
        types::HASH => {
            DataType::Hash(read_hash(input))
        },
        types::HASH_ZIPMAP => {
            DataType::Hash(read_hash_zipmap(input))
        },
        types::LIST_ZIPLIST => {
            DataType::ListOfTypes(read_list_ziplist(input))
        },
        types::SET_INTSET => {
            DataType::Intset(read_set_intset(input))
        },
        types::ZSET_ZIPLIST => {
            DataType::SortedSetOfTypes(read_list_ziplist(input))
        },
        types::HASH_ZIPLIST => {
            DataType::ListOfTypes(read_list_ziplist(input))
        },
        _ => { panic!("Value Type not implemented: {}", value_type) }
    }
}

pub fn read_length_with_encoding<T: Reader>(input: &mut T) -> LengthEncoded {
    let mut length;
    let mut is_encoded = false;

    let enc_type = input.read_byte().unwrap();

    match (enc_type & 0xC0) >> 6 {
        constants::RDB_ENCVAL => {
            is_encoded = true;
            length = (enc_type & 0x3F) as u32;
        },
        constants::RDB_6BITLEN => {
            length = (enc_type & 0x3F) as u32;
        },
        constants::RDB_14BITLEN => {
            let next_byte = input.read_byte().unwrap();
            length = (((enc_type & 0x3F) as u32) <<8) | next_byte as u32;
        },
        _ => {
            length = input.read_be_u32().unwrap();
        }
    }

    LengthEncoded::LE(length, is_encoded)
}

pub fn read_length<T: Reader>(input: &mut T) -> u32 {
    let LengthEncoded::LE(length, _) = read_length_with_encoding(input);
    length
}

fn int_to_vec(number: i32) -> Vec<u8> {
    let number = number.to_string();
    let mut result = Vec::with_capacity(number.len());
    for &c in number.as_bytes().iter() {
        result.push(c);
    }
    result
}

pub fn read_blob<T: Reader>(input: &mut T) -> Vec<u8> {
    let LengthEncoded::LE(length, is_encoded) = read_length_with_encoding(input);

    if is_encoded {
        match length {
            encoding::INT8 => { int_to_vec(input.read_i8().unwrap() as i32) },
            encoding::INT16 => { int_to_vec(input.read_le_i16().unwrap() as i32) },
            encoding::INT32 => { int_to_vec(input.read_le_i32().unwrap() as i32) },
            encoding::LZF => {
                let compressed_length = read_length(input);
                let real_length = read_length(input);
                let data = input.read_exact(compressed_length as uint).unwrap();
                lzf::decompress(data.as_slice(), real_length as uint).unwrap()
            },
            _ => { panic!("Unknown encoding: {}", length) }
        }
    } else {
        input.read_exact(length as uint).unwrap()
    }
}
<|endoftext|>


<commit_before>#![crate_name = "bindgen"]
#![crate_type = "dylib"]

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", allow(needless_lifetimes))]

extern crate syntex_syntax as syntax;
extern crate libc;
#[macro_use] extern crate log;

use std::collections::HashSet;
use std::default::Default;
use std::io::{Write, self};
use std::fs::OpenOptions;
use std::path::{Path, self};
use std::{env, fs};

use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::print::pprust;
use syntax::print::pp::eof;
use syntax::ptr::P;

use types::Global;

mod types;
mod clangll;
mod clang;
mod gen;
mod parser;

#[derive(Clone)]
pub struct Builder<'a> {
    options: BindgenOptions,
    logger: Option<&'a Logger>
}

pub fn builder<'a>() -> Builder<'a> {
    Default::default()
}

impl<'a> Builder<'a> {
    pub fn header<T: Into<String>>(&mut self, header: T) -> &mut Self {
        self.clang_arg(header)
    }

    pub fn match_pat<T: Into<String>>(&mut self, arg: T) -> &mut Self {
        self.options.match_pat.push(arg.into());
        self
    }

    pub fn clang_arg<T: Into<String>>(&mut self, arg: T) -> &mut Self {
        self.options.clang_args.push(arg.into());
        self
    }

    pub fn link<T: Into<String>>(&mut self, library: T) -> &mut Self {
        self.options.links.push((library.into(), LinkType::Default));
        self
    }

    pub fn link_static<T: Into<String>>(&mut self, library: T) -> &mut Self {
        self.options.links.push((library.into(), LinkType::Static));
        self
    }

    pub fn link_framework<T: Into<String>>(&mut self, library: T) -> &mut Self {
        self.options.links.push((library.into(), LinkType::Framework));
        self
    }

    pub fn forbid_unknown_types(&mut self) -> &mut Self {
        self.options.fail_on_unknown_type = true;
        self
    }

    pub fn emit_builtins(&mut self) -> &mut Self {
        self.options.builtins = true;
        self
    }

    pub fn rust_enums(&mut self, value: bool) -> &mut Self {
        self.options.rust_enums = value;
        self
    }

    pub fn log(&mut self, logger: &'a Logger) -> &mut Self {
        self.logger = Some(logger);
        self
    }

    pub fn generate(&self) -> Result<Bindings, ()> {
        Bindings::generate(&self.options, self.logger, None)
    }
}

impl<'a> Default for Builder<'a> {
    fn default() -> Builder<'a> {
        Builder {
            logger: None,
            options: Default::default()
        }
    }
}

#[derive(Clone)]
/// Deprecated - use a `Builder` instead
pub struct BindgenOptions {
    pub match_pat: Vec<String>,
    pub builtins: bool,
    pub rust_enums: bool,
    pub links: Vec<(String, LinkType)>,
    pub emit_ast: bool,
    pub fail_on_unknown_type: bool,
    pub override_enum_ty: String,
    pub clang_args: Vec<String>,
    pub derive_debug: bool,
}

impl Default for BindgenOptions {
    fn default() -> BindgenOptions {
        BindgenOptions {
            match_pat: Vec::new(),
            builtins: false,
            rust_enums: true,
            links: Vec::new(),
            emit_ast: false,
            fail_on_unknown_type: false,
            override_enum_ty: "".to_owned(),
            clang_args: match get_include_dir() {
                Some(path) => vec!("-idirafter".to_owned(), path),
                None => Vec::new()
            },
            derive_debug: true
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LinkType {
    Default,
    Static,
    Framework
}

pub trait Logger {
    fn error(&self, msg: &str);
    fn warn(&self, msg: &str);
}

#[derive(Clone)]
pub struct Bindings {
    module: ast::Mod
}

impl Bindings {
    /// Deprecated - use a `Builder` instead
    pub fn generate(options: &BindgenOptions, logger: Option<&Logger>, span: Option<Span>) -> Result<Bindings, ()> {
        let l = DummyLogger;
        let logger = match logger {
            Some(l) => l,
            None => &l as &Logger
        };

        let span = match span {
            Some(s) => s,
            None => DUMMY_SP
        };

        let globals = try!(parse_headers(options, logger));

        let module = ast::Mod {
            inner: span,
            items: gen::gen_mod(options, globals, span)
        };

        Ok(Bindings {
            module: module
        })
    }

    pub fn into_ast(self) -> Vec<P<ast::Item>> {
        self.module.items
    }

    pub fn to_string(&self) -> String {
        let mut mod_str = Vec::new();
        {
            let ref_writer = Box::new(mod_str.by_ref()) as Box<Write>;
            self.write(ref_writer).expect("Could not write bindings to string");
        }
        String::from_utf8(mod_str).unwrap()
    }

    pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
        let file = try!(OpenOptions::new().write(true).truncate(true).create(true).open(path));
        self.write(Box::new(file))
    }

    pub fn write<'a>(&self, mut writer: Box<Write + 'a>) -> io::Result<()> {
        try!(writer.write("/* automatically generated by rust-bindgen */\n\n".as_bytes()));
        let mut ps = pprust::rust_printer(writer);
        try!(ps.print_mod(&self.module, &[]));
        try!(ps.print_remaining_comments());
        try!(eof(&mut ps.s));
        ps.s.out.flush()
    }
}

struct DummyLogger;

impl Logger for DummyLogger {
    fn error(&self, _msg: &str) { }
    fn warn(&self, _msg: &str) { }
}

fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<Vec<Global>, ()> {
    fn str_to_ikind(s: &str) -> Option<types::IKind> {
        match s {
            "uchar"     => Some(types::IUChar),
            "schar"     => Some(types::ISChar),
            "ushort"    => Some(types::IUShort),
            "sshort"    => Some(types::IShort),
            "uint"      => Some(types::IUInt),
            "sint"      => Some(types::IInt),
            "ulong"     => Some(types::IULong),
            "slong"     => Some(types::ILong),
            "ulonglong" => Some(types::IULongLong),
            "slonglong" => Some(types::ILongLong),
            _           => None,
        }
    }

    let clang_opts = parser::ClangParserOptions {
        builtin_names: builtin_names(),
        builtins: options.builtins,
        match_pat: options.match_pat.clone(),
        emit_ast: options.emit_ast,
        fail_on_unknown_type: options.fail_on_unknown_type,
        override_enum_ty: str_to_ikind(&options.override_enum_ty[..]),
        clang_args: options.clang_args.clone(),
    };

    parser::parse(clang_opts, logger)
}

fn builtin_names() -> HashSet<String> {
    let mut names = HashSet::new();
    let keys = [
        "__va_list_tag",
        "__va_list",
        "__builtin_va_list",
    ];

    for s in &keys {
        names.insert((*s).to_owned());
    }

    names
}

#[test]
fn builder_state()
{
    let logger = DummyLogger;
    let mut build = builder();
    {
        build.header("example.h");
        build.link_static("m");
        build.log(&logger);
    }
    assert!(build.logger.is_some());
    assert!(build.options.clang_args.binary_search(&"example.h".to_owned()).is_ok());
    assert!(build.options.links.binary_search(&("m".to_owned(), LinkType::Static)).is_ok());
}

// Get the first directory in PATH that contains a file named "clang".
fn get_clang_dir() -> Option<path::PathBuf>{
    if let Some(paths) = env::var_os("PATH") {
        for mut path in env::split_paths(&paths) {
            path.push("clang");
            if let Ok(real_path) = fs::canonicalize(&path) {
                if fs::metadata(&real_path).iter().any(|m| m.is_file()) &&
                    real_path
                        .file_name()
                        .and_then(|f| f.to_str())
                        .iter()
                        .any(|&f| f.starts_with("clang")) {
                    if let Some(dir) = real_path.parent() {
                        return Some(dir.to_path_buf())
                    }
                }
            }
        }
    }
    None
}

// Try to find the directory that contains clang's bundled headers. Clang itself does something
// very similar: it takes the parent directory of the current executable, appends
// "../lib/clang/<VERSIONSTRING>/include". We have two problems emulating this behaviour:
// * We don't have a very good way of finding the clang executable, but can fake this by
//   searching $PATH and take one directory that contains "clang".
// * We don't have access to <VERSIONSTRING>. There is clang_getClangVersion(), but it returns
//   a human-readable description string which is not guaranteed to be stable and a pain to parse.
//   We work around that by just taking the first directory in ../lib/clang and hope it's the
//   current version.
// TODO: test if this works on Windows at all.
#[doc(hidden)]
pub fn get_include_dir() -> Option<String> {
    match get_clang_dir() {
        Some(mut p) => {
            p.push("..");
            p.push("lib");
            p.push("clang");

            let dir_iter = match fs::read_dir(p) {
                Ok(dir_iter) => dir_iter,
                _ => return None
            };
            for dir in dir_iter {
                match dir {
                    Ok(dir) => {
                        // Let's take the first dir. In my case, there's only one directory
                        // there anyway.
                        let mut p = dir.path();
                        p.push("include");
                        match p.into_os_string().into_string() {
                            Ok(s) => return Some(s),
                            // We found the directory, but can't access it as it contains
                            // invalid unicode.
                            _ => return None,
                        }
                    }
                    _ => return None,
                }
            }
            None
        }
        None => None,
    }
}
<commit_msg>Disallow needless_lifetimes<commit_after>#![crate_name = "bindgen"]
#![crate_type = "dylib"]

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

extern crate syntex_syntax as syntax;
extern crate libc;
#[macro_use] extern crate log;

use std::collections::HashSet;
use std::default::Default;
use std::io::{Write, self};
use std::fs::OpenOptions;
use std::path::{Path, self};
use std::{env, fs};

use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::print::pprust;
use syntax::print::pp::eof;
use syntax::ptr::P;

use types::Global;

mod types;
mod clangll;
mod clang;
mod gen;
mod parser;

#[derive(Clone)]
pub struct Builder<'a> {
    options: BindgenOptions,
    logger: Option<&'a Logger>
}

pub fn builder<'a>() -> Builder<'a> {
    Default::default()
}

impl<'a> Builder<'a> {
    pub fn header<T: Into<String>>(&mut self, header: T) -> &mut Self {
        self.clang_arg(header)
    }

    pub fn match_pat<T: Into<String>>(&mut self, arg: T) -> &mut Self {
        self.options.match_pat.push(arg.into());
        self
    }

    pub fn clang_arg<T: Into<String>>(&mut self, arg: T) -> &mut Self {
        self.options.clang_args.push(arg.into());
        self
    }

    pub fn link<T: Into<String>>(&mut self, library: T) -> &mut Self {
        self.options.links.push((library.into(), LinkType::Default));
        self
    }

    pub fn link_static<T: Into<String>>(&mut self, library: T) -> &mut Self {
        self.options.links.push((library.into(), LinkType::Static));
        self
    }

    pub fn link_framework<T: Into<String>>(&mut self, library: T) -> &mut Self {
        self.options.links.push((library.into(), LinkType::Framework));
        self
    }

    pub fn forbid_unknown_types(&mut self) -> &mut Self {
        self.options.fail_on_unknown_type = true;
        self
    }

    pub fn emit_builtins(&mut self) -> &mut Self {
        self.options.builtins = true;
        self
    }

    pub fn rust_enums(&mut self, value: bool) -> &mut Self {
        self.options.rust_enums = value;
        self
    }

    pub fn log(&mut self, logger: &'a Logger) -> &mut Self {
        self.logger = Some(logger);
        self
    }

    pub fn generate(&self) -> Result<Bindings, ()> {
        Bindings::generate(&self.options, self.logger, None)
    }
}

impl<'a> Default for Builder<'a> {
    fn default() -> Builder<'a> {
        Builder {
            logger: None,
            options: Default::default()
        }
    }
}

#[derive(Clone)]
/// Deprecated - use a `Builder` instead
pub struct BindgenOptions {
    pub match_pat: Vec<String>,
    pub builtins: bool,
    pub rust_enums: bool,
    pub links: Vec<(String, LinkType)>,
    pub emit_ast: bool,
    pub fail_on_unknown_type: bool,
    pub override_enum_ty: String,
    pub clang_args: Vec<String>,
    pub derive_debug: bool,
}

impl Default for BindgenOptions {
    fn default() -> BindgenOptions {
        BindgenOptions {
            match_pat: Vec::new(),
            builtins: false,
            rust_enums: true,
            links: Vec::new(),
            emit_ast: false,
            fail_on_unknown_type: false,
            override_enum_ty: "".to_owned(),
            clang_args: match get_include_dir() {
                Some(path) => vec!("-idirafter".to_owned(), path),
                None => Vec::new()
            },
            derive_debug: true
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LinkType {
    Default,
    Static,
    Framework
}

pub trait Logger {
    fn error(&self, msg: &str);
    fn warn(&self, msg: &str);
}

#[derive(Clone)]
pub struct Bindings {
    module: ast::Mod
}

impl Bindings {
    /// Deprecated - use a `Builder` instead
    pub fn generate(options: &BindgenOptions, logger: Option<&Logger>, span: Option<Span>) -> Result<Bindings, ()> {
        let l = DummyLogger;
        let logger = match logger {
            Some(l) => l,
            None => &l as &Logger
        };

        let span = match span {
            Some(s) => s,
            None => DUMMY_SP
        };

        let globals = try!(parse_headers(options, logger));

        let module = ast::Mod {
            inner: span,
            items: gen::gen_mod(options, globals, span)
        };

        Ok(Bindings {
            module: module
        })
    }

    pub fn into_ast(self) -> Vec<P<ast::Item>> {
        self.module.items
    }

    pub fn to_string(&self) -> String {
        let mut mod_str = Vec::new();
        {
            let ref_writer = Box::new(mod_str.by_ref()) as Box<Write>;
            self.write(ref_writer).expect("Could not write bindings to string");
        }
        String::from_utf8(mod_str).unwrap()
    }

    pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
        let file = try!(OpenOptions::new().write(true).truncate(true).create(true).open(path));
        self.write(Box::new(file))
    }

    // https://github.com/Manishearth/rust-clippy/issues/740
    #[cfg_attr(feature = "clippy", allow(needless_lifetimes))]
    pub fn write<'a>(&self, mut writer: Box<Write + 'a>) -> io::Result<()> {
        try!(writer.write("/* automatically generated by rust-bindgen */\n\n".as_bytes()));
        let mut ps = pprust::rust_printer(writer);
        try!(ps.print_mod(&self.module, &[]));
        try!(ps.print_remaining_comments());
        try!(eof(&mut ps.s));
        ps.s.out.flush()
    }
}

struct DummyLogger;

impl Logger for DummyLogger {
    fn error(&self, _msg: &str) { }
    fn warn(&self, _msg: &str) { }
}

fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<Vec<Global>, ()> {
    fn str_to_ikind(s: &str) -> Option<types::IKind> {
        match s {
            "uchar"     => Some(types::IUChar),
            "schar"     => Some(types::ISChar),
            "ushort"    => Some(types::IUShort),
            "sshort"    => Some(types::IShort),
            "uint"      => Some(types::IUInt),
            "sint"      => Some(types::IInt),
            "ulong"     => Some(types::IULong),
            "slong"     => Some(types::ILong),
            "ulonglong" => Some(types::IULongLong),
            "slonglong" => Some(types::ILongLong),
            _           => None,
        }
    }

    let clang_opts = parser::ClangParserOptions {
        builtin_names: builtin_names(),
        builtins: options.builtins,
        match_pat: options.match_pat.clone(),
        emit_ast: options.emit_ast,
        fail_on_unknown_type: options.fail_on_unknown_type,
        override_enum_ty: str_to_ikind(&options.override_enum_ty[..]),
        clang_args: options.clang_args.clone(),
    };

    parser::parse(clang_opts, logger)
}

fn builtin_names() -> HashSet<String> {
    let mut names = HashSet::new();
    let keys = [
        "__va_list_tag",
        "__va_list",
        "__builtin_va_list",
    ];

    for s in &keys {
        names.insert((*s).to_owned());
    }

    names
}

#[test]
fn builder_state()
{
    let logger = DummyLogger;
    let mut build = builder();
    {
        build.header("example.h");
        build.link_static("m");
        build.log(&logger);
    }
    assert!(build.logger.is_some());
    assert!(build.options.clang_args.binary_search(&"example.h".to_owned()).is_ok());
    assert!(build.options.links.binary_search(&("m".to_owned(), LinkType::Static)).is_ok());
}

// Get the first directory in PATH that contains a file named "clang".
fn get_clang_dir() -> Option<path::PathBuf>{
    if let Some(paths) = env::var_os("PATH") {
        for mut path in env::split_paths(&paths) {
            path.push("clang");
            if let Ok(real_path) = fs::canonicalize(&path) {
                if fs::metadata(&real_path).iter().any(|m| m.is_file()) &&
                    real_path
                        .file_name()
                        .and_then(|f| f.to_str())
                        .iter()
                        .any(|&f| f.starts_with("clang")) {
                    if let Some(dir) = real_path.parent() {
                        return Some(dir.to_path_buf())
                    }
                }
            }
        }
    }
    None
}

// Try to find the directory that contains clang's bundled headers. Clang itself does something
// very similar: it takes the parent directory of the current executable, appends
// "../lib/clang/<VERSIONSTRING>/include". We have two problems emulating this behaviour:
// * We don't have a very good way of finding the clang executable, but can fake this by
//   searching $PATH and take one directory that contains "clang".
// * We don't have access to <VERSIONSTRING>. There is clang_getClangVersion(), but it returns
//   a human-readable description string which is not guaranteed to be stable and a pain to parse.
//   We work around that by just taking the first directory in ../lib/clang and hope it's the
//   current version.
// TODO: test if this works on Windows at all.
#[doc(hidden)]
pub fn get_include_dir() -> Option<String> {
    match get_clang_dir() {
        Some(mut p) => {
            p.push("..");
            p.push("lib");
            p.push("clang");

            let dir_iter = match fs::read_dir(p) {
                Ok(dir_iter) => dir_iter,
                _ => return None
            };
            for dir in dir_iter {
                match dir {
                    Ok(dir) => {
                        // Let's take the first dir. In my case, there's only one directory
                        // there anyway.
                        let mut p = dir.path();
                        p.push("include");
                        match p.into_os_string().into_string() {
                            Ok(s) => return Some(s),
                            // We found the directory, but can't access it as it contains
                            // invalid unicode.
                            _ => return None,
                        }
                    }
                    _ => return None,
                }
            }
            None
        }
        None => None,
    }
}
<|endoftext|>


<commit_before>#![warn(rust_2018_idioms)]
extern crate conduit;
extern crate route_recognizer as router;

use std::collections::hash_map::{Entry, HashMap};
use std::error::Error;
use std::fmt;

use conduit::{box_error, Handler, HandlerResult, Method, RequestExt};
use router::{Match, Router};

#[derive(Default)]
pub struct RouteBuilder {
    routers: HashMap<Method, Router<WrappedHandler>>,
}

#[derive(Clone)]
struct RoutePattern(String);

pub struct WrappedHandler {
    pattern: RoutePattern,
    handler: Box<dyn Handler>,
}

#[derive(Debug)]
pub struct RouterError(String);

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder {
            routers: HashMap::new(),
        }
    }

    #[allow(clippy::borrowed_box)]
    pub fn recognize<'a>(
        &'a self,
        method: &Method,
        path: &str,
    ) -> Result<Match<&WrappedHandler>, RouterError> {
        match self.routers.get(method) {
            Some(router) => router.recognize(path),
            None => Err(format!("No router found for {:?}", method)),
        }
        .map_err(RouterError)
    }

    pub fn map<'a, H: Handler>(
        &'a mut self,
        method: Method,
        pattern: &str,
        handler: H,
    ) -> &'a mut RouteBuilder {
        {
            let router = match self.routers.entry(method) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Router::new()),
            };
            let wrapped_handler = WrappedHandler {
                pattern: RoutePattern(pattern.to_string()),
                handler: Box::new(handler)
            };
            router.add(pattern, wrapped_handler);
        }
        self
    }

    pub fn get<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::GET, pattern, handler)
    }

    pub fn post<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::POST, pattern, handler)
    }

    pub fn put<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::PUT, pattern, handler)
    }

    pub fn delete<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::DELETE, pattern, handler)
    }

    pub fn head<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::HEAD, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => return Err(box_error(e)),
            }
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert(m.handler.pattern.clone());
            extensions.insert(m.params.clone());
        }

        (*m.handler.handler).call(request)
    }
}

impl Error for RouterError {
    fn description(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for RouterError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params(req: &dyn RequestExt) -> &router::Params {
    req.extensions()
        .find::<router::Params>()
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a (dyn RequestExt + 'a) {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    extern crate conduit_test;

    use std::io;
    use std::net::SocketAddr;

    use {RequestParams, RouteBuilder, RoutePattern};

    use self::conduit_test::ResponseExt;
    use conduit::{
        Body, Extensions, Handler, HeaderMap, Host, Method, Response, Scheme, StatusCode, TypeMap,
        Version,
    };

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions,
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: TypeMap::new(),
                method,
            }
        }
    }

    impl conduit::RequestExt for RequestSentinel {
        fn http_version(&self) -> Version {
            unimplemented!()
        }
        fn method(&self) -> &Method {
            &self.method
        }
        fn scheme(&self) -> Scheme {
            unimplemented!()
        }
        fn host(&self) -> Host<'_> {
            unimplemented!()
        }
        fn virtual_root(&self) -> Option<&str> {
            unimplemented!()
        }
        fn path(&self) -> &str {
            &self.path
        }
        fn path_mut(&mut self) -> &mut String {
            &mut self.path
        }
        fn query_string(&self) -> Option<&str> {
            unimplemented!()
        }
        fn remote_addr(&self) -> SocketAddr {
            unimplemented!()
        }
        fn content_length(&self) -> Option<u64> {
            unimplemented!()
        }
        fn headers(&self) -> &HeaderMap {
            unimplemented!()
        }
        fn body(&mut self) -> &mut dyn io::Read {
            unimplemented!()
        }
        fn extensions(&self) -> &Extensions {
            &self.extensions
        }
        fn mut_extensions(&mut self) -> &mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::GET, "/posts/1");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"1, GET, /posts/:id"[..]);
    }

    #[test]
    fn basic_post() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::POST, "/posts/10");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"10, POST, /posts/:id"[..]);
    }

    #[test]
    fn nonexistent_route() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::POST, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut dyn conduit::RequestExt) -> conduit::HttpResult {
        let mut res = vec![];
        res.push(req.params()["id"].clone());
        res.push(format!("{:?}", req.method()));
        res.push(req.extensions().find::<RoutePattern>().unwrap().0.clone());

        let bytes = res.join(", ").into_bytes();
        Response::builder().body(Body::from_vec(bytes))
    }
}
<commit_msg>Use static string slice in `RoutePattern` struct<commit_after>#![warn(rust_2018_idioms)]
extern crate conduit;
extern crate route_recognizer as router;

use std::collections::hash_map::{Entry, HashMap};
use std::error::Error;
use std::fmt;

use conduit::{box_error, Handler, HandlerResult, Method, RequestExt};
use router::{Match, Router};

#[derive(Default)]
pub struct RouteBuilder {
    routers: HashMap<Method, Router<WrappedHandler>>,
}

#[derive(Clone)]
struct RoutePattern(&'static str);

pub struct WrappedHandler {
    pattern: RoutePattern,
    handler: Box<dyn Handler>,
}

#[derive(Debug)]
pub struct RouterError(String);

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder {
            routers: HashMap::new(),
        }
    }

    #[allow(clippy::borrowed_box)]
    pub fn recognize<'a>(
        &'a self,
        method: &Method,
        path: &str,
    ) -> Result<Match<&WrappedHandler>, RouterError> {
        match self.routers.get(method) {
            Some(router) => router.recognize(path),
            None => Err(format!("No router found for {:?}", method)),
        }
        .map_err(RouterError)
    }

    pub fn map<'a, H: Handler>(
        &'a mut self,
        method: Method,
        pattern: &'static str,
        handler: H,
    ) -> &'a mut RouteBuilder {
        {
            let router = match self.routers.entry(method) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Router::new()),
            };
            let wrapped_handler = WrappedHandler {
                pattern: RoutePattern(pattern),
                handler: Box::new(handler)
            };
            router.add(pattern, wrapped_handler);
        }
        self
    }

    pub fn get<'a, H: Handler>(&'a mut self, pattern: &'static str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::GET, pattern, handler)
    }

    pub fn post<'a, H: Handler>(&'a mut self, pattern: &'static str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::POST, pattern, handler)
    }

    pub fn put<'a, H: Handler>(&'a mut self, pattern: &'static str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::PUT, pattern, handler)
    }

    pub fn delete<'a, H: Handler>(&'a mut self, pattern: &'static str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::DELETE, pattern, handler)
    }

    pub fn head<'a, H: Handler>(&'a mut self, pattern: &'static str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::HEAD, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => return Err(box_error(e)),
            }
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert(m.handler.pattern.clone());
            extensions.insert(m.params.clone());
        }

        (*m.handler.handler).call(request)
    }
}

impl Error for RouterError {
    fn description(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for RouterError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params(req: &dyn RequestExt) -> &router::Params {
    req.extensions()
        .find::<router::Params>()
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a (dyn RequestExt + 'a) {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    extern crate conduit_test;

    use std::io;
    use std::net::SocketAddr;

    use {RequestParams, RouteBuilder, RoutePattern};

    use self::conduit_test::ResponseExt;
    use conduit::{
        Body, Extensions, Handler, HeaderMap, Host, Method, Response, Scheme, StatusCode, TypeMap,
        Version,
    };

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions,
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: TypeMap::new(),
                method,
            }
        }
    }

    impl conduit::RequestExt for RequestSentinel {
        fn http_version(&self) -> Version {
            unimplemented!()
        }
        fn method(&self) -> &Method {
            &self.method
        }
        fn scheme(&self) -> Scheme {
            unimplemented!()
        }
        fn host(&self) -> Host<'_> {
            unimplemented!()
        }
        fn virtual_root(&self) -> Option<&str> {
            unimplemented!()
        }
        fn path(&self) -> &str {
            &self.path
        }
        fn path_mut(&mut self) -> &mut String {
            &mut self.path
        }
        fn query_string(&self) -> Option<&str> {
            unimplemented!()
        }
        fn remote_addr(&self) -> SocketAddr {
            unimplemented!()
        }
        fn content_length(&self) -> Option<u64> {
            unimplemented!()
        }
        fn headers(&self) -> &HeaderMap {
            unimplemented!()
        }
        fn body(&mut self) -> &mut dyn io::Read {
            unimplemented!()
        }
        fn extensions(&self) -> &Extensions {
            &self.extensions
        }
        fn mut_extensions(&mut self) -> &mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::GET, "/posts/1");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"1, GET, /posts/:id"[..]);
    }

    #[test]
    fn basic_post() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::POST, "/posts/10");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"10, POST, /posts/:id"[..]);
    }

    #[test]
    fn nonexistent_route() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::POST, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut dyn conduit::RequestExt) -> conduit::HttpResult {
        let mut res = vec![];
        res.push(req.params()["id"].clone());
        res.push(format!("{:?}", req.method()));
        res.push(req.extensions().find::<RoutePattern>().unwrap().0.to_string());

        let bytes = res.join(", ").into_bytes();
        Response::builder().body(Body::from_vec(bytes))
    }
}
<|endoftext|>