http_types_rs/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 { inner: self.entries.iter() }
96 }
97
98 pub fn iter_mut(&mut self) -> IterMut<'_> {
100 IterMut {
101 inner: self.entries.iter_mut(),
102 }
103 }
104}
105
106impl Header for Vary {
107 fn header_name(&self) -> HeaderName {
108 VARY
109 }
110
111 fn header_value(&self) -> HeaderValue {
112 let mut output = String::new();
113 for (n, name) in self.entries.iter().enumerate() {
114 let directive: HeaderValue = name.as_str().parse().expect("Could not convert a HeaderName into a HeaderValue");
115 match n {
116 0 => write!(output, "{}", directive).unwrap(),
117 _ => write!(output, ", {}", directive).unwrap(),
118 };
119 }
120
121 if self.wildcard {
122 match output.len() {
123 0 => write!(output, "*").unwrap(),
124 _ => write!(output, ", *").unwrap(),
125 };
126 }
127
128 unsafe { HeaderValue::from_bytes_unchecked(output.into()) }
130 }
131}
132
133impl IntoIterator for Vary {
134 type Item = HeaderName;
135 type IntoIter = IntoIter;
136
137 #[inline]
138 fn into_iter(self) -> Self::IntoIter {
139 IntoIter {
140 inner: self.entries.into_iter(),
141 }
142 }
143}
144
145impl<'a> IntoIterator for &'a Vary {
146 type Item = &'a HeaderName;
147 type IntoIter = Iter<'a>;
148
149 #[inline]
150 fn into_iter(self) -> Self::IntoIter {
151 self.iter()
152 }
153}
154
155impl<'a> IntoIterator for &'a mut Vary {
156 type Item = &'a mut HeaderName;
157 type IntoIter = IterMut<'a>;
158
159 #[inline]
160 fn into_iter(self) -> Self::IntoIter {
161 self.iter_mut()
162 }
163}
164
165#[derive(Debug)]
167pub struct IntoIter {
168 inner: std::vec::IntoIter<HeaderName>,
169}
170
171impl Iterator for IntoIter {
172 type Item = HeaderName;
173
174 fn next(&mut self) -> Option<Self::Item> {
175 self.inner.next()
176 }
177
178 #[inline]
179 fn size_hint(&self) -> (usize, Option<usize>) {
180 self.inner.size_hint()
181 }
182}
183
184#[derive(Debug)]
186pub struct Iter<'a> {
187 inner: slice::Iter<'a, HeaderName>,
188}
189
190impl<'a> Iterator for Iter<'a> {
191 type Item = &'a HeaderName;
192
193 fn next(&mut self) -> Option<Self::Item> {
194 self.inner.next()
195 }
196
197 #[inline]
198 fn size_hint(&self) -> (usize, Option<usize>) {
199 self.inner.size_hint()
200 }
201}
202
203#[derive(Debug)]
205pub struct IterMut<'a> {
206 inner: slice::IterMut<'a, HeaderName>,
207}
208
209impl<'a> Iterator for IterMut<'a> {
210 type Item = &'a mut HeaderName;
211
212 fn next(&mut self) -> Option<Self::Item> {
213 self.inner.next()
214 }
215
216 #[inline]
217 fn size_hint(&self) -> (usize, Option<usize>) {
218 self.inner.size_hint()
219 }
220}
221
222impl Debug for Vary {
223 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224 let mut list = f.debug_list();
225 for directive in &self.entries {
226 list.entry(directive);
227 }
228 list.finish()
229 }
230}
231
232#[cfg(test)]
233mod test {
234 use super::*;
235 use crate::conditional::Vary;
236 use crate::Response;
237
238 #[test]
239 fn smoke() -> crate::Result<()> {
240 let mut entries = Vary::new();
241 entries.push("User-Agent")?;
242 entries.push("Accept-Encoding")?;
243
244 let mut res = Response::new(200);
245 entries.apply_header(&mut res);
246
247 let entries = Vary::from_headers(res)?.unwrap();
248 let mut entries = entries.iter();
249 assert_eq!(entries.next().unwrap(), "User-Agent");
250 assert_eq!(entries.next().unwrap(), "Accept-Encoding");
251 Ok(())
252 }
253
254 #[test]
255 fn wildcard() -> crate::Result<()> {
256 let mut entries = Vary::new();
257 entries.push("User-Agent")?;
258 entries.set_wildcard(true);
259
260 let mut res = Response::new(200);
261 entries.apply_header(&mut res);
262
263 let entries = Vary::from_headers(res)?.unwrap();
264 assert!(entries.wildcard());
265 let mut entries = entries.iter();
266 assert_eq!(entries.next().unwrap(), "User-Agent");
267 Ok(())
268 }
269}