Skip to content

Commit 9375add

Browse files
untitakerseanmonstar
authored andcommitted
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()`.
1 parent 74136de commit 9375add

File tree

3 files changed

+41
-3
lines changed

3 files changed

+41
-3
lines changed

src/header/internals/cell.rs

+14
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,20 @@ impl<V: ?Sized + Any + 'static> PtrMapCell<V> {
8686
}.map(|val| &mut **val)
8787
}
8888

89+
#[inline]
90+
pub fn into_value(self, key: TypeId) -> Option<Box<V>> {
91+
let map = unsafe { self.0.into_inner() };
92+
match map {
93+
PtrMap::Empty => None,
94+
PtrMap::One(id, v) => if id == key {
95+
Some(v)
96+
} else {
97+
None
98+
},
99+
PtrMap::Many(mut hm) => hm.remove(&key)
100+
}
101+
}
102+
89103
#[inline]
90104
pub unsafe fn insert(&self, key: TypeId, val: Box<V>) {
91105
let mut map = &mut *self.0.get();

src/header/internals/item.rs

+8
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ impl Item {
8282
}
8383
self.typed.get_mut(tid).map(|typed| unsafe { typed.downcast_mut_unchecked() })
8484
}
85+
86+
pub fn into_typed<H: Header>(self) -> Option<H> {
87+
let tid = TypeId::of::<H>();
88+
match self.typed.into_value(tid) {
89+
Some(val) => Some(val),
90+
None => parse::<H>(self.raw.as_ref().expect("item.raw must exist")).ok()
91+
}.map(|typed| unsafe { typed.downcast_unchecked() })
92+
}
8593
}
8694

8795
#[inline]

src/header/mod.rs

+19-3
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ impl Header + Send + Sync {
182182
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
183183
&mut *(mem::transmute::<*mut _, (*mut (), *mut ())>(self).0 as *mut T)
184184
}
185+
186+
#[inline]
187+
unsafe fn downcast_unchecked<T: 'static>(self: Box<Self>) -> T {
188+
*Box::from_raw(mem::transmute::<*mut _, (*mut (), *mut ())>(Box::into_raw(self)).0 as *mut T)
189+
}
185190
}
186191

187192
impl Clone for Box<Header + Send + Sync> {
@@ -320,10 +325,14 @@ impl Headers {
320325
}
321326

322327
/// Removes a header from the map, if one existed.
323-
/// Returns true if a header has been removed.
324-
pub fn remove<H: Header>(&mut self) -> bool {
328+
/// Returns the header, if one has been removed and could be parsed.
329+
///
330+
/// Note that this function may return `None` even though a header was removed. If you want to
331+
/// know whether a header exists, rather rely on `has`.
332+
pub fn remove<H: Header>(&mut self) -> Option<H> {
325333
trace!("Headers.remove( {:?} )", header_name::<H>());
326-
self.data.remove(&HeaderName(UniCase(Cow::Borrowed(header_name::<H>())))).is_some()
334+
self.data.remove(&HeaderName(UniCase(Cow::Borrowed(header_name::<H>()))))
335+
.and_then(Item::into_typed::<H>)
327336
}
328337

329338
/// Returns an iterator over the header fields.
@@ -751,6 +760,13 @@ mod tests {
751760
assert_eq!(headers.get_raw("Content-length"), None);
752761
}
753762

763+
#[test]
764+
fn test_remove() {
765+
let mut headers = Headers::new();
766+
headers.set(ContentLength(10));
767+
assert_eq!(headers.remove(), Some(ContentLength(10)));
768+
}
769+
754770
#[test]
755771
fn test_len() {
756772
let mut headers = Headers::new();

0 commit comments

Comments
 (0)