rama_http_headers/
map_ext.rs

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