server_timing/
lib.rs

1mod parser;
2
3pub use parser::Metric;
4
5#[derive(Debug, thiserror::Error)]
6pub enum Error<'a> {
7    #[error("parse error: {0}")]
8    ParseError(nom::Err<nom::error::Error<&'a str>>),
9    #[error("unexpected input: {0}")]
10    UnexpectedInput(&'a str),
11}
12
13impl<'a> From<nom::Err<nom::error::Error<&'a str>>> for Error<'a> {
14    fn from(e: nom::Err<nom::error::Error<&'a str>>) -> Self {
15        Error::ParseError(e)
16    }
17}
18
19pub fn parse_server_timing(input: &str) -> Result<Vec<Metric>, Error> {
20    let (input, metrics) = parser::server_timing(input)?;
21
22    if input.is_empty() {
23        Ok(metrics)
24    } else {
25        Err(Error::UnexpectedInput(input))
26    }
27}
28
29#[cfg(test)]
30mod test {
31    use super::{parse_server_timing, Error};
32
33    #[test]
34    fn test_parse_server_timing() {
35        let input = "foo;dur=12.3;desc=bar";
36        let metrics = parse_server_timing(input).unwrap();
37        assert_eq!(
38            metrics,
39            vec![("foo", vec![("dur", "12.3".into()), ("desc", "bar".into())])],
40        );
41    }
42
43    #[test]
44    fn test_parse_server_timing_error() {
45        let input = "foo extra input";
46        let result = parse_server_timing(input);
47        assert!(result.is_err());
48        assert!(matches!(
49            result,
50            Err(Error::UnexpectedInput(" extra input"))
51        ));
52    }
53}