headers/
map_ext.rs

1use super::{Error, Header, HeaderValue};
2use http;
3
4/// An extension trait adding "typed" methods to `http::HeaderMap`.
5pub trait HeaderMapExt: self::sealed::Sealed {
6    /// Inserts the typed `Header` into this `HeaderMap`.
7    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`.
12    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`.
17    fn typed_try_get<H>(&self) -> Result<Option<H>, Error>
18    where
19        H: Header;
20}
21
22impl HeaderMapExt for http::HeaderMap {
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
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
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
54struct ToValues<'a> {
55    state: State<'a>,
56}
57
58#[derive(Debug)]
59enum State<'a> {
60    First(http::header::Entry<'a, HeaderValue>),
61    Latter(http::header::OccupiedEntry<'a, HeaderValue>),
62    Tmp,
63}
64
65impl<'a> Extend<HeaderValue> for ToValues<'a> {
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
85mod sealed {
86    pub trait Sealed {}
87    impl Sealed for ::http::HeaderMap {}
88}