http_types_2/conditional/
vary.rs1use crate::headers::{Header, HeaderName, HeaderValue, Headers, VARY};
4
5use std::fmt::{self, Debug, Write};
6use std::iter::Iterator;
7
8use std::slice;
9use std::str::FromStr;
10
11pub struct Vary {
40 entries: Vec<HeaderName>,
41 wildcard: bool,
42}
43
44impl Vary {
45 pub fn new() -> Self {
47 Self {
48 entries: vec![],
49 wildcard: false,
50 }
51 }
52
53 pub fn from_headers(headers: impl AsRef<Headers>) -> crate::Result<Option<Self>> {
55 let mut entries = vec![];
56 let headers = match headers.as_ref().get(VARY) {
57 Some(headers) => headers,
58 None => return Ok(None),
59 };
60
61 let mut wildcard = false;
62 for value in headers {
63 for part in value.as_str().trim().split(',') {
64 let part = part.trim();
65 if part == "*" {
66 wildcard = true;
67 continue;
68 }
69 let entry = HeaderName::from_str(part.trim())?;
70 entries.push(entry);
71 }
72 }
73
74 Ok(Some(Self { entries, wildcard }))
75 }
76
77 pub fn wildcard(&self) -> bool {
79 self.wildcard
80 }
81
82 pub fn set_wildcard(&mut self, wildcard: bool) {
84 self.wildcard = wildcard
85 }
86
87 pub fn push(&mut self, directive: impl Into<HeaderName>) -> crate::Result<()> {
89 self.entries.push(directive.into());
90 Ok(())
91 }
92
93 pub fn iter(&self) -> Iter<'_> {
95 Iter {
96 inner: self.entries.iter(),
97 }
98 }
99
100 pub fn iter_mut(&mut self) -> IterMut<'_> {
102 IterMut {
103 inner: self.entries.iter_mut(),
104 }
105 }
106}
107
108impl Header for Vary {
109 fn header_name(&self) -> HeaderName {
110 VARY
111 }
112
113 fn header_value(&self) -> HeaderValue {
114 let mut output = String::new();
115 for (n, name) in self.entries.iter().enumerate() {
116 let directive: HeaderValue = name
117 .as_str()
118 .parse()
119 .expect("Could not convert a HeaderName into a HeaderValue");
120 match n {
121 0 => write!(output, "{directive}").unwrap(),
122 _ => write!(output, ", {directive}").unwrap(),
123 };
124 }
125
126 if self.wildcard {
127 match output.len() {
128 0 => write!(output, "*").unwrap(),
129 _ => write!(output, ", *").unwrap(),
130 };
131 }
132
133 unsafe { HeaderValue::from_bytes_unchecked(output.into()) }
135 }
136}
137
138impl IntoIterator for Vary {
139 type Item = HeaderName;
140 type IntoIter = IntoIter;
141
142 #[inline]
143 fn into_iter(self) -> Self::IntoIter {
144 IntoIter {
145 inner: self.entries.into_iter(),
146 }
147 }
148}
149
150impl<'a> IntoIterator for &'a Vary {
151 type Item = &'a HeaderName;
152 type IntoIter = Iter<'a>;
153
154 #[inline]
155 fn into_iter(self) -> Self::IntoIter {
156 self.iter()
157 }
158}
159
160impl<'a> IntoIterator for &'a mut Vary {
161 type Item = &'a mut HeaderName;
162 type IntoIter = IterMut<'a>;
163
164 #[inline]
165 fn into_iter(self) -> Self::IntoIter {
166 self.iter_mut()
167 }
168}
169
170#[derive(Debug)]
172pub struct IntoIter {
173 inner: std::vec::IntoIter<HeaderName>,
174}
175
176impl Iterator for IntoIter {
177 type Item = HeaderName;
178
179 fn next(&mut self) -> Option<Self::Item> {
180 self.inner.next()
181 }
182
183 #[inline]
184 fn size_hint(&self) -> (usize, Option<usize>) {
185 self.inner.size_hint()
186 }
187}
188
189#[derive(Debug)]
191pub struct Iter<'a> {
192 inner: slice::Iter<'a, HeaderName>,
193}
194
195impl<'a> Iterator for Iter<'a> {
196 type Item = &'a HeaderName;
197
198 fn next(&mut self) -> Option<Self::Item> {
199 self.inner.next()
200 }
201
202 #[inline]
203 fn size_hint(&self) -> (usize, Option<usize>) {
204 self.inner.size_hint()
205 }
206}
207
208#[derive(Debug)]
210pub struct IterMut<'a> {
211 inner: slice::IterMut<'a, HeaderName>,
212}
213
214impl<'a> Iterator for IterMut<'a> {
215 type Item = &'a mut HeaderName;
216
217 fn next(&mut self) -> Option<Self::Item> {
218 self.inner.next()
219 }
220
221 #[inline]
222 fn size_hint(&self) -> (usize, Option<usize>) {
223 self.inner.size_hint()
224 }
225}
226
227impl Debug for Vary {
228 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229 let mut list = f.debug_list();
230 for directive in &self.entries {
231 list.entry(directive);
232 }
233 list.finish()
234 }
235}
236
237#[cfg(test)]
238mod test {
239 use super::*;
240 use crate::conditional::Vary;
241 use crate::Response;
242
243 #[test]
244 fn smoke() -> crate::Result<()> {
245 let mut entries = Vary::new();
246 entries.push("User-Agent")?;
247 entries.push("Accept-Encoding")?;
248
249 let mut res = Response::new(200);
250 entries.apply_header(&mut res);
251
252 let entries = Vary::from_headers(res)?.unwrap();
253 let mut entries = entries.iter();
254 assert_eq!(entries.next().unwrap(), "User-Agent");
255 assert_eq!(entries.next().unwrap(), "Accept-Encoding");
256 Ok(())
257 }
258
259 #[test]
260 fn wildcard() -> crate::Result<()> {
261 let mut entries = Vary::new();
262 entries.push("User-Agent")?;
263 entries.set_wildcard(true);
264
265 let mut res = Response::new(200);
266 entries.apply_header(&mut res);
267
268 let entries = Vary::from_headers(res)?.unwrap();
269 assert!(entries.wildcard());
270 let mut entries = entries.iter();
271 assert_eq!(entries.next().unwrap(), "User-Agent");
272 Ok(())
273 }
274}