bo4e_core/com/
interval.rs

1//! Interval component.
2
3use serde::{Deserialize, Serialize};
4
5use crate::enums::TimeUnit;
6use crate::traits::{Bo4eMeta, Bo4eObject};
7
8/// A time interval with duration and unit.
9///
10/// German: Intervall
11///
12/// # Example
13///
14/// ```rust
15/// use bo4e_core::com::Interval;
16/// use bo4e_core::enums::TimeUnit;
17///
18/// let interval = Interval {
19///     duration: Some(15),
20///     unit: Some(TimeUnit::Minute),
21///     ..Default::default()
22/// };
23/// ```
24#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
25#[serde(rename_all = "camelCase")]
26pub struct Interval {
27    /// BO4E metadata
28    #[serde(flatten)]
29    pub meta: Bo4eMeta,
30
31    /// Duration value (Dauer)
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub duration: Option<i32>,
34
35    /// Time unit (Zeiteinheit)
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub unit: Option<TimeUnit>,
38}
39
40impl Bo4eObject for Interval {
41    fn type_name_german() -> &'static str {
42        "Intervall"
43    }
44
45    fn type_name_english() -> &'static str {
46        "Interval"
47    }
48
49    fn meta(&self) -> &Bo4eMeta {
50        &self.meta
51    }
52
53    fn meta_mut(&mut self) -> &mut Bo4eMeta {
54        &mut self.meta
55    }
56}
57
58impl Interval {
59    /// Create a 15-minute interval (common for load profiles).
60    pub fn minutes_15() -> Self {
61        Self {
62            duration: Some(15),
63            unit: Some(TimeUnit::Minute),
64            ..Default::default()
65        }
66    }
67
68    /// Create an hourly interval.
69    pub fn hourly() -> Self {
70        Self {
71            duration: Some(1),
72            unit: Some(TimeUnit::Hour),
73            ..Default::default()
74        }
75    }
76
77    /// Create a daily interval.
78    pub fn daily() -> Self {
79        Self {
80            duration: Some(1),
81            unit: Some(TimeUnit::Day),
82            ..Default::default()
83        }
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_15_minute_interval() {
93        let interval = Interval::minutes_15();
94        assert_eq!(interval.duration, Some(15));
95        assert_eq!(interval.unit, Some(TimeUnit::Minute));
96    }
97
98    #[test]
99    fn test_hourly_interval() {
100        let interval = Interval::hourly();
101        assert_eq!(interval.duration, Some(1));
102        assert_eq!(interval.unit, Some(TimeUnit::Hour));
103    }
104
105    #[test]
106    fn test_roundtrip() {
107        let interval = Interval::daily();
108        let json = serde_json::to_string(&interval).unwrap();
109        let parsed: Interval = serde_json::from_str(&json).unwrap();
110        assert_eq!(interval, parsed);
111    }
112
113    #[test]
114    fn test_bo4e_object_impl() {
115        assert_eq!(Interval::type_name_german(), "Intervall");
116        assert_eq!(Interval::type_name_english(), "Interval");
117    }
118}