<commit_before>use std::collections::{BTreeSet, HashSet};
use std::collections::hash_state::HashState;
use std::default::Default;
use std::hash::{Hash, Hasher};

/// An extension trait for a `Set` whose elements have a defined total ordering.
/// This trait provides convenience methods which take advantage of the set's ordering.
pub trait SortedSet<T> : Sized
    where T: Clone + Ord {
    /// Returns the first (lowest) element currently in this set and optionally removes it
    /// from the set.
    /// Returns `None` if this set is empty.
    fn first(&mut self, remove: bool) -> Option<T>;

    /// Returns the last (highest) element current in this set and optionally removes it
    /// from the set.
    /// Returns `None` if this set is empty.
    fn last(&mut self, remove: bool) -> Option<T>;

    /// Returns the elements of this set which are less than (or equal to, if `inclusive`
    /// is true) `elem`, as a new instance of the same type of set.
    fn head_set(&self, elem: &T, inclusive: bool) -> Self;

    /// Returns the elements of this set ranging from `from_elem` to `to_elem`, as
    /// a new instance of the same type of set.
    fn sub_set(&self, from_elem: &T, from_inclusive: bool, to_elem: &T, to_inclusive: bool) -> Self;

    /// Returns the elements of this set which are greater than (or equal to, if
    /// `inclusive` is true) `elem`, as a new instance of the same type of set.
    fn tail_set(&self, elem: &T, inclusive: bool) -> Self;

    /// Returns the least element in this set greater than or equal to `elem`.
    /// Returns `None` if there is no such element.
    fn ceiling(&self, elem: &T) -> Option<T> {
        let mut tail = self.tail_set(elem, true);
        tail.first(false)
    }

    /// Returns the greatest element in this set less than or equal to `elem`.
    /// Returns `None` if there is no such element.
    fn floor(&self, elem: &T) -> Option<T> {
        let mut head = self.head_set(elem, true);
        head.last(false)
    }

    /// Returns the least element in this set strictly greater than `elem`.
    /// Returns `None` if there is no such element.
    fn higher(&self, elem: &T) -> Option<T> {
        let mut tail = self.tail_set(elem, false);
        tail.first(false)
    }

    /// Returns the greatest element in this set strictly less than `elem`.
    /// Returns `None` if there is no such element.
    fn lower(&self, elem: &T) -> Option<T> {
        let mut head = self.head_set(elem, false);
        head.first(false)
    }
}

macro_rules! sortedset_impl {
    ($typ:ty) => (
        fn first(&mut self, remove: bool) -> Option<T> {
            if self.is_empty() { return None }

            let ret = self.iter().min().unwrap().clone();
            if remove {
                self.remove(&ret);
            }
            Some(ret)
        }

        fn last(&mut self, remove: bool) -> Option<T> {
            if self.is_empty() { return None }

            let ret = self.iter().max().unwrap().clone();
            if remove {
                self.remove(&ret);
            }
            Some(ret)
        }

        fn head_set(&self, elem: &T, inclusive: bool) -> $typ {
            if inclusive {
                return self.iter().cloned().filter(|x| x <= elem).collect();
            } else {
                return self.iter().cloned().filter(|x| x < elem).collect();
            }
        }

        fn sub_set(&self, from_elem: &T, from_inclusive: bool, to_elem: &T, to_inclusive:bool) -> $typ {
            assert!(from_elem <= to_elem);

            if from_inclusive && to_inclusive {
                return self.iter().cloned().filter(|x| x >= from_elem && x <= to_elem).collect();
            } else if from_inclusive && !to_inclusive {
                return self.iter().cloned().filter(|x| x >= from_elem && x < to_elem).collect();
            } else if !from_inclusive && to_inclusive {
                return self.iter().cloned().filter(|x| x > from_elem && x <= to_elem).collect();
            } else {
                return self.iter().cloned().filter(|x| x > from_elem && x < to_elem).collect();
            }
        }

        fn tail_set(&self, elem: &T, inclusive: bool) -> $typ {
            if inclusive {
                return self.iter().cloned().filter(|x| x >= elem).collect();
            } else {
                return self.iter().cloned().filter(|x| x > elem).collect();
            }
        }
    );
}

impl<T> SortedSet<T> for BTreeSet<T>
    where T: Clone + Ord {
    sortedset_impl!(BTreeSet<T>);
}
impl<T, S, H> SortedSet<T> for HashSet<T, S>
    where T: Clone + Eq + Hash<H> + Ord,
          S: HashState<Hasher=H> + Default,
          H: Hasher<Output=u64> {
    sortedset_impl!(HashSet<T, S>);
}

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

    use std::collections::BTreeSet;

    #[test]
    fn test_first_noremove() {
        let mut set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        assert_eq!(set.first(false).unwrap(), 1u32);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
    }

    #[test]
    fn test_first_remove() {
        let mut set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        assert_eq!(set.first(true).unwrap(), 1u32);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![2u32, 3, 4, 5]);
    }

    #[test]
    fn test_last_noremove() {
        let mut set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        assert_eq!(set.last(false).unwrap(), 5u32);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
    }

    #[test]
    fn test_last_remove() {
        let mut set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        assert_eq!(set.last(true).unwrap(), 5u32);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4]);
    }

    #[test]
    fn test_head_set_noinclusive() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let head_set = set.head_set(&3, false);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(head_set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2]);
    }

    #[test]
    fn test_head_set_inclusive() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let head_set = set.head_set(&3, true);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(head_set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3]);

    }

    #[test]
    fn test_sub_set_noinclusive() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let sub_set = set.sub_set(&2, false, &4, false);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(sub_set.into_iter().collect::<Vec<u32>>(), vec![3u32]);
    }

    #[test]
    fn test_sub_set_nofrom_to() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let sub_set = set.sub_set(&2, false, &4, true);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(sub_set.into_iter().collect::<Vec<u32>>(), vec![3u32, 4]);
    }

    #[test]
    fn test_sub_set_from_noto() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let sub_set = set.sub_set(&2, true, &4, false);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(sub_set.into_iter().collect::<Vec<u32>>(), vec![2u32, 3]);
    }

    #[test]
    fn test_sub_set_inclusive() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let sub_set = set.sub_set(&2, true, &4, true);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(sub_set.into_iter().collect::<Vec<u32>>(), vec![2u32, 3, 4]);
    }

    #[test]
    fn test_tail_set_noinclusive() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let tail_set = set.tail_set(&3, false);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(tail_set.into_iter().collect::<Vec<u32>>(), vec![4u32, 5]);
    }

    #[test]
    fn test_tail_set_inclusive() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let tail_set = set.tail_set(&3, true);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(tail_set.into_iter().collect::<Vec<u32>>(), vec![3u32, 4, 5]);
    }
}
<commit_msg>Add more tests (and a bugfix!!)<commit_after>use std::collections::{BTreeSet, HashSet};
use std::collections::hash_state::HashState;
use std::default::Default;
use std::hash::{Hash, Hasher};

/// An extension trait for a `Set` whose elements have a defined total ordering.
/// This trait provides convenience methods which take advantage of the set's ordering.
pub trait SortedSet<T> : Sized
    where T: Clone + Ord {
    /// Returns the first (lowest) element currently in this set and optionally removes it
    /// from the set.
    /// Returns `None` if this set is empty.
    fn first(&mut self, remove: bool) -> Option<T>;

    /// Returns the last (highest) element current in this set and optionally removes it
    /// from the set.
    /// Returns `None` if this set is empty.
    fn last(&mut self, remove: bool) -> Option<T>;

    /// Returns the elements of this set which are less than (or equal to, if `inclusive`
    /// is true) `elem`, as a new instance of the same type of set.
    fn head_set(&self, elem: &T, inclusive: bool) -> Self;

    /// Returns the elements of this set ranging from `from_elem` to `to_elem`, as
    /// a new instance of the same type of set.
    fn sub_set(&self, from_elem: &T, from_inclusive: bool, to_elem: &T, to_inclusive: bool) -> Self;

    /// Returns the elements of this set which are greater than (or equal to, if
    /// `inclusive` is true) `elem`, as a new instance of the same type of set.
    fn tail_set(&self, elem: &T, inclusive: bool) -> Self;

    /// Returns the least element in this set greater than or equal to `elem`.
    /// Returns `None` if there is no such element.
    fn ceiling(&self, elem: &T) -> Option<T> {
        let mut tail = self.tail_set(elem, true);
        tail.first(false)
    }

    /// Returns the greatest element in this set less than or equal to `elem`.
    /// Returns `None` if there is no such element.
    fn floor(&self, elem: &T) -> Option<T> {
        let mut head = self.head_set(elem, true);
        head.last(false)
    }

    /// Returns the least element in this set strictly greater than `elem`.
    /// Returns `None` if there is no such element.
    fn higher(&self, elem: &T) -> Option<T> {
        let mut tail = self.tail_set(elem, false);
        tail.first(false)
    }

    /// Returns the greatest element in this set strictly less than `elem`.
    /// Returns `None` if there is no such element.
    fn lower(&self, elem: &T) -> Option<T> {
        let mut head = self.head_set(elem, false);
        head.last(false)
    }
}

