summaryrefslogtreecommitdiffstats
path: root/crates/core/thin_edge_json/src/measurement.rs
blob: 51058db05d380d8026f5ef911d77d3f139451236 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use time::OffsetDateTime;

/// The `MeasurementVisitor` trait represents the capability to visit a series of measurements, possibly grouped.
///
/// Here is an implementation of the `MeasurementVisitor` trait that prints the measurements:
///
/// ```
/// # use thin_edge_json::measurement::*;
/// # use time::{OffsetDateTime, format_description};
///
/// struct MeasurementPrinter {
///     group: Option<String>,
/// }
///
/// #[derive(thiserror::Error, Debug)]
/// pub enum MeasurementError {
///     #[error("Unexpected time stamp within a group")]
///     UnexpectedTimestamp,
///
///     #[error("Unexpected end of group")]
///     UnexpectedEndOfGroup,
///
///     #[error("Unexpected start of group")]
///     UnexpectedStartOfGroup,
/// }
///
/// impl MeasurementVisitor for MeasurementPrinter {
///     type Error = MeasurementError;
///
///     fn visit_timestamp(&mut self, timestamp: OffsetDateTime) -> Result<(), Self::Error> {
///         let format =
///             format_description::parse("[day] [month repr:short] [year] [hour repr:24]:[minute]:[seconds] [offset_hour sign:mandatory]:[offset_minute]").unwrap();
///         if self.group.is_none() {
///             Ok(println!("time = {}", timestamp.format(&format).unwrap()))
///         } else {
///             Err(MeasurementError::UnexpectedTimestamp)
///         }
///     }
///
///     fn visit_measurement(&mut self, name: &str, value: f64) -> Result<(), Self::Error> {
///         if let Some(group_name) = self.group.as_ref() {
///             Ok(println!("{}.{} = {}", group_name, name, value))
///         } else {
///             Ok(println!("{} = {}", name, value))
///         }
///     }
///
///     fn visit_start_group(&mut self, group: &str) -> Result<(), Self::Error> {
///         if self.group.is_none() {
///             self.group = Some(group.to_owned());
///             Ok(())
///         } else {
///             Err(MeasurementError::UnexpectedStartOfGroup)
///         }
///     }
///
///     fn visit_end_group(&mut self) -> Result<(), Self::Error> {
///         if self.group.is_none() {
///             Err(MeasurementError::UnexpectedEndOfGroup)
///         } else {
///             self.group = None;
///             Ok(())
///         }
///     }
/// }
/// ```
pub trait MeasurementVisitor {
    /// Error type specific to this visitor.
    type Error: std::error::Error + std::fmt::Debug;

    /// Set the timestamp shared by all the measurements of this series.
    fn visit_timestamp(&mut self, value: OffsetDateTime) -> Result<(), Self::Error>;

    /// Add a new measurement, attached to the current group if any.
    fn visit_measurement(&mut self, name: &str, value: f64) -> Result<(), Self::Error>;

    /// Start to gather measurements for a group.
    fn visit_start_group(&mut self, group: &str) -> Result<(), Self::Error>;

    /// End to gather measurements for the current group.
    fn visit_end_group(&mut self) -> Result<(), Self::Error>;

    /// A single measurement contained in `group`. Defaults to a sequence of
    /// `visit_start_group`, `visit_measurement` and `visit_end_group`.
    fn visit_grouped_measurement(
        &mut self,
        group: &str,
        name: &str,
        value: f64,
    ) -> Result<(), Self::Error> {
        self.visit_start_group(group)?;
        self.visit_measurement(name, value)?;
        self.visit_end_group()?;
        Ok(())
    }
}