bo4e_core/com/
quantity.rs

1//! Quantity (Menge) component.
2
3use serde::{Deserialize, Serialize};
4
5use crate::enums::Unit;
6use crate::traits::{Bo4eMeta, Bo4eObject};
7
8/// A quantity with value and unit.
9///
10/// German: Menge
11///
12/// # Example
13///
14/// ```rust
15/// use bo4e_core::com::Quantity;
16/// use bo4e_core::enums::Unit;
17///
18/// let qty = Quantity {
19///     value: Some(3500.0),
20///     unit: Some(Unit::KilowattHour),
21///     ..Default::default()
22/// };
23/// ```
24#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
25#[serde(rename_all = "camelCase")]
26pub struct Quantity {
27    /// BO4E metadata
28    #[serde(flatten)]
29    pub meta: Bo4eMeta,
30
31    /// Numeric value (Wert)
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub value: Option<f64>,
34
35    /// Unit of measurement (Einheit)
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub unit: Option<Unit>,
38}
39
40impl Bo4eObject for Quantity {
41    fn type_name_german() -> &'static str {
42        "Menge"
43    }
44
45    fn type_name_english() -> &'static str {
46        "Quantity"
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 Quantity {
59    /// Create a quantity in kWh.
60    pub fn kwh(value: f64) -> Self {
61        Self {
62            value: Some(value),
63            unit: Some(Unit::KilowattHour),
64            ..Default::default()
65        }
66    }
67
68    /// Create a quantity in cubic meters.
69    pub fn cubic_meters(value: f64) -> Self {
70        Self {
71            value: Some(value),
72            unit: Some(Unit::CubicMeter),
73            ..Default::default()
74        }
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn test_kwh_quantity() {
84        let qty = Quantity::kwh(3500.0);
85        assert_eq!(qty.value, Some(3500.0));
86        assert_eq!(qty.unit, Some(Unit::KilowattHour));
87    }
88
89    #[test]
90    fn test_gas_quantity() {
91        let qty = Quantity::cubic_meters(1500.0);
92        assert_eq!(qty.unit, Some(Unit::CubicMeter));
93    }
94
95    #[test]
96    fn test_roundtrip() {
97        let qty = Quantity::kwh(12345.67);
98        let json = serde_json::to_string(&qty).unwrap();
99        let parsed: Quantity = serde_json::from_str(&json).unwrap();
100        assert_eq!(qty, parsed);
101    }
102
103    #[test]
104    fn test_bo4e_object_impl() {
105        assert_eq!(Quantity::type_name_german(), "Menge");
106        assert_eq!(Quantity::type_name_english(), "Quantity");
107    }
108}