macro_rules! sortedset_impl {
    ($typ:ty) => (
        fn first(&mut self, remove: bool) -> Option<T> {
            if self.is_empty() { return None }

            let ret = self.iter().min().unwrap().clone();
            if remove {
                self.remove(&ret);
            }
            Some(ret)
        }

        fn last(&mut self, remove: bool) -> Option<T> {
            if self.is_empty() { return None }

            let ret = self.iter().max().unwrap().clone();
            if remove {
                self.remove(&ret);
            }
            Some(ret)
        }

        fn head_set(&self, elem: &T, inclusive: bool) -> $typ {
            if inclusive {
                return self.iter().cloned().filter(|x| x <= elem).collect();
            } else {
                return self.iter().cloned().filter(|x| x < elem).collect();
            }
        }

        fn sub_set(&self, from_elem: &T, from_inclusive: bool, to_elem: &T, to_inclusive:bool) -> $typ {
            assert!(from_elem <= to_elem);

            if from_inclusive && to_inclusive {
                return self.iter().cloned().filter(|x| x >= from_elem && x <= to_elem).collect();
            } else if from_inclusive && !to_inclusive {
                return self.iter().cloned().filter(|x| x >= from_elem && x < to_elem).collect();
            } else if !from_inclusive && to_inclusive {
                return self.iter().cloned().filter(|x| x > from_elem && x <= to_elem).collect();
            } else {
                return self.iter().cloned().filter(|x| x > from_elem && x < to_elem).collect();
            }
        }

        fn tail_set(&self, elem: &T, inclusive: bool) -> $typ {
            if inclusive {
                return self.iter().cloned().filter(|x| x >= elem).collect();
            } else {
                return self.iter().cloned().filter(|x| x > elem).collect();
            }
        }
    );
}

impl<T> SortedSet<T> for BTreeSet<T>
    where T: Clone + Ord {
    sortedset_impl!(BTreeSet<T>);
}
impl<T, S, H> SortedSet<T> for HashSet<T, S>
    where T: Clone + Eq + Hash<H> + Ord,
          S: HashState<Hasher=H> + Default,
          H: Hasher<Output=u64> {
    sortedset_impl!(HashSet<T, S>);
}

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

    use std::collections::BTreeSet;

    #[test]
    fn test_first_noremove() {
        let mut set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        assert_eq!(set.first(false).unwrap(), 1u32);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
    }

    #[test]
    fn test_first_remove() {
        let mut set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        assert_eq!(set.first(true).unwrap(), 1u32);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![2u32, 3, 4, 5]);
    }

    #[test]
    fn test_last_noremove() {
        let mut set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        assert_eq!(set.last(false).unwrap(), 5u32);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
    }

    #[test]
    fn test_last_remove() {
        let mut set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        assert_eq!(set.last(true).unwrap(), 5u32);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4]);
    }

    #[test]
    fn test_head_set_noinclusive() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let head_set = set.head_set(&3, false);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(head_set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2]);
    }

    #[test]
    fn test_head_set_inclusive() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let head_set = set.head_set(&3, true);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(head_set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3]);

    }

    #[test]
    fn test_sub_set_noinclusive() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let sub_set = set.sub_set(&2, false, &4, false);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(sub_set.into_iter().collect::<Vec<u32>>(), vec![3u32]);
    }

    #[test]
    fn test_sub_set_nofrom_to() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let sub_set = set.sub_set(&2, false, &4, true);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(sub_set.into_iter().collect::<Vec<u32>>(), vec![3u32, 4]);
    }

    #[test]
    fn test_sub_set_from_noto() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let sub_set = set.sub_set(&2, true, &4, false);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(sub_set.into_iter().collect::<Vec<u32>>(), vec![2u32, 3]);
    }

    #[test]
    fn test_sub_set_inclusive() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let sub_set = set.sub_set(&2, true, &4, true);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(sub_set.into_iter().collect::<Vec<u32>>(), vec![2u32, 3, 4]);
    }

    #[test]
    fn test_tail_set_noinclusive() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let tail_set = set.tail_set(&3, false);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(tail_set.into_iter().collect::<Vec<u32>>(), vec![4u32, 5]);
    }

    #[test]
    fn test_tail_set_inclusive() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let tail_set = set.tail_set(&3, true);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
        assert_eq!(tail_set.into_iter().collect::<Vec<u32>>(), vec![3u32, 4, 5]);
    }

    #[test]
    fn test_ceiling() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        assert_eq!(set.ceiling(&3).unwrap(), 3);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
    }

    #[test]
    fn test_floor() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        assert_eq!(set.floor(&3).unwrap(), 3);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
    }

    #[test]
    fn test_higher() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        assert_eq!(set.higher(&3).unwrap(), 4);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
    }

    #[test]
    fn test_lower() {
        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        assert_eq!(set.lower(&3).unwrap(), 2);
        assert_eq!(set.into_iter().collect::<Vec<u32>>(), vec![1u32, 2, 3, 4, 5]);
    }
}
<|endoftext|>


<commit_before>use super::coordinate::Coordinate;
use super::distance::Distance;

pub struct Point<T> {
   x: T,
   y: T
}

impl<T> Point<T> where T: Coordinate {
   pub fn new(x: T, y: T) -> Self {
      Point {
         x: x,
         y: y
      }
   }

}

impl<T> Distance<Point<T>, T> for Point<T> where T: Coordinate {
   fn distance(&self, other: &Self) -> T {
      let x = other.x - self.x;
      let y = other.y - self.y;
      return (x * x + y * y).sqrt()
   }
}

#[cfg(test)]
mod tests {
   use test::{Bencher, black_box};

   use super::super::distance::Distance;

   use super::*;

   #[bench]
   fn bench_distance_f64(b: &mut Bencher) {
      let p1 = Point::new(5_f64, 7_f64);
      let p2 = Point::new(3_f64, 2_f64);
      b.iter(|| {
         for _ in 0..black_box(1000) {
            p1.distance(&p2);
         }
      });
   }

   #[bench]
   fn bench_distance_f32(b: &mut Bencher) {
      let p1 = Point::new(5_f32, 7_f32);
      let p2 = Point::new(3_f32, 2_f32);
      b.iter(|| {
         for _ in 0..black_box(1000) {
            p1.distance(&p2);
         }
      });
   }
}
<commit_msg>Formatting adjustment<commit_after>use super::coordinate::Coordinate;
use super::distance::Distance;

pub struct Point<T> {
   x: T,
   y: T
}

impl<T> Point<T> where T: Coordinate {
   pub fn new(x: T, y: T) -> Self {
      Point {
         x: x,
         y: y
      }
   }
}

impl<T> Distance<Point<T>, T> for Point<T> where T: Coordinate {
   fn distance(&self, other: &Self) -> T {
      let x = other.x - self.x;
      let y = other.y - self.y;
      return (x * x + y * y).sqrt()
   }
}

#[cfg(test)]
mod tests {
   use test::{Bencher, black_box};

   use super::super::distance::Distance;

   use super::*;

   #[bench]
   fn bench_distance_f64(b: &mut Bencher) {
      let p1 = Point::new(5_f64, 7_f64);
      let p2 = Point::new(3_f64, 2_f64);
      b.iter(|| {
         for _ in 0..black_box(1000) {
            p1.distance(&p2);
         }
      });
   }

