feat(headers): Headers::remove returns the Header

Closes #891

BREAKING CHANGE: `Headers.remove()` used to return a `bool`,
  it now returns `Option<H>`. To determine if a a header exists,
  switch to `Headers.has()`.
This commit is contained in:
Markus Unterwaditzer
2016-08-23 22:46:07 +02:00
committed by Sean McArthur
parent 74136de960
commit 9375addba0
3 changed files with 41 additions and 3 deletions

View File

@@ -86,6 +86,20 @@ impl<V: ?Sized + Any + 'static> PtrMapCell<V> {
}.map(|val| &mut **val) }.map(|val| &mut **val)
} }
#[inline]
pub fn into_value(self, key: TypeId) -> Option<Box<V>> {
let map = unsafe { self.0.into_inner() };
match map {
PtrMap::Empty => None,
PtrMap::One(id, v) => if id == key {
Some(v)
} else {
None
},
PtrMap::Many(mut hm) => hm.remove(&key)
}
}
#[inline] #[inline]
pub unsafe fn insert(&self, key: TypeId, val: Box<V>) { pub unsafe fn insert(&self, key: TypeId, val: Box<V>) {
let mut map = &mut *self.0.get(); let mut map = &mut *self.0.get();

View File

@@ -82,6 +82,14 @@ impl Item {
} }
self.typed.get_mut(tid).map(|typed| unsafe { typed.downcast_mut_unchecked() }) self.typed.get_mut(tid).map(|typed| unsafe { typed.downcast_mut_unchecked() })
} }
pub fn into_typed<H: Header>(self) -> Option<H> {
let tid = TypeId::of::<H>();
match self.typed.into_value(tid) {
Some(val) => Some(val),
None => parse::<H>(self.raw.as_ref().expect("item.raw must exist")).ok()
}.map(|typed| unsafe { typed.downcast_unchecked() })
}
} }
#[inline] #[inline]

View File

@@ -182,6 +182,11 @@ impl Header + Send + Sync {
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T { unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
&mut *(mem::transmute::<*mut _, (*mut (), *mut ())>(self).0 as *mut T) &mut *(mem::transmute::<*mut _, (*mut (), *mut ())>(self).0 as *mut T)
} }
#[inline]
unsafe fn downcast_unchecked<T: 'static>(self: Box<Self>) -> T {
*Box::from_raw(mem::transmute::<*mut _, (*mut (), *mut ())>(Box::into_raw(self)).0 as *mut T)
}
} }
impl Clone for Box<Header + Send + Sync> { impl Clone for Box<Header + Send + Sync> {
@@ -320,10 +325,14 @@ impl Headers {
} }
/// Removes a header from the map, if one existed. /// Removes a header from the map, if one existed.
/// Returns true if a header has been removed. /// Returns the header, if one has been removed and could be parsed.
pub fn remove<H: Header>(&mut self) -> bool { ///
/// Note that this function may return `None` even though a header was removed. If you want to
/// know whether a header exists, rather rely on `has`.
pub fn remove<H: Header>(&mut self) -> Option<H> {
trace!("Headers.remove( {:?} )", header_name::<H>()); trace!("Headers.remove( {:?} )", header_name::<H>());
self.data.remove(&HeaderName(UniCase(Cow::Borrowed(header_name::<H>())))).is_some() self.data.remove(&HeaderName(UniCase(Cow::Borrowed(header_name::<H>()))))
.and_then(Item::into_typed::<H>)
} }
/// Returns an iterator over the header fields. /// Returns an iterator over the header fields.
@@ -751,6 +760,13 @@ mod tests {
assert_eq!(headers.get_raw("Content-length"), None); assert_eq!(headers.get_raw("Content-length"), None);
} }
#[test]
fn test_remove() {
let mut headers = Headers::new();
headers.set(ContentLength(10));
assert_eq!(headers.remove(), Some(ContentLength(10)));
}
#[test] #[test]
fn test_len() { fn test_len() {
let mut headers = Headers::new(); let mut headers = Headers::new();