Skip to content

Commit e4efa9d

Browse files
committed
implement serialization for server timing entry
1 parent 66caf81 commit e4efa9d

File tree

2 files changed

+58
-19
lines changed

2 files changed

+58
-19
lines changed

src/trace/server_timing/entry.rs

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::time::Duration;
22

3+
use crate::headers::HeaderValue;
4+
35
/// An individual `ServerTiming` entry.
46
//
57
// # Implementation notes
@@ -21,37 +23,74 @@ pub struct Entry {
2123

2224
impl Entry {
2325
/// Create a new instance of `Entry`.
24-
pub fn new(name: String, dur: Option<Duration>, desc: Option<String>) -> Self {
25-
Self { name, dur, desc }
26+
///
27+
/// # Errors
28+
///
29+
/// An error will be returned if the string values are invalid ASCII.
30+
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 })
2637
}
2738

2839
/// The timing name.
2940
pub fn name(&self) -> &String {
3041
&self.name
3142
}
3243

33-
/// Set the timing name.
34-
pub fn set_name(&mut self, name: String) {
35-
self.name = name;
36-
}
37-
3844
/// The timing duration.
3945
pub fn duration(&self) -> Option<Duration> {
4046
self.dur
4147
}
4248

43-
/// Set the timing name.
44-
pub fn set_duration(&mut self, dur: Option<Duration>) {
45-
self.dur = dur;
46-
}
47-
4849
/// The timing description.
4950
pub fn description(&self) -> Option<&String> {
5051
self.desc.as_ref()
5152
}
53+
}
54+
55+
impl From<Entry> for HeaderValue {
56+
fn from(entry: Entry) -> HeaderValue {
57+
let mut string = entry.name;
58+
59+
// Format a `Duration` into the format that the spec expects.
60+
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+
// SAFETY: we validate that the values are valid ASCII on creation.
72+
unsafe { HeaderValue::from_bytes_unchecked(string.into_bytes()) }
73+
}
74+
}
75+
76+
#[cfg(test)]
77+
mod test {
78+
use super::*;
79+
80+
#[test]
81+
fn create_header_value() -> crate::Result<()> {
82+
let name = String::from("Server");
83+
let dur = Duration::from_secs(1);
84+
let desc = String::from("A server timing");
85+
86+
let val: HeaderValue = Entry::new(name.clone(), None, None)?.into();
87+
assert_eq!(val, "Server");
88+
89+
let val: HeaderValue = Entry::new(name.clone(), Some(dur), None)?.into();
90+
assert_eq!(val, "Server; dur=1000");
5291

53-
/// Set the timing description.
54-
pub fn set_description(&mut self, desc: Option<String>) {
55-
self.desc = desc;
92+
let val: HeaderValue = Entry::new(name.clone(), Some(dur), Some(desc.clone()))?.into();
93+
assert_eq!(val, r#"Server; dur=1000; desc="A server timing""#);
94+
Ok(())
5695
}
5796
}

src/trace/server_timing/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ impl<'a> Iterator for IterMut<'a> {
128128
}
129129
}
130130

131-
mod test {
132-
const CASE1: &str =
133-
"Server-Timing: metric1; dur=1.1; desc=document, metric1; dur=1.2; desc=document";
134-
}
131+
// mod test {
132+
// const CASE1: &str =
133+
// "Server-Timing: metric1; dur=1.1; desc=document, metric1; dur=1.2; desc=document";
134+
// }

0 commit comments

Comments
 (0)