   #[bench]
   fn bench_distance_f32(b: &mut Bencher) {
      let p1 = Point::new(5_f32, 7_f32);
      let p2 = Point::new(3_f32, 2_f32);
      b.iter(|| {
         for _ in 0..black_box(1000) {
            p1.distance(&p2);
         }
      });
   }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct PagedData<T> {
    pub size: u32,
    pub limit: u32,
    #[serde(rename="isLastPage")]
    pub is_last_page: bool,
    pub values: Vec<T>,
    pub start: u32,
    #[serde(rename="nextPageStart")]
    pub next_page_start: Option<u32>,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct Project {
    pub id: u32,
    pub key: String,
    pub name: String,
    pub public: bool,
    pub description: Option<String>,
    #[serde(rename="type")]
    pub _type: String,
    pub link: Link,
    pub links: HashMap<String, Vec<LinkHref>>,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct Ref {
    pub id: String,
    pub repository: Repository,
    #[serde(rename="displayId")]
    pub display_id: String,
    #[serde(rename="latestChangeset")]
    pub latest_changeset: String,
    #[serde(rename="latestCommit")]
    pub latest_commit: String,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct Repository {
    pub id: u32,
    pub slug: String,
    pub name: String,
    #[serde(rename="scmId")]
    pub scm_id: String,
    pub state: String,
    #[serde(rename="statusMessage")]
    pub status_message: String,
    pub forkable: bool,
    pub project: Project,
    pub public: bool,
    pub link: Link,
    #[serde(rename="cloneUrl")]
    pub clone_url: String,
    pub links: HashMap<String, Vec<LinkHref>>,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct User {
    pub name: String,
    #[serde(rename="emailAddress")]
    pub email_address: String,
    pub id: u32,
    #[serde(rename="displayName")]
    pub display_name: String,
    pub active: bool,
    pub slug: String,
    #[serde(rename="type")]
    pub _type: String,
    pub link: Link,
    pub links: HashMap<String, Vec<LinkHref>>,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct Author {
    pub user: User,
    pub role: String,
    pub approved: bool,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct Link {
    pub url: String,
    pub rel: String,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct LinkHref {
    pub href: String,
    pub name: Option<String>,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct PullRequest {
    pub id: u32,
    pub version: u32,
    pub title: String,
    pub description: Option<String>,
    pub state: String,
    pub open: bool,
    pub closed: bool,
    #[serde(rename="createdDate")]
    pub created_date: u64,
    #[serde(rename="updatedDate")]
    pub updated_date: u64,
    #[serde(rename="fromRef")]
    pub from_ref: Ref,
    #[serde(rename="toRef")]
    pub to_ref: Ref,
    pub author: Author,
    pub locked: bool,
    pub reviewers: Vec<Author>,
    pub participants: Vec<Author>,
    pub attributes: HashMap<String, Vec<String>>,
    pub link: Link,
    pub links: HashMap<String, Vec<LinkHref>>,
}
<commit_msg>Fix some fields that didn't match Stash's API<commit_after>use std::collections::HashMap;

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct PagedData<T> {
    pub size: u32,
    pub limit: u32,
    #[serde(rename="isLastPage")]
    pub is_last_page: bool,
    pub values: Vec<T>,
    pub start: u32,
    #[serde(rename="nextPageStart")]
    pub next_page_start: Option<u32>,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct Project {
    pub id: u32,
    pub key: String,
    pub name: String,
    pub public: Option<bool>,
    pub description: Option<String>,
    #[serde(rename="type")]
    pub _type: String,
    pub owner: Option<User>,
    pub link: Link,
    pub links: HashMap<String, Vec<LinkHref>>,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct Ref {
    pub id: String,
    pub repository: Repository,
    #[serde(rename="displayId")]
    pub display_id: String,
    #[serde(rename="latestChangeset")]
    pub latest_changeset: String,
    #[serde(rename="latestCommit")]
    pub latest_commit: String,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct Repository {
    pub id: u32,
    pub slug: String,
    pub name: String,
    #[serde(rename="scmId")]
    pub scm_id: String,
    pub state: String,
    #[serde(rename="statusMessage")]
    pub status_message: String,
    pub forkable: bool,
    pub origin: Option<Box<Repository>>,
    pub project: Project,
    pub public: bool,
    pub link: Link,
    #[serde(rename="cloneUrl")]
    pub clone_url: String,
    pub links: HashMap<String, Vec<LinkHref>>,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct User {
    pub name: String,
    #[serde(rename="emailAddress")]
    pub email_address: Option<String>,
    pub id: u32,
    #[serde(rename="displayName")]
    pub display_name: String,
    pub active: bool,
    pub slug: String,
    #[serde(rename="type")]
    pub _type: String,
    pub link: Link,
    pub links: HashMap<String, Vec<LinkHref>>,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct Author {
    pub user: User,
    pub role: String,
    pub approved: bool,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct Link {
    pub url: String,
    pub rel: String,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct LinkHref {
    pub href: String,
    pub name: Option<String>,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct PullRequest {
    pub id: u32,
    pub version: u32,
    pub title: String,
    pub description: Option<String>,
    pub state: String,
    pub open: bool,
    pub closed: bool,
    #[serde(rename="createdDate")]
    pub created_date: u64,
    #[serde(rename="updatedDate")]
    pub updated_date: u64,
    #[serde(rename="fromRef")]
    pub from_ref: Ref,
    #[serde(rename="toRef")]
    pub to_ref: Ref,
    pub author: Author,
    pub locked: bool,
    pub reviewers: Vec<Author>,
    pub participants: Vec<Author>,
    pub attributes: HashMap<String, Vec<String>>,
    pub link: Link,
    pub links: HashMap<String, Vec<LinkHref>>,
}
<|endoftext|>


<commit_before>
use BuildQuery;
use Groups;

pub mod owned_groups;

// https://docs.gitlab.com/ce/api/groups.html
// List groups:                 GET /groups
// List owned groups:           GET /groups/owned
// List a group's projects:     GET /groups/:id/projects
// Details of a group:          GET /groups/:id
// New group:                   POST /groups
// Transfer project to group:   POST  /groups/:id/projects/:project_id
// Update group:                PUT /groups/:id
// Remove group:                DELETE /groups/:id
// Search for group:            GET /groups?search=foobar

// https://docs.gitlab.com/ce/api/groups.html#list-groups

#[derive(Debug, Copy, Clone)]
pub enum ListingOrderBy {
    Name,
    Path,
}

#[derive(Debug, Copy, Clone)]
pub enum ListingSort {
    Asc,
    Desc,
}

fn append_group_lister_options_order_by(order_by: ListingOrderBy, s: &mut String) {
    s.push_str(match order_by {
        ListingOrderBy::Name => "name",
        ListingOrderBy::Path => "path",
    });
}

fn append_group_lister_options_sort(order_by: ListingSort, s: &mut String) {
    s.push_str(match order_by {
        ListingSort::Asc => "asc",
        ListingSort::Desc => "desc",
    });
}

/// https://docs.gitlab.com/ce/api/groups.html#list-groups
#[derive(Default, Debug, Clone)]
pub struct Listing {
    /// Skip the group IDs passes
    skip_groups: Vec<i64>,
    /// Show all the groups you have access to
    all_available: Option<bool>,
    /// Return list of authorized groups matching the search criteria
    search: String,
    /// Order groups by `name` or `path`. Default is `name`
    order_by: Option<ListingOrderBy>,
    /// Order groups in `asc` or `desc` order. Default is `asc`
    sort: Option<ListingSort>,
}

impl Listing {
    pub fn new() -> Listing {
        Default::default()
    }
    pub fn skip_groups(&mut self, skip_groups: Vec<i64>) -> &mut Listing {
        self.skip_groups = skip_groups;
        self
    }
    pub fn all_available(&mut self, all_available: bool) -> &mut Listing {
        self.all_available = Some(all_available);
        self
    }
    pub fn search(&mut self, search: String) -> &mut Listing {
        self.search = search;
        self
    }
    pub fn order_by(&mut self, order_by: ListingOrderBy) -> &mut Listing {
        self.order_by = Some(order_by);
        self
    }
    fn sort(&mut self, sort: ListingSort) -> &mut Listing {
        self.sort = Some(sort);
        self
    }
}

impl BuildQuery for Listing {
    fn build_query(&self) -> String {

        let mut query = String::from("groups");

        let amp_char = "&";
        let none_char = "";
        let mut split_char = &none_char;

        // Append a "?", only if one of the `Option` is `Some(_)`
        query.push_str(match (self.skip_groups.is_empty(),
                              &self.all_available,
                              self.search.is_empty(),
                              &self.order_by,
                              &self.sort) {
            (true, &None, true, &None, &None) => "",
            _ => "?",
        });

        if !self.skip_groups.is_empty() {
            query.push_str(&split_char);
            split_char = &amp_char;

            let mut array_split_char = &none_char;
            for skip_group in &self.skip_groups {
                query.push_str(array_split_char);
                query.push_str("skip_groups[]=");
                query.push_str(&skip_group.to_string());
                array_split_char = &amp_char;
            }
        }

        self.all_available.map(|all_available| {
            query.push_str(&split_char);
            split_char = &amp_char;

            if all_available {
                query.push_str("all_available=true")
            } else {
                query.push_str("all_available=false")
            }
        });

        if !self.search.is_empty() {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("search=");
            query.push_str(&self.search);
        }

        self.order_by.map(|order_by| {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("order_by=");
            append_group_lister_options_order_by(order_by, &mut query);
        });

        self.sort.map(|sort| {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("sort=");
            append_group_lister_options_sort(sort, &mut query);
        });

        query
    }
}

#[test]
fn test_append_group_lister_options_order_by() {
    let expected_string = "Initialnamepathpathname";

    let mut s = String::from("Initial");

    append_group_lister_options_order_by(ListingOrderBy::Name, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Path, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Path, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Name, &mut s);

    assert_eq!(s, expected_string);
}

#[test]
fn test_append_group_lister_options_sort() {
    let expected_string = "Initialascdescascdesc";

    let mut s = String::from("Initial");

    append_group_lister_options_sort(ListingSort::Asc, &mut s);
    append_group_lister_options_sort(ListingSort::Desc, &mut s);
    append_group_lister_options_sort(ListingSort::Asc, &mut s);
    append_group_lister_options_sort(ListingSort::Desc, &mut s);

    assert_eq!(s, expected_string);
}

#[test]
fn groups_build_query_default() {
    let expected_string = "groups";
    let listing: Listing = Default::default();
    let query = listing.build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups";
    let listing = Listing::new();
    let query = listing.build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_skip_groups() {
    let expected_string = "groups?skip_groups[]=1&skip_groups[]=2&skip_groups[]=3";
    let query = Listing::new().skip_groups(vec![1,2,3]).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_all_available() {
    let expected_string = "groups?all_available=true";
    let query = Listing::new().all_available(true).build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups?all_available=false";
    let query = Listing::new().all_available(false).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_search() {
    let expected_string = "groups?search=SearchPattern";
    let query = Listing::new().search(String::from("SearchPattern")).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_order_by_name() {
    let expected_string = "groups?order_by=name";
    let query = Listing::new().order_by(ListingOrderBy::Name).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_order_by_path() {
    let expected_string = "groups?order_by=path";
    let query = Listing::new().order_by(ListingOrderBy::Path).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_sort() {
    let expected_string = "groups?sort=asc";
    let query = Listing::new().sort(ListingSort::Asc).build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups?sort=desc";
    let query = Listing::new().sort(ListingSort::Desc).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_search_order_by_path() {
    let expected_string = "groups?search=SearchPattern&order_by=path";
    let query = Listing::new().order_by(ListingOrderBy::Path).search(String::from("SearchPattern")).build_query();
    assert_eq!(query, expected_string);
    let query = Listing::new().search(String::from("SearchPattern")).order_by(ListingOrderBy::Path).build_query();
    assert_eq!(query, expected_string);
}
<commit_msg>Cleanup<commit_after>
use BuildQuery;

pub mod owned_groups;

// https://docs.gitlab.com/ce/api/groups.html
// List groups:                 GET /groups
// List owned groups:           GET /groups/owned
// List a group's projects:     GET /groups/:id/projects
// Details of a group:          GET /groups/:id
// New group:                   POST /groups
// Transfer project to group:   POST  /groups/:id/projects/:project_id
// Update group:                PUT /groups/:id
// Remove group:                DELETE /groups/:id
// Search for group:            GET /groups?search=foobar

// https://docs.gitlab.com/ce/api/groups.html#list-groups

#[derive(Debug, Copy, Clone)]
pub enum ListingOrderBy {
    Name,
    Path,
}

#[derive(Debug, Copy, Clone)]
pub enum ListingSort {
    Asc,
    Desc,
}

fn append_group_lister_options_order_by(order_by: ListingOrderBy, s: &mut String) {
    s.push_str(match order_by {
        ListingOrderBy::Name => "name",
        ListingOrderBy::Path => "path",
    });
}

fn append_group_lister_options_sort(order_by: ListingSort, s: &mut String) {
    s.push_str(match order_by {
        ListingSort::Asc => "asc",
        ListingSort::Desc => "desc",
    });
}

/// https://docs.gitlab.com/ce/api/groups.html#list-groups
#[derive(Default, Debug, Clone)]
pub struct Listing {
    /// Skip the group IDs passes
    skip_groups: Vec<i64>,
    /// Show all the groups you have access to
    all_available: Option<bool>,
    /// Return list of authorized groups matching the search criteria
    search: String,
    /// Order groups by `name` or `path`. Default is `name`
    order_by: Option<ListingOrderBy>,
    /// Order groups in `asc` or `desc` order. Default is `asc`
    sort: Option<ListingSort>,
}

impl Listing {
    pub fn new() -> Listing {
        Default::default()
    }
    pub fn skip_groups(&mut self, skip_groups: Vec<i64>) -> &mut Listing {
        self.skip_groups = skip_groups;
        self
    }
    pub fn all_available(&mut self, all_available: bool) -> &mut Listing {
        self.all_available = Some(all_available);
        self
    }
    pub fn search(&mut self, search: String) -> &mut Listing {
        self.search = search;
        self
    }
    pub fn order_by(&mut self, order_by: ListingOrderBy) -> &mut Listing {
        self.order_by = Some(order_by);
        self
    }
    fn sort(&mut self, sort: ListingSort) -> &mut Listing {
        self.sort = Some(sort);
        self
    }
}

impl BuildQuery for Listing {
    fn build_query(&self) -> String {

        let mut query = String::from("groups");

        let amp_char = "&";
        let none_char = "";
        let mut split_char = &none_char;

        // Append a "?", only if one of the `Option` is `Some(_)`
        query.push_str(match (self.skip_groups.is_empty(),
                              &self.all_available,
                              self.search.is_empty(),
                              &self.order_by,
                              &self.sort) {
            (true, &None, true, &None, &None) => "",
            _ => "?",
        });

        if !self.skip_groups.is_empty() {
            query.push_str(&split_char);
            split_char = &amp_char;

            let mut array_split_char = &none_char;
            for skip_group in &self.skip_groups {
                query.push_str(array_split_char);
                query.push_str("skip_groups[]=");
                query.push_str(&skip_group.to_string());
                array_split_char = &amp_char;
            }
        }

        self.all_available.map(|all_available| {
            query.push_str(&split_char);
            split_char = &amp_char;

            if all_available {
                query.push_str("all_available=true")
            } else {
                query.push_str("all_available=false")
            }
        });

        if !self.search.is_empty() {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("search=");
            query.push_str(&self.search);
        }

        self.order_by.map(|order_by| {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("order_by=");
            append_group_lister_options_order_by(order_by, &mut query);
        });

        self.sort.map(|sort| {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("sort=");
            append_group_lister_options_sort(sort, &mut query);
        });

        query
    }
}

#[test]
fn test_append_group_lister_options_order_by() {
    let expected_string = "Initialnamepathpathname";

    let mut s = String::from("Initial");

    append_group_lister_options_order_by(ListingOrderBy::Name, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Path, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Path, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Name, &mut s);

    assert_eq!(s, expected_string);
}

#[test]
fn test_append_group_lister_options_sort() {
    let expected_string = "Initialascdescascdesc";

    let mut s = String::from("Initial");

    append_group_lister_options_sort(ListingSort::Asc, &mut s);
    append_group_lister_options_sort(ListingSort::Desc, &mut s);
    append_group_lister_options_sort(ListingSort::Asc, &mut s);
    append_group_lister_options_sort(ListingSort::Desc, &mut s);

    assert_eq!(s, expected_string);
}

#[test]
fn groups_build_query_default() {
    let expected_string = "groups";
    let listing: Listing = Default::default();
    let query = listing.build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups";
    let listing = Listing::new();
    let query = listing.build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_skip_groups() {
    let expected_string = "groups?skip_groups[]=1&skip_groups[]=2&skip_groups[]=3";
    let query = Listing::new().skip_groups(vec![1,2,3]).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_all_available() {
    let expected_string = "groups?all_available=true";
    let query = Listing::new().all_available(true).build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups?all_available=false";
    let query = Listing::new().all_available(false).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_search() {
    let expected_string = "groups?search=SearchPattern";
    let query = Listing::new().search(String::from("SearchPattern")).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_order_by_name() {
    let expected_string = "groups?order_by=name";
    let query = Listing::new().order_by(ListingOrderBy::Name).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_order_by_path() {
    let expected_string = "groups?order_by=path";
    let query = Listing::new().order_by(ListingOrderBy::Path).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_sort() {
    let expected_string = "groups?sort=asc";
    let query = Listing::new().sort(ListingSort::Asc).build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups?sort=desc";
    let query = Listing::new().sort(ListingSort::Desc).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_search_order_by_path() {
    let expected_string = "groups?search=SearchPattern&order_by=path";
    let query = Listing::new().order_by(ListingOrderBy::Path).search(String::from("SearchPattern")).build_query();
    assert_eq!(query, expected_string);
    let query = Listing::new().search(String::from("SearchPattern")).order_by(ListingOrderBy::Path).build_query();
    assert_eq!(query, expected_string);
}
<|endoftext|>


<commit_before>//! Headers container, and common header fields.
//!
//! hyper has the opinion that Headers should be strongly-typed, because that's
//! why we're using Rust in the first place. To set or get any header, an object
//! must implement the `Header` trait from this module. Several common headers
//! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others.
use std::ascii::OwnedAsciiExt;
use std::char::is_lowercase;
use std::fmt::{mod, Show};
use std::mem::{transmute, transmute_copy};
use std::raw::TraitObject;
use std::str::{from_utf8, SendStr, Slice, Owned};
use std::string::raw;
use std::collections::hashmap::{HashMap, Entries};

use uany::UncheckedAnyDowncast;

use http::read_header;
use {HttpResult};

/// Common Headers
pub mod common;

/// A trait for any object that will represent a header field and value.
pub trait Header: 'static {
    /// Returns the name of the header field this belongs to.
    ///
    /// The market `Option` is to hint to the type system which implementation
    /// to call. This can be done away with once UFCS arrives.
    fn header_name(marker: Option<Self>) -> &'static str;
    /// Parse a header from a raw stream of bytes.
    ///
    /// It's possible that a request can include a header field more than once,
    /// and in that case, the slice will have a length greater than 1. However,
    /// it's not necessarily the case that a Header is *allowed* to have more
    /// than one field value. If that's the case, you **should** return `None`
    /// if `raw.len() > 1`.
    fn parse_header(raw: &[Vec<u8>]) -> Option<Self>;
    /// Format a header to be output into a TcpStream.
    fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result;
}

impl<'a> UncheckedAnyDowncast<'a> for &'a Header + 'a {
    #[inline]
    unsafe fn downcast_ref_unchecked<T: 'static>(self) -> &'a T {
        let to: TraitObject = transmute_copy(&self);
        transmute(to.data)
    }
}

fn header_name<T: Header>() -> &'static str {
    let name = Header::header_name(None::<T>);
    debug_assert!(name.as_slice().chars().all(|c| c == '-' || is_lowercase(c)),
        "Header names should be lowercase: {}", name);
    name
}

/// A map of header fields on requests and responses.
pub struct Headers {
    data: HashMap<SendStr, Item>
}

impl Headers {

    /// Creates a new, empty headers map.
    pub fn new() -> Headers {
        Headers {
            data: HashMap::new()
        }
    }

    #[doc(hidden)]
    pub fn from_raw<R: Reader>(rdr: &mut R) -> HttpResult<Headers> {
        let mut headers = Headers::new();
        loop {
            match try!(read_header(rdr)) {
                Some((name, value)) => {
                    // read_header already checks that name is a token, which
                    // means its safe utf8
                    let name = unsafe {
                        raw::from_utf8(name)
                    }.into_ascii_lower();
                    match headers.data.find_or_insert(Owned(name), Raw(vec![])) {
                        &Raw(ref mut pieces) => pieces.push(value),
                        // at this point, Raw is the only thing that has been inserted
                        _ => unreachable!()
                    }
                },
                None => break,
            }
        }
        Ok(headers)
    }

    /// Set a header field to the corresponding value.
    ///
    /// The field is determined by the type of the value being set.
    pub fn set<H: Header>(&mut self, value: H) {
        self.data.insert(Slice(header_name::<H>()), Typed(box value));
    }

    /// Get a clone of the header field's value, if it exists.
    ///
    /// Example:
    ///
    /// ```
    /// # use hyper::header::Headers;
    /// # use hyper::header::common::ContentType;
    /// # let mut headers = Headers::new();
    /// let content_type = headers.get::<ContentType>();
    /// ```
    pub fn get<H: Header + Clone>(&mut self) -> Option<H> {
        self.get_ref().map(|v: &H| v.clone())
    }

    /// Access the raw value of a header, if it exists and has not
    /// been already parsed.
    ///
    /// If the header field has already been parsed into a typed header,
    /// then you *must* access it through that representation.
    ///
    /// Example:
    /// ```
    /// # use hyper::header::Headers;
    /// # let mut headers = Headers::new();
    /// let raw_content_type = unsafe { headers.get_raw("content-type") };
    /// ```
    pub unsafe fn get_raw(&self, name: &'static str) -> Option<&[Vec<u8>]> {
        self.data.find(&Slice(name)).and_then(|item| {
            match *item {
                Raw(ref raw) => Some(raw.as_slice()),
                _ => None
            }
        })
    }

    /// Get a reference to the header field's value, if it exists.
    pub fn get_ref<H: Header>(&mut self) -> Option<&H> {
        self.data.find_mut(&Slice(header_name::<H>())).and_then(|item| {
            debug!("get_ref, name={}, val={}", header_name::<H>(), item);
            let header = match *item {
                Raw(ref raw) => match Header::parse_header(raw.as_slice()) {
                    Some::<H>(h) => {
                        h
                    },
                    None => return None
                },
                Typed(..) => return Some(item)
            };
            *item = Typed(box header as Box<Header>);
            Some(item)
        }).and_then(|item| {
            debug!("downcasting {}", item);
            let ret = match *item {
                Typed(ref val) => {
                    unsafe {
                        Some(val.downcast_ref_unchecked())
                    }
                },
                Raw(..) => unreachable!()
            };
            debug!("returning {}", ret.is_some());
            ret
        })
    }

    /// Returns a boolean of whether a certain header is in the map.
    ///
    /// Example:
    ///
    /// ```
    /// # use hyper::header::Headers;
    /// # use hyper::header::common::ContentType;
    /// # let mut headers = Headers::new();
    /// let has_type = headers.has::<ContentType>();
    /// ```
    pub fn has<H: Header>(&self) -> bool {
        self.data.contains_key(&Slice(header_name::<H>()))
    }

    /// Removes a header from the map, if one existed.
    /// Returns true if a header has been removed.
    pub fn remove<H: Header>(&mut self) -> bool {
        self.data.pop_equiv(&Header::header_name(None::<H>)).is_some()
    }

    /// Returns an iterator over the header fields.
    pub fn iter<'a>(&'a self) -> HeadersItems<'a> {
        HeadersItems {
            inner: self.data.iter()
        }
    }
}

impl fmt::Show for Headers {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!("Headers {\n".fmt(fmt));
        for (k, v) in self.iter() {
            try!(write!(fmt, "\t{}: {}\n", k, v));
        }
        "}".fmt(fmt)
    }
}

/// An `Iterator` over the fields in a `Headers` map.
pub struct HeadersItems<'a> {
    inner: Entries<'a, SendStr, Item>
}

impl<'a> Iterator<(&'a str, HeaderView<'a>)> for HeadersItems<'a> {
    fn next(&mut self) -> Option<(&'a str, HeaderView<'a>)> {
        match self.inner.next() {
            Some((k, v)) => Some((k.as_slice(), HeaderView(v))),
            None => None
        }
    }
}

/// Returned with the `HeadersItems` iterator.
pub struct HeaderView<'a>(&'a Item);

impl<'a> fmt::Show for HeaderView<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let HeaderView(item) = *self;
        item.fmt(fmt)
    }
}

impl Collection for Headers {
    fn len(&self) -> uint {
        self.data.len()
    }
}

impl Mutable for Headers {
    fn clear(&mut self) {
        self.data.clear()
    }
}

enum Item {
    Raw(Vec<Vec<u8>>),
    Typed(Box<Header>)
}

impl fmt::Show for Item {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Raw(ref v) => {
                for part in v.iter() {
                    try!(fmt.write(part.as_slice()));
                }
                Ok(())
            },
            Typed(ref h) => h.fmt_header(fmt)
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::MemReader;
    use mime::{Mime, Text, Plain};
    use super::{Headers, Header};
    use super::common::{ContentLength, ContentType};

    fn mem(s: &str) -> MemReader {
        MemReader::new(s.as_bytes().to_vec())
    }

    #[test]
    fn test_from_raw() {
        let mut headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
        assert_eq!(headers.get_ref(), Some(&ContentLength(10)));
    }

    #[test]
    fn test_content_type() {
        let content_type = Header::parse_header(["text/plain".as_bytes().to_vec()].as_slice());
        assert_eq!(content_type, Some(ContentType(Mime(Text, Plain, vec![]))));
    }
}
<commit_msg>adjust representation of internal Items<commit_after>//! Headers container, and common header fields.
//!
//! hyper has the opinion that Headers should be strongly-typed, because that's
//! why we're using Rust in the first place. To set or get any header, an object
//! must implement the `Header` trait from this module. Several common headers
//! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others.
use std::ascii::OwnedAsciiExt;
use std::char::is_lowercase;
use std::fmt::{mod, Show};
use std::intrinsics::TypeId;
use std::mem::{transmute, transmute_copy};
use std::raw::TraitObject;
use std::str::{from_utf8, SendStr, Slice, Owned};
use std::string::raw;
use std::collections::hashmap::{HashMap, Entries};

use uany::UncheckedAnyDowncast;

use http::read_header;
use {HttpResult};

/// Common Headers
pub mod common;

/// A trait for any object that will represent a header field and value.
pub trait Header: 'static {
    /// Returns the name of the header field this belongs to.
    ///
    /// The market `Option` is to hint to the type system which implementation
    /// to call. This can be done away with once UFCS arrives.
    fn header_name(marker: Option<Self>) -> &'static str;
    /// Parse a header from a raw stream of bytes.
    ///
    /// It's possible that a request can include a header field more than once,
    /// and in that case, the slice will have a length greater than 1. However,
    /// it's not necessarily the case that a Header is *allowed* to have more
    /// than one field value. If that's the case, you **should** return `None`
    /// if `raw.len() > 1`.
    fn parse_header(raw: &[Vec<u8>]) -> Option<Self>;
    /// Format a header to be output into a TcpStream.
    fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result;
}

impl<'a> UncheckedAnyDowncast<'a> for &'a Header + 'a {
    #[inline]
    unsafe fn downcast_ref_unchecked<T: 'static>(self) -> &'a T {
        let to: TraitObject = transmute_copy(&self);
        transmute(to.data)
    }
}

fn header_name<T: Header>() -> &'static str {
    let name = Header::header_name(None::<T>);
    debug_assert!(name.as_slice().chars().all(|c| c == '-' || is_lowercase(c)),
        "Header names should be lowercase: {}", name);
    name
}

/// A map of header fields on requests and responses.
pub struct Headers {
    data: HashMap<SendStr, Item>
}

impl Headers {

    /// Creates a new, empty headers map.
    pub fn new() -> Headers {
        Headers {
            data: HashMap::new()
        }
    }

    #[doc(hidden)]
    pub fn from_raw<R: Reader>(rdr: &mut R) -> HttpResult<Headers> {
        let mut headers = Headers::new();
        loop {
            match try!(read_header(rdr)) {
                Some((name, value)) => {
                    // read_header already checks that name is a token, which
                    // means its safe utf8
                    let name = unsafe {
                        raw::from_utf8(name)
                    }.into_ascii_lower();
                    let item = headers.data.find_or_insert(Owned(name), raw(vec![]));
                    item.raw.push(value);
                },
                None => break,
            }
        }
        Ok(headers)
    }

    /// Set a header field to the corresponding value.
    ///
    /// The field is determined by the type of the value being set.
    pub fn set<H: Header>(&mut self, value: H) {
        self.data.insert(Slice(header_name::<H>()), Item {
            raw: vec![],
            tid: Some(TypeId::of::<H>()),
            typed: Some(box value as Box<Header>)
        });
    }

    /// Get a clone of the header field's value, if it exists.
    ///
    /// Example:
    ///
    /// ```
    /// # use hyper::header::Headers;
    /// # use hyper::header::common::ContentType;
    /// # let mut headers = Headers::new();
    /// let content_type = headers.get::<ContentType>();
    /// ```
    pub fn get<H: Header + Clone>(&mut self) -> Option<H> {
        self.get_ref().map(|v: &H| v.clone())
    }

    /// Access the raw value of a header, if it exists and has not
    /// been already parsed.
    ///
    /// If the header field has already been parsed into a typed header,
    /// then you *must* access it through that representation.
    ///
    /// Example:
    /// ```
    /// # use hyper::header::Headers;
    /// # let mut headers = Headers::new();
    /// let raw_content_type = unsafe { headers.get_raw("content-type") };
    /// ```
    pub unsafe fn get_raw(&self, name: &'static str) -> Option<&[Vec<u8>]> {
        self.data.find(&Slice(name)).map(|item| {
            item.raw.as_slice()
        })
    }

    /// Get a reference to the header field's value, if it exists.
    pub fn get_ref<H: Header>(&mut self) -> Option<&H> {
        self.data.find_mut(&Slice(header_name::<H>())).and_then(|item| {
            debug!("get_ref, name={}, val={}", header_name::<H>(), item);
            let expected_tid = TypeId::of::<H>();
            let header = match item.tid {
                Some(tid) if tid == expected_tid => return Some(item),
                _ => match Header::parse_header(item.raw.as_slice()) {
                    Some::<H>(h) => {
                        h
                    },
                    None => return None
                },
            };
            item.typed = Some(box header as Box<Header>);
            item.tid = Some(expected_tid);
            Some(item)
        }).and_then(|item| {
            debug!("downcasting {}", item);
            let ret = match item.typed {
                Some(ref val) => {
                    unsafe {
                        Some(val.downcast_ref_unchecked())
                    }
                },
                None => unreachable!()
            };
            ret
        })
    }

    /// Returns a boolean of whether a certain header is in the map.
    ///
    /// Example:
    ///
    /// ```
    /// # use hyper::header::Headers;
    /// # use hyper::header::common::ContentType;
    /// # let mut headers = Headers::new();
    /// let has_type = headers.has::<ContentType>();
    /// ```
    pub fn has<H: Header>(&self) -> bool {
        self.data.contains_key(&Slice(header_name::<H>()))
    }

    /// Removes a header from the map, if one existed.
    /// Returns true if a header has been removed.
    pub fn remove<H: Header>(&mut self) -> bool {
        self.data.pop_equiv(&Header::header_name(None::<H>)).is_some()
    }

    /// Returns an iterator over the header fields.
    pub fn iter<'a>(&'a self) -> HeadersItems<'a> {
        HeadersItems {
            inner: self.data.iter()
        }
    }
}

impl fmt::Show for Headers {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!("Headers {\n".fmt(fmt));
        for (k, v) in self.iter() {
            try!(write!(fmt, "\t{}: {}\n", k, v));
        }
        "}".fmt(fmt)
    }
}

/// An `Iterator` over the fields in a `Headers` map.
pub struct HeadersItems<'a> {
    inner: Entries<'a, SendStr, Item>
}

impl<'a> Iterator<(&'a str, HeaderView<'a>)> for HeadersItems<'a> {
    fn next(&mut self) -> Option<(&'a str, HeaderView<'a>)> {
        match self.inner.next() {
            Some((k, v)) => Some((k.as_slice(), HeaderView(v))),
            None => None
        }
    }
}

/// Returned with the `HeadersItems` iterator.
pub struct HeaderView<'a>(&'a Item);

impl<'a> fmt::Show for HeaderView<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let HeaderView(item) = *self;
        item.fmt(fmt)
    }
}

impl Collection for Headers {
    fn len(&self) -> uint {
        self.data.len()
    }
}

impl Mutable for Headers {
    fn clear(&mut self) {
        self.data.clear()
    }
}

struct Item {
    raw: Vec<Vec<u8>>,
    tid: Option<TypeId>,
    typed: Option<Box<Header>>,
}

fn raw(parts: Vec<Vec<u8>>) -> Item {
    Item {
        raw: parts,
        tid: None,
        typed: None,
    }
}

impl fmt::Show for Item {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.typed {
            Some(ref h) => h.fmt_header(fmt),
            None => {
                for part in self.raw.iter() {
                    try!(fmt.write(part.as_slice()));
                }
                Ok(())
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::MemReader;
    use std::fmt;
    use mime::{Mime, Text, Plain};
    use super::{Headers, Header};
    use super::common::{ContentLength, ContentType};

    fn mem(s: &str) -> MemReader {
        MemReader::new(s.as_bytes().to_vec())
    }

    #[test]
    fn test_from_raw() {
        let mut headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
        assert_eq!(headers.get_ref(), Some(&ContentLength(10)));
    }

    #[test]
    fn test_content_type() {
        let content_type = Header::parse_header(["text/plain".as_bytes().to_vec()].as_slice());
        assert_eq!(content_type, Some(ContentType(Mime(Text, Plain, vec![]))));
    }

    #[deriving(Clone)]
    struct CrazyLength(Option<bool>, uint);

    impl Header for CrazyLength {
        fn header_name(_: Option<CrazyLength>) -> &'static str {
            "content-length"
        }
        fn parse_header(raw: &[Vec<u8>]) -> Option<CrazyLength> {
            use std::str::from_utf8;
            use std::from_str::FromStr;

            if raw.len() != 1 {
                return None;
            }
            // we JUST checked that raw.len() == 1, so raw[0] WILL exist.
            match from_utf8(unsafe { raw.as_slice().unsafe_get(0).as_slice() }) {
                Some(s) => FromStr::from_str(s),
                None => None
            }.map(|u| CrazyLength(Some(false), u))
        }
        fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            use std::fmt::Show;
            let CrazyLength(_, ref value) = *self;
            value.fmt(fmt)
        }
    }

    #[test]
    fn test_different_structs_for_same_header() {
        let mut headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
        let ContentLength(num) = headers.get::<ContentLength>().unwrap();
        let CrazyLength(_, crazy_num) = headers.get::<CrazyLength>().unwrap();
        assert_eq!(num, crazy_num);
    }
}
<|endoftext|>


<commit_before>//! Headers container, and common header fields.
//!
//! hyper has the opinion that Headers should be strongly-typed, because that's
//! why we're using Rust in the first place. To set or get any header, an object
//! must implement the `Header` trait from this module. Several common headers
//! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others.
use std::ascii::OwnedAsciiExt;
use std::char::is_lowercase;
use std::fmt::{mod, Show};
use std::intrinsics::TypeId;
use std::mem::{transmute, transmute_copy};
use std::raw::TraitObject;
use std::str::{from_utf8, SendStr, Slice, Owned};
use std::string::raw;
use std::collections::hashmap::{HashMap, Entries};

use uany::UncheckedAnyDowncast;
use typeable::Typeable;

use http::read_header;
use {HttpResult};

/// Common Headers
pub mod common;

/// A trait for any object that will represent a header field and value.
pub trait Header: Typeable {
    /// Returns the name of the header field this belongs to.
    ///
    /// The market `Option` is to hint to the type system which implementation
    /// to call. This can be done away with once UFCS arrives.
    fn header_name(marker: Option<Self>) -> &'static str;
    /// Parse a header from a raw stream of bytes.
    ///
    /// It's possible that a request can include a header field more than once,
    /// and in that case, the slice will have a length greater than 1. However,
    /// it's not necessarily the case that a Header is *allowed* to have more
    /// than one field value. If that's the case, you **should** return `None`
    /// if `raw.len() > 1`.
    fn parse_header(raw: &[Vec<u8>]) -> Option<Self>;
    /// Format a header to be output into a TcpStream.
    fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result;
}

#[doc(hidden)]
trait Is {
    fn is<T: 'static>(self) -> bool;
}

impl<'a> Is for &'a Header {
    fn is<T: 'static>(self) -> bool {
        self.get_type() == TypeId::of::<T>()
    }
}

impl<'a> UncheckedAnyDowncast<'a> for &'a Header {
    #[inline]
    unsafe fn downcast_ref_unchecked<T: 'static>(self) -> &'a T {
        let to: TraitObject = transmute_copy(&self);
        transmute(to.data)
    }
}

fn header_name<T: Header>() -> &'static str {
    let name = Header::header_name(None::<T>);
    debug_assert!(name.as_slice().chars().all(|c| c == '-' || is_lowercase(c)),
        "Header names should be lowercase: {}", name);
    name
}

/// A map of header fields on requests and responses.
pub struct Headers {
    data: HashMap<SendStr, Item>
}

impl Headers {

    /// Creates a new, empty headers map.
    pub fn new() -> Headers {
        Headers {
            data: HashMap::new()
        }
    }

    #[doc(hidden)]
    pub fn from_raw<R: Reader>(rdr: &mut R) -> HttpResult<Headers> {
        let mut headers = Headers::new();
        loop {
            match try!(read_header(rdr)) {
                Some((name, value)) => {
                    // read_header already checks that name is a token, which
                    // means its safe utf8
                    let name = unsafe {
                        raw::from_utf8(name)
                    }.into_ascii_lower();
                    let item = headers.data.find_or_insert(Owned(name), Raw(vec![]));
                    match *item {
                        Raw(ref mut raw) => raw.push(value),
                        // Unreachable
                        _ => {}
                    };
                },
                None => break,
            }
        }
        Ok(headers)
    }

    /// Set a header field to the corresponding value.
    ///
    /// The field is determined by the type of the value being set.
    pub fn set<H: Header>(&mut self, value: H) {
        self.data.insert(Slice(header_name::<H>()), Typed(box value as Box<Header>));
    }

    /// Get a clone of the header field's value, if it exists.
    ///
    /// Example:
    ///
    /// ```
    /// # use hyper::header::Headers;
    /// # use hyper::header::common::ContentType;
    /// # let mut headers = Headers::new();
    /// let content_type = headers.get::<ContentType>();
    /// ```
    pub fn get<H: Header + Clone>(&mut self) -> Option<H> {
        self.get_ref().map(|v: &H| v.clone())
    }

    /// Access the raw value of a header, if it exists and has not
    /// been already parsed.
    ///
    /// If the header field has already been parsed into a typed header,
    /// then you *must* access it through that representation.
    ///
    /// Example:
    /// ```
    /// # use hyper::header::Headers;
    /// # let mut headers = Headers::new();
    /// let raw_content_type = unsafe { headers.get_raw("content-type") };
    /// ```
    pub unsafe fn get_raw(&self, name: &'static str) -> Option<&[Vec<u8>]> {
        self.data.find(&Slice(name)).and_then(|item| {
            match *item {
                Raw(ref raw) => Some(raw.as_slice()),
                _ => None
            }
        })
    }

    /// Get a reference to the header field's value, if it exists.
    pub fn get_ref<H: Header>(&mut self) -> Option<&H> {
        self.data.find_mut(&Slice(header_name::<H>())).and_then(|item| {
            debug!("get_ref, name={}, val={}", header_name::<H>(), item);
            let header = match *item {
                // Huge borrowck hack here, should be refactored to just return here.
                Typed(ref typed) if typed.is::<H>() => None,
                // Typed, wrong type
                Typed(_) => return None,
                Raw(ref raw) => match Header::parse_header(raw.as_slice()) {
                    Some::<H>(h) => {
                        Some(h)
                    },
                    None => return None
                },
            };

            match header {
                Some(header) => {
                    *item = Typed(box header as Box<Header>);
                    Some(item)
                },
                None => {
                    Some(item)
                }
            }
        }).and_then(|item| {
            debug!("downcasting {}", item);
            let ret = match *item {
                Typed(ref val) => {
                    unsafe { Some(val.downcast_ref_unchecked()) }
                },
                _ => unreachable!()
            };
            ret
        })
    }

    /// Returns a boolean of whether a certain header is in the map.
    ///
    /// Example:
    ///
    /// ```
    /// # use hyper::header::Headers;
    /// # use hyper::header::common::ContentType;
    /// # let mut headers = Headers::new();
    /// let has_type = headers.has::<ContentType>();
    /// ```
    pub fn has<H: Header>(&self) -> bool {
        self.data.contains_key(&Slice(header_name::<H>()))
    }

    /// Removes a header from the map, if one existed.
    /// Returns true if a header has been removed.
    pub fn remove<H: Header>(&mut self) -> bool {
        self.data.remove(&Slice(Header::header_name(None::<H>)))
    }

    /// Returns an iterator over the header fields.
    pub fn iter<'a>(&'a self) -> HeadersItems<'a> {
        HeadersItems {
            inner: self.data.iter()
        }
    }
}

impl fmt::Show for Headers {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!("Headers {\n".fmt(fmt));
        for (k, v) in self.iter() {
            try!(write!(fmt, "\t{}: {}\n", k, v));
        }
        "}".fmt(fmt)
    }
}

/// An `Iterator` over the fields in a `Headers` map.
pub struct HeadersItems<'a> {
    inner: Entries<'a, SendStr, Item>
}

impl<'a> Iterator<(&'a str, HeaderView<'a>)> for HeadersItems<'a> {
    fn next(&mut self) -> Option<(&'a str, HeaderView<'a>)> {
        match self.inner.next() {
            Some((k, v)) => Some((k.as_slice(), HeaderView(v))),
            None => None
        }
    }
}

/// Returned with the `HeadersItems` iterator.
pub struct HeaderView<'a>(&'a Item);

impl<'a> fmt::Show for HeaderView<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let HeaderView(item) = *self;
        item.fmt(fmt)
    }
}

impl Collection for Headers {
    fn len(&self) -> uint {
        self.data.len()
    }
}

impl Mutable for Headers {
    fn clear(&mut self) {
        self.data.clear()
    }
}

enum Item {
    Raw(Vec<Vec<u8>>),
    Typed(Box<Header>)
}

impl fmt::Show for Item {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Typed(ref h) => h.fmt_header(fmt),
            Raw(ref raw) => {
                for part in raw.iter() {
                    try!(fmt.write(part.as_slice()));
                }
                Ok(())
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::MemReader;
    use std::fmt;
    use mime::{Mime, Text, Plain};
    use super::{Headers, Header};
    use super::common::{ContentLength, ContentType};

    fn mem(s: &str) -> MemReader {
        MemReader::new(s.as_bytes().to_vec())
    }

    #[test]
    fn test_from_raw() {
        let mut headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
        assert_eq!(headers.get_ref(), Some(&ContentLength(10)));
    }

    #[test]
    fn test_content_type() {
        let content_type = Header::parse_header(["text/plain".as_bytes().to_vec()].as_slice());
        assert_eq!(content_type, Some(ContentType(Mime(Text, Plain, vec![]))));
    }

    #[deriving(Clone)]
    struct CrazyLength(Option<bool>, uint);

    impl Header for CrazyLength {
        fn header_name(_: Option<CrazyLength>) -> &'static str {
            "content-length"
        }
        fn parse_header(raw: &[Vec<u8>]) -> Option<CrazyLength> {
            use std::str::from_utf8;
            use std::from_str::FromStr;

            if raw.len() != 1 {
                return None;
            }
            // we JUST checked that raw.len() == 1, so raw[0] WILL exist.
            match from_utf8(unsafe { raw.as_slice().unsafe_get(0).as_slice() }) {
                Some(s) => FromStr::from_str(s),
                None => None
            }.map(|u| CrazyLength(Some(false), u))
        }
        fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            use std::fmt::Show;
            let CrazyLength(_, ref value) = *self;
            value.fmt(fmt)
        }
    }

    #[test]
    fn test_different_structs_for_same_header() {
        let mut headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
        let ContentLength(num) = headers.get::<ContentLength>().unwrap();
        let CrazyLength(_, crazy_num) = headers.get::<CrazyLength>().unwrap();
        assert_eq!(num, crazy_num);
    }
}
<commit_msg>Disallow parsing as multiple types to prevent transient errors.<commit_after>//! Headers container, and common header fields.
//!
//! hyper has the opinion that Headers should be strongly-typed, because that's
//! why we're using Rust in the first place. To set or get any header, an object
//! must implement the `Header` trait from this module. Several common headers
//! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others.
use std::ascii::OwnedAsciiExt;
use std::char::is_lowercase;
use std::fmt::{mod, Show};
use std::intrinsics::TypeId;
use std::mem::{transmute, transmute_copy};
use std::raw::TraitObject;
use std::str::{from_utf8, SendStr, Slice, Owned};
use std::string::raw;
use std::collections::hashmap::{HashMap, Entries};

use uany::UncheckedAnyDowncast;
use typeable::Typeable;

use http::read_header;
use {HttpResult};

/// Common Headers
pub mod common;

/// A trait for any object that will represent a header field and value.
pub trait Header: Typeable {
    /// Returns the name of the header field this belongs to.
    ///
    /// The market `Option` is to hint to the type system which implementation
    /// to call. This can be done away with once UFCS arrives.
    fn header_name(marker: Option<Self>) -> &'static str;
    /// Parse a header from a raw stream of bytes.
    ///
    /// It's possible that a request can include a header field more than once,
    /// and in that case, the slice will have a length greater than 1. However,
    /// it's not necessarily the case that a Header is *allowed* to have more
    /// than one field value. If that's the case, you **should** return `None`
    /// if `raw.len() > 1`.
    fn parse_header(raw: &[Vec<u8>]) -> Option<Self>;
    /// Format a header to be output into a TcpStream.
    fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result;
}

#[doc(hidden)]
trait Is {
    fn is<T: 'static>(self) -> bool;
}

impl<'a> Is for &'a Header {
    fn is<T: 'static>(self) -> bool {
        self.get_type() == TypeId::of::<T>()
    }
}

impl<'a> UncheckedAnyDowncast<'a> for &'a Header {
    #[inline]
    unsafe fn downcast_ref_unchecked<T: 'static>(self) -> &'a T {
        let to: TraitObject = transmute_copy(&self);
        transmute(to.data)
    }
}

