1 use super::{Error, Header, HeaderValue}; 2 use http; 3 4 /// An extension trait adding "typed" methods to `http::HeaderMap`. 5 pub trait HeaderMapExt: self::sealed::Sealed { 6 /// Inserts the typed `Header` into this `HeaderMap`. typed_insert<H>(&mut self, header: H) where H: Header7 fn typed_insert<H>(&mut self, header: H) 8 where 9 H: Header; 10 11 /// Tries to find the header by name, and then decode it into `H`. typed_get<H>(&self) -> Option<H> where H: Header12 fn typed_get<H>(&self) -> Option<H> 13 where 14 H: Header; 15 16 /// Tries to find the header by name, and then decode it into `H`. typed_try_get<H>(&self) -> Result<Option<H>, Error> where H: Header17 fn typed_try_get<H>(&self) -> Result<Option<H>, Error> 18 where 19 H: Header; 20 } 21 22 impl HeaderMapExt for http::HeaderMap { typed_insert<H>(&mut self, header: H) where H: Header,23 fn typed_insert<H>(&mut self, header: H) 24 where 25 H: Header, 26 { 27 let entry = self.entry(H::name()); 28 let mut values = ToValues { 29 state: State::First(entry), 30 }; 31 header.encode(&mut values); 32 } 33 typed_get<H>(&self) -> Option<H> where H: Header,34 fn typed_get<H>(&self) -> Option<H> 35 where 36 H: Header, 37 { 38 HeaderMapExt::typed_try_get(self).unwrap_or(None) 39 } 40 typed_try_get<H>(&self) -> Result<Option<H>, Error> where H: Header,41 fn typed_try_get<H>(&self) -> Result<Option<H>, Error> 42 where 43 H: Header, 44 { 45 let mut values = self.get_all(H::name()).iter(); 46 if values.size_hint() == (0, Some(0)) { 47 Ok(None) 48 } else { 49 H::decode(&mut values).map(Some) 50 } 51 } 52 } 53 54 struct ToValues<'a> { 55 state: State<'a>, 56 } 57 58 #[derive(Debug)] 59 enum State<'a> { 60 First(http::header::Entry<'a, HeaderValue>), 61 Latter(http::header::OccupiedEntry<'a, HeaderValue>), 62 Tmp, 63 } 64 65 impl<'a> Extend<HeaderValue> for ToValues<'a> { extend<T: IntoIterator<Item = HeaderValue>>(&mut self, iter: T)66 fn extend<T: IntoIterator<Item = HeaderValue>>(&mut self, iter: T) { 67 for value in iter { 68 let entry = match ::std::mem::replace(&mut self.state, State::Tmp) { 69 State::First(http::header::Entry::Occupied(mut e)) => { 70 e.insert(value); 71 e 72 } 73 State::First(http::header::Entry::Vacant(e)) => e.insert_entry(value), 74 State::Latter(mut e) => { 75 e.append(value); 76 e 77 } 78 State::Tmp => unreachable!("ToValues State::Tmp"), 79 }; 80 self.state = State::Latter(entry); 81 } 82 } 83 } 84 85 mod sealed { 86 pub trait Sealed {} 87 impl Sealed for ::http::HeaderMap {} 88 } 89