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
97
98
99
100
101
102
103
104
|
use crate::{data::*, measurement::*};
use chrono::prelude::*;
/// A `MeasurementVisitor` that builds up `ThinEdgeJson`.
pub struct ThinEdgeJsonBuilder {
timestamp: Option<DateTime<FixedOffset>>,
inside_group: Option<MultiValueMeasurement>,
measurements: Vec<ThinEdgeValue>,
}
impl ThinEdgeJsonBuilder {
pub fn new() -> Self {
Self {
timestamp: None,
inside_group: None,
measurements: Vec::new(),
}
}
pub fn done(self) -> Result<ThinEdgeJson, ThinEdgeJsonBuilderError> {
if self.inside_group.is_some() {
return Err(ThinEdgeJsonBuilderError::UnexpectedOpenGroup);
}
if self.measurements.is_empty() {
return Err(ThinEdgeJsonBuilderError::EmptyThinEdgeJsonRoot);
}
Ok(ThinEdgeJson {
timestamp: self.timestamp,
values: self.measurements,
})
}
}
impl MeasurementVisitor for ThinEdgeJsonBuilder {
type Error = ThinEdgeJsonBuilderError;
fn visit_timestamp(&mut self, value: DateTime<FixedOffset>) -> Result<(), Self::Error> {
match self.timestamp {
None => {
self.timestamp = Some(value);
Ok(())
}
Some(_) => Err(ThinEdgeJsonBuilderError::DuplicatedTimestamp),
}
}
fn visit_measurement(&mut self, name: &str, value: f64) -> Result<(), Self::Error> {
if let Some(group) = &mut self.inside_group {
group.values.push((name, value).into());
} else {
self.measurements.push((name, value).into());
}
Ok(())
}
fn visit_start_group(&mut self, group: &str) -> Result<(), Self::Error> {
if self.inside_group.is_none() {
self.inside_group = Some(MultiValueMeasurement {
name: group.into(),
values: Vec::new(),
});
Ok(())
} else {
Err(ThinEdgeJsonBuilderError::UnexpectedStartOfGroup)
}
}
fn visit_end_group(&mut self) -> Result<(), Self::Error> {
match self.inside_group.take() {
Some(group) => {
if group.values.is_empty() {
return Err(ThinEdgeJsonBuilderError::EmptyThinEdgeJson { name: group.name });
} else {
self.measurements.push(ThinEdgeValue::Multi(group))
}
}
None => return Err(ThinEdgeJsonBuilderError::UnexpectedEndOfGroup),
}
Ok(())
}
}
#[derive(thiserror::Error, Debug)]
pub enum ThinEdgeJsonBuilderError {
#[error("Empty Thin Edge measurement: it must contain at least one measurement")]
EmptyThinEdgeJsonRoot,
#[error("Empty Thin Edge measurement: {name:?} must contain at least one measurement")]
EmptyThinEdgeJson { name: String },
#[error("... time stamp within a group")]
DuplicatedTimestamp,
#[error("Unexpected open group")]
UnexpectedOpenGroup,
#[error("Unexpected start of group")]
UnexpectedStartOfGroup,
#[error("Unexpected end of group")]
UnexpectedEndOfGroup,
}
|