fn header_name<T: Header>() -> &'static str {
    let name = Header::header_name(None::<T>);
    debug_assert!(name.as_slice().chars().all(|c| c == '-' || is_lowercase(c)),
        "Header names should be lowercase: {}", name);
    name
}

/// A map of header fields on requests and responses.
pub struct Headers {
    data: HashMap<SendStr, Item>
}

impl Headers {

    /// Creates a new, empty headers map.
    pub fn new() -> Headers {
        Headers {
            data: HashMap::new()
        }
    }

    #[doc(hidden)]
    pub fn from_raw<R: Reader>(rdr: &mut R) -> HttpResult<Headers> {
        let mut headers = Headers::new();
        loop {
            match try!(read_header(rdr)) {
                Some((name, value)) => {
                    // read_header already checks that name is a token, which
                    // means its safe utf8
                    let name = unsafe {
                        raw::from_utf8(name)
                    }.into_ascii_lower();
                    let item = headers.data.find_or_insert(Owned(name), Raw(vec![]));
                    match *item {
                        Raw(ref mut raw) => raw.push(value),
                        // Unreachable
                        _ => {}
                    };
                },
                None => break,
            }
        }
        Ok(headers)
    }

    /// Set a header field to the corresponding value.
    ///
    /// The field is determined by the type of the value being set.
    pub fn set<H: Header>(&mut self, value: H) {
        self.data.insert(Slice(header_name::<H>()), Typed(box value as Box<Header>));
    }

