http_types/trace/server_timing/
metric.rs1use std::time::Duration;
2
3use crate::headers::HeaderValue;
4
5#[derive(Debug, Clone, Eq, PartialEq)]
18pub struct Metric {
19 pub(crate) name: String,
20 pub(crate) dur: Option<Duration>,
21 pub(crate) desc: Option<String>,
22}
23
24impl Metric {
25 pub fn new(name: String, dur: Option<Duration>, desc: Option<String>) -> crate::Result<Self> {
31 crate::ensure!(name.is_ascii(), "Name should be valid ASCII");
32 if let Some(desc) = desc.as_ref() {
33 crate::ensure!(desc.is_ascii(), "Description should be valid ASCII");
34 };
35
36 Ok(Self { name, dur, desc })
37 }
38
39 pub fn name(&self) -> &String {
41 &self.name
42 }
43
44 pub fn duration(&self) -> Option<Duration> {
46 self.dur
47 }
48
49 pub fn description(&self) -> Option<&str> {
51 self.desc.as_deref()
52 }
53}
54
55impl From<Metric> for HeaderValue {
56 fn from(entry: Metric) -> HeaderValue {
57 let mut string = entry.name;
58
59 let f = |d: Duration| d.as_secs_f64() * 1000.0;
61
62 match (entry.dur, entry.desc) {
63 (Some(dur), Some(desc)) => {
64 string.push_str(&format!("; dur={}; desc=\"{}\"", f(dur), desc))
65 }
66 (Some(dur), None) => string.push_str(&format!("; dur={}", f(dur))),
67 (None, Some(desc)) => string.push_str(&format!("; desc=\"{}\"", desc)),
68 (None, None) => {}
69 };
70
71 unsafe { HeaderValue::from_bytes_unchecked(string.into_bytes()) }
73 }
74}
75
76#[cfg(test)]
77mod test {
78 use super::*;
79 use crate::headers::HeaderValue;
80 use std::time::Duration;
81
82 #[test]
83 #[allow(clippy::redundant_clone)]
84 fn encode() -> crate::Result<()> {
85 let name = String::from("Server");
86 let dur = Duration::from_secs(1);
87 let desc = String::from("A server timing");
88
89 let val: HeaderValue = Metric::new(name.clone(), None, None)?.into();
90 assert_eq!(val, "Server");
91
92 let val: HeaderValue = Metric::new(name.clone(), Some(dur), None)?.into();
93 assert_eq!(val, "Server; dur=1000");
94
95 let val: HeaderValue = Metric::new(name.clone(), None, Some(desc.clone()))?.into();
96 assert_eq!(val, r#"Server; desc="A server timing""#);
97
98 let val: HeaderValue = Metric::new(name.clone(), Some(dur), Some(desc.clone()))?.into();
99 assert_eq!(val, r#"Server; dur=1000; desc="A server timing""#);
100 Ok(())
101 }
102}