http_types/trace/server_timing/
mod.rs1mod metric;
25mod parse;
26
27pub use metric::Metric;
28use parse::parse_header;
29
30use std::convert::AsMut;
31use std::fmt::Write;
32use std::iter::Iterator;
33use std::option;
34use std::slice;
35
36use crate::headers::{HeaderName, HeaderValue, Headers, ToHeaderValues, SERVER_TIMING};
37
38#[derive(Debug)]
65pub struct ServerTiming {
66 timings: Vec<Metric>,
67}
68
69impl ServerTiming {
70 pub fn new() -> Self {
72 Self { timings: vec![] }
73 }
74
75 pub fn from_headers(headers: impl AsRef<Headers>) -> crate::Result<Option<Self>> {
77 let mut timings = vec![];
78 let headers = match headers.as_ref().get(SERVER_TIMING) {
79 Some(headers) => headers,
80 None => return Ok(None),
81 };
82
83 for value in headers {
84 parse_header(value.as_str(), &mut timings)?;
85 }
86 Ok(Some(Self { timings }))
87 }
88
89 pub fn apply(&self, mut headers: impl AsMut<Headers>) {
91 headers.as_mut().insert(SERVER_TIMING, self.value());
92 }
93
94 pub fn name(&self) -> HeaderName {
96 SERVER_TIMING
97 }
98
99 pub fn value(&self) -> HeaderValue {
101 let mut output = String::new();
102 for (n, timing) in self.timings.iter().enumerate() {
103 let timing: HeaderValue = timing.clone().into();
104 match n {
105 0 => write!(output, "{}", timing).unwrap(),
106 _ => write!(output, ", {}", timing).unwrap(),
107 };
108 }
109
110 unsafe { HeaderValue::from_bytes_unchecked(output.into()) }
112 }
113
114 pub fn push(&mut self, entry: Metric) {
116 self.timings.push(entry);
117 }
118
119 pub fn iter(&self) -> Iter<'_> {
121 Iter {
122 inner: self.timings.iter(),
123 }
124 }
125
126 pub fn iter_mut(&mut self) -> IterMut<'_> {
128 IterMut {
129 inner: self.timings.iter_mut(),
130 }
131 }
132}
133
134impl IntoIterator for ServerTiming {
135 type Item = Metric;
136 type IntoIter = IntoIter;
137
138 #[inline]
139 fn into_iter(self) -> Self::IntoIter {
140 IntoIter {
141 inner: self.timings.into_iter(),
142 }
143 }
144}
145
146impl<'a> IntoIterator for &'a ServerTiming {
147 type Item = &'a Metric;
148 type IntoIter = Iter<'a>;
149
150 fn into_iter(self) -> Self::IntoIter {
152 self.iter()
153 }
154}
155
156impl<'a> IntoIterator for &'a mut ServerTiming {
157 type Item = &'a mut Metric;
158 type IntoIter = IterMut<'a>;
159
160 #[inline]
161 fn into_iter(self) -> Self::IntoIter {
162 self.iter_mut()
163 }
164}
165
166#[derive(Debug)]
168pub struct IntoIter {
169 inner: std::vec::IntoIter<Metric>,
170}
171
172impl Iterator for IntoIter {
173 type Item = Metric;
174
175 fn next(&mut self) -> Option<Self::Item> {
176 self.inner.next()
177 }
178
179 #[inline]
180 fn size_hint(&self) -> (usize, Option<usize>) {
181 self.inner.size_hint()
182 }
183}
184
185#[derive(Debug)]
187pub struct Iter<'a> {
188 inner: slice::Iter<'a, Metric>,
189}
190
191impl<'a> Iterator for Iter<'a> {
192 type Item = &'a Metric;
193
194 fn next(&mut self) -> Option<Self::Item> {
195 self.inner.next()
196 }
197
198 #[inline]
199 fn size_hint(&self) -> (usize, Option<usize>) {
200 self.inner.size_hint()
201 }
202}
203
204#[derive(Debug)]
206pub struct IterMut<'a> {
207 inner: slice::IterMut<'a, Metric>,
208}
209
210impl<'a> Iterator for IterMut<'a> {
211 type Item = &'a mut Metric;
212
213 fn next(&mut self) -> Option<Self::Item> {
214 self.inner.next()
215 }
216
217 #[inline]
218 fn size_hint(&self) -> (usize, Option<usize>) {
219 self.inner.size_hint()
220 }
221}
222
223impl ToHeaderValues for ServerTiming {
224 type Iter = option::IntoIter<HeaderValue>;
225 fn to_header_values(&self) -> crate::Result<Self::Iter> {
226 Ok(self.value().to_header_values().unwrap())
228 }
229}
230
231#[cfg(test)]
232mod test {
233 use super::*;
234 use crate::headers::Headers;
235
236 #[test]
237 fn smoke() -> crate::Result<()> {
238 let mut timings = ServerTiming::new();
239 timings.push(Metric::new("server".to_owned(), None, None)?);
240
241 let mut headers = Headers::new();
242 timings.apply(&mut headers);
243
244 let timings = ServerTiming::from_headers(headers)?.unwrap();
245 let entry = timings.iter().next().unwrap();
246 assert_eq!(entry.name(), "server");
247 Ok(())
248 }
249
250 #[test]
251 fn to_header_values() -> crate::Result<()> {
252 let mut timings = ServerTiming::new();
253 timings.push(Metric::new("server".to_owned(), None, None)?);
254
255 let mut headers = Headers::new();
256 timings.apply(&mut headers);
257
258 let timings = ServerTiming::from_headers(headers)?.unwrap();
259 let entry = timings.iter().next().unwrap();
260 assert_eq!(entry.name(), "server");
261 Ok(())
262 }
263
264 #[test]
265 fn bad_request_on_parse_error() {
266 let mut headers = Headers::new();
267 headers.insert(SERVER_TIMING, "server; <nori ate your param omnom>");
268 let err = ServerTiming::from_headers(headers).unwrap_err();
269 assert_eq!(err.status(), 400);
270 }
271}