    /// Get a clone of the header field's value, if it exists.
    ///
    /// Example:
    ///
    /// ```
    /// # use hyper::header::Headers;
    /// # use hyper::header::common::ContentType;
    /// # let mut headers = Headers::new();
    /// let content_type = headers.get::<ContentType>();
    /// ```
    pub fn get<H: Header + Clone>(&mut self) -> Option<H> {
        self.get_ref().map(|v: &H| v.clone())
    }

    /// Access the raw value of a header, if it exists and has not
    /// been already parsed.
    ///
    /// If the header field has already been parsed into a typed header,
    /// then you *must* access it through that representation.
    ///
    /// Example:
    /// ```
    /// # use hyper::header::Headers;
    /// # let mut headers = Headers::new();
    /// let raw_content_type = unsafe { headers.get_raw("content-type") };
    /// ```
    pub unsafe fn get_raw(&self, name: &'static str) -> Option<&[Vec<u8>]> {
        self.data.find(&Slice(name)).and_then(|item| {
            match *item {
                Raw(ref raw) => Some(raw.as_slice()),
                _ => None
            }
        })
    }

    /// Get a reference to the header field's value, if it exists.
    pub fn get_ref<H: Header>(&mut self) -> Option<&H> {
        self.data.find_mut(&Slice(header_name::<H>())).and_then(|item| {
            debug!("get_ref, name={}, val={}", header_name::<H>(), item);
            let header = match *item {
                // Huge borrowck hack here, should be refactored to just return here.
                Typed(ref typed) if typed.is::<H>() => None,
                // Typed, wrong type
                Typed(_) => return None,
                Raw(ref raw) => match Header::parse_header(raw.as_slice()) {
                    Some::<H>(h) => {
                        Some(h)
                    },
                    None => return None
                },
            };

            match header {
                Some(header) => {
                    *item = Typed(box header as Box<Header>);
                    Some(item)
                },
                None => {
                    Some(item)
                }
            }
        }).and_then(|item| {
            debug!("downcasting {}", item);
            let ret = match *item {
                Typed(ref val) => {
                    unsafe { Some(val.downcast_ref_unchecked()) }
                },
                _ => unreachable!()
            };
            ret
        })
    }

