li_http_types/cache/cache_control/
cache_control.rs

1use crate::cache::CacheDirective;
2use crate::headers::{HeaderName, HeaderValue, Headers, ToHeaderValues, CACHE_CONTROL};
3
4use std::fmt::{self, Debug, Write};
5use std::iter::Iterator;
6use std::option;
7use std::slice;
8
9/// A Cache-Control header.
10///
11/// # Examples
12///
13/// ```
14/// # fn main() -> li_http_types::Result<()> {
15/// #
16/// use li_http_types::Response;
17/// use li_http_types::cache::{CacheControl, CacheDirective};
18/// let mut entries = CacheControl::new();
19/// entries.push(CacheDirective::Immutable);
20/// entries.push(CacheDirective::NoStore);
21///
22/// let mut res = Response::new(200);
23/// entries.apply(&mut res);
24///
25/// let entries = CacheControl::from_headers(res)?.unwrap();
26/// let mut entries = entries.iter();
27/// assert_eq!(entries.next().unwrap(), &CacheDirective::Immutable);
28/// assert_eq!(entries.next().unwrap(), &CacheDirective::NoStore);
29/// #
30/// # Ok(()) }
31/// ```
32pub struct CacheControl {
33    entries: Vec<CacheDirective>,
34}
35
36impl CacheControl {
37    /// Create a new instance of `CacheControl`.
38    pub fn new() -> Self {
39        Self { entries: vec![] }
40    }
41
42    /// Create a new instance from headers.
43    pub fn from_headers(headers: impl AsRef<Headers>) -> crate::Result<Option<Self>> {
44        let mut entries = vec![];
45        let headers = match headers.as_ref().get(CACHE_CONTROL) {
46            Some(headers) => headers,
47            None => return Ok(None),
48        };
49
50        for value in headers {
51            for part in value.as_str().trim().split(',') {
52                // Try and parse a directive from a str. If the directive is
53                // unkown we skip it.
54                if let Some(entry) = CacheDirective::from_str(part)? {
55                    entries.push(entry);
56                }
57            }
58        }
59
60        Ok(Some(Self { entries }))
61    }
62
63    /// Sets the `Server-Timing` header.
64    pub fn apply(&self, mut headers: impl AsMut<Headers>) {
65        headers.as_mut().insert(CACHE_CONTROL, self.value());
66    }
67
68    /// Get the `HeaderName`.
69    pub fn name(&self) -> HeaderName {
70        CACHE_CONTROL
71    }
72
73    /// Get the `HeaderValue`.
74    pub fn value(&self) -> HeaderValue {
75        let mut output = String::new();
76        for (n, directive) in self.entries.iter().enumerate() {
77            let directive: HeaderValue = directive.clone().into();
78            match n {
79                0 => write!(output, "{}", directive).unwrap(),
80                _ => write!(output, ", {}", directive).unwrap(),
81            };
82        }
83
84        // SAFETY: the internal string is validated to be ASCII.
85        unsafe { HeaderValue::from_bytes_unchecked(output.into()) }
86    }
87    /// Push a directive into the list of entries.
88    pub fn push(&mut self, directive: CacheDirective) {
89        self.entries.push(directive);
90    }
91
92    /// An iterator visiting all server entries.
93    pub fn iter(&self) -> Iter<'_> {
94        Iter {
95            inner: self.entries.iter(),
96        }
97    }
98
99    /// An iterator visiting all server entries.
100    pub fn iter_mut(&mut self) -> IterMut<'_> {
101        IterMut {
102            inner: self.entries.iter_mut(),
103        }
104    }
105}
106
107impl IntoIterator for CacheControl {
108    type Item = CacheDirective;
109    type IntoIter = IntoIter;
110
111    #[inline]
112    fn into_iter(self) -> Self::IntoIter {
113        IntoIter {
114            inner: self.entries.into_iter(),
115        }
116    }
117}
118
119impl<'a> IntoIterator for &'a CacheControl {
120    type Item = &'a CacheDirective;
121    type IntoIter = Iter<'a>;
122
123    #[inline]
124    fn into_iter(self) -> Self::IntoIter {
125        self.iter()
126    }
127}
128
129impl<'a> IntoIterator for &'a mut CacheControl {
130    type Item = &'a mut CacheDirective;
131    type IntoIter = IterMut<'a>;
132
133    #[inline]
134    fn into_iter(self) -> Self::IntoIter {
135        self.iter_mut()
136    }
137}
138
139/// A borrowing iterator over entries in `CacheControl`.
140#[derive(Debug)]
141pub struct IntoIter {
142    inner: std::vec::IntoIter<CacheDirective>,
143}
144
145impl Iterator for IntoIter {
146    type Item = CacheDirective;
147
148    fn next(&mut self) -> Option<Self::Item> {
149        self.inner.next()
150    }
151
152    #[inline]
153    fn size_hint(&self) -> (usize, Option<usize>) {
154        self.inner.size_hint()
155    }
156}
157
158/// A lending iterator over entries in `CacheControl`.
159#[derive(Debug)]
160pub struct Iter<'a> {
161    inner: slice::Iter<'a, CacheDirective>,
162}
163
164impl<'a> Iterator for Iter<'a> {
165    type Item = &'a CacheDirective;
166
167    fn next(&mut self) -> Option<Self::Item> {
168        self.inner.next()
169    }
170
171    #[inline]
172    fn size_hint(&self) -> (usize, Option<usize>) {
173        self.inner.size_hint()
174    }
175}
176
177/// A mutable iterator over entries in `CacheControl`.
178#[derive(Debug)]
179pub struct IterMut<'a> {
180    inner: slice::IterMut<'a, CacheDirective>,
181}
182
183impl<'a> Iterator for IterMut<'a> {
184    type Item = &'a mut CacheDirective;
185
186    fn next(&mut self) -> Option<Self::Item> {
187        self.inner.next()
188    }
189
190    #[inline]
191    fn size_hint(&self) -> (usize, Option<usize>) {
192        self.inner.size_hint()
193    }
194}
195
196impl ToHeaderValues for CacheControl {
197    type Iter = option::IntoIter<HeaderValue>;
198    fn to_header_values(&self) -> crate::Result<Self::Iter> {
199        // A HeaderValue will always convert into itself.
200        Ok(self.value().to_header_values().unwrap())
201    }
202}
203
204impl Debug for CacheControl {
205    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206        let mut list = f.debug_list();
207        for directive in &self.entries {
208            list.entry(directive);
209        }
210        list.finish()
211    }
212}