diff --git a/src/header/internals/cell.rs b/src/header/internals/cell.rs index fd15b1e9af..2e87b0bd5d 100644 --- a/src/header/internals/cell.rs +++ b/src/header/internals/cell.rs @@ -86,6 +86,20 @@ impl PtrMapCell { }.map(|val| &mut **val) } + #[inline] + pub fn into_value(self, key: TypeId) -> Option> { + 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] pub unsafe fn insert(&self, key: TypeId, val: Box) { let mut map = &mut *self.0.get(); diff --git a/src/header/internals/item.rs b/src/header/internals/item.rs index bf9ed44638..ab9ca9015d 100644 --- a/src/header/internals/item.rs +++ b/src/header/internals/item.rs @@ -82,6 +82,14 @@ impl Item { } self.typed.get_mut(tid).map(|typed| unsafe { typed.downcast_mut_unchecked() }) } + + pub fn into_typed(self) -> Option { + let tid = TypeId::of::(); + match self.typed.into_value(tid) { + Some(val) => Some(val), + None => parse::(self.raw.as_ref().expect("item.raw must exist")).ok() + }.map(|typed| unsafe { typed.downcast_unchecked() }) + } } #[inline] diff --git a/src/header/mod.rs b/src/header/mod.rs index 8e36bf4f97..f5929ccfde 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -182,6 +182,11 @@ impl Header + Send + Sync { unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { &mut *(mem::transmute::<*mut _, (*mut (), *mut ())>(self).0 as *mut T) } + + #[inline] + unsafe fn downcast_unchecked(self: Box) -> T { + *Box::from_raw(mem::transmute::<*mut _, (*mut (), *mut ())>(Box::into_raw(self)).0 as *mut T) + } } impl Clone for Box
{ @@ -320,10 +325,14 @@ impl Headers { } /// Removes a header from the map, if one existed. - /// Returns true if a header has been removed. - pub fn remove(&mut self) -> bool { + /// Returns the header, if one has been removed and could be parsed. + /// + /// 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(&mut self) -> Option { trace!("Headers.remove( {:?} )", header_name::()); - self.data.remove(&HeaderName(UniCase(Cow::Borrowed(header_name::())))).is_some() + self.data.remove(&HeaderName(UniCase(Cow::Borrowed(header_name::())))) + .and_then(Item::into_typed::) } /// Returns an iterator over the header fields. @@ -751,6 +760,13 @@ mod tests { 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] fn test_len() { let mut headers = Headers::new();