    /// Returns a boolean of whether a certain header is in the map.
    ///
    /// Example:
    ///
    /// ```
    /// # use hyper::header::Headers;
    /// # use hyper::header::common::ContentType;
    /// # let mut headers = Headers::new();
    /// let has_type = headers.has::<ContentType>();
    /// ```
    pub fn has<H: Header>(&self) -> bool {
        self.data.contains_key(&Slice(header_name::<H>()))
    }

    /// Removes a header from the map, if one existed.
    /// Returns true if a header has been removed.
    pub fn remove<H: Header>(&mut self) -> bool {
        self.data.remove(&Slice(Header::header_name(None::<H>)))
    }

    /// Returns an iterator over the header fields.
    pub fn iter<'a>(&'a self) -> HeadersItems<'a> {
        HeadersItems {
            inner: self.data.iter()
        }
    }
}

impl fmt::Show for Headers {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!("Headers {\n".fmt(fmt));
        for (k, v) in self.iter() {
            try!(write!(fmt, "\t{}: {}\n", k, v));
        }
        "}".fmt(fmt)
    }
}

/// An `Iterator` over the fields in a `Headers` map.
pub struct HeadersItems<'a> {
    inner: Entries<'a, SendStr, Item>
}

impl<'a> Iterator<(&'a str, HeaderView<'a>)> for HeadersItems<'a> {
    fn next(&mut self) -> Option<(&'a str, HeaderView<'a>)> {
        match self.inner.next() {
            Some((k, v)) => Some((k.as_slice(), HeaderView(v))),
            None => None
        }
    }
}

/// Returned with the `HeadersItems` iterator.
pub struct HeaderView<'a>(&'a Item);

impl<'a> fmt::Show for HeaderView<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let HeaderView(item) = *self;
        item.fmt(fmt)
    }
}

impl Collection for Headers {
    fn len(&self) -> uint {
        self.data.len()
    }
}

impl Mutable for Headers {
    fn clear(&mut self) {
        self.data.clear()
    }
}

enum Item {
    Raw(Vec<Vec<u8>>),
    Typed(Box<Header>)
}

impl fmt::Show for Item {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Typed(ref h) => h.fmt_header(fmt),
            Raw(ref raw) => {
                for part in raw.iter() {
                    try!(fmt.write(part.as_slice()));
                }
                Ok(())
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::MemReader;
    use std::fmt;
    use mime::{Mime, Text, Plain};
    use super::{Headers, Header};
    use super::common::{ContentLength, ContentType};

    fn mem(s: &str) -> MemReader {
        MemReader::new(s.as_bytes().to_vec())
    }

    #[test]
    fn test_from_raw() {
        let mut headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
        assert_eq!(headers.get_ref(), Some(&ContentLength(10)));
    }

    #[test]
    fn test_content_type() {
        let content_type = Header::parse_header(["text/plain".as_bytes().to_vec()].as_slice());
        assert_eq!(content_type, Some(ContentType(Mime(Text, Plain, vec![]))));
    }

    #[deriving(Clone)]
    struct CrazyLength(Option<bool>, uint);

    impl Header for CrazyLength {
        fn header_name(_: Option<CrazyLength>) -> &'static str {
            "content-length"
        }
        fn parse_header(raw: &[Vec<u8>]) -> Option<CrazyLength> {
            use std::str::from_utf8;
            use std::from_str::FromStr;

            if raw.len() != 1 {
                return None;
            }
            // we JUST checked that raw.len() == 1, so raw[0] WILL exist.
            match from_utf8(unsafe { raw.as_slice().unsafe_get(0).as_slice() }) {
                Some(s) => FromStr::from_str(s),
                None => None
            }.map(|u| CrazyLength(Some(false), u))
        }
        fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            use std::fmt::Show;
            let CrazyLength(_, ref value) = *self;
            value.fmt(fmt)
        }
    }

    #[test]
    fn test_different_structs_for_same_header() {
        let mut headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
        let ContentLength(_) = headers.get::<ContentLength>().unwrap();
        assert!(headers.get::<CrazyLength>().is_none());
    }
}
<|endoftext|>