bo4e_core/com/
hardware.rs

1//! Hardware component.
2
3use serde::{Deserialize, Serialize};
4
5use crate::enums::{DeviceCategory, DeviceType};
6use crate::traits::{Bo4eMeta, Bo4eObject};
7
8/// Hardware component for representing physical devices.
9///
10/// This component represents hardware devices that are not meters,
11/// such as transformers, communication equipment, or other technical devices.
12///
13/// German: Hardware
14///
15/// # Example
16///
17/// ```rust
18/// use bo4e_core::com::Hardware;
19///
20/// let hw = Hardware {
21///     device_number: Some("HW-2024-001".to_string()),
22///     description: Some("Current transformer".to_string()),
23///     ..Default::default()
24/// };
25/// ```
26#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
27#[serde(rename_all = "camelCase")]
28pub struct Hardware {
29    /// BO4E metadata
30    #[serde(flatten)]
31    pub meta: Bo4eMeta,
32
33    /// Device number assigned by the metering service operator (Gerätenummer)
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub device_number: Option<String>,
36
37    /// Description of the device (Bezeichnung)
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub description: Option<String>,
40
41    /// Category/class of the device (Geräteklasse)
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub device_category: Option<DeviceCategory>,
44
45    /// Specific type of the device (Gerätetyp)
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub device_type: Option<DeviceType>,
48}
49
50impl Bo4eObject for Hardware {
51    fn type_name_german() -> &'static str {
52        "Hardware"
53    }
54
55    fn type_name_english() -> &'static str {
56        "Hardware"
57    }
58
59    fn meta(&self) -> &Bo4eMeta {
60        &self.meta
61    }
62
63    fn meta_mut(&mut self) -> &mut Bo4eMeta {
64        &mut self.meta
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71
72    #[test]
73    fn test_hardware_default() {
74        let hw = Hardware::default();
75        assert!(hw.device_number.is_none());
76        assert!(hw.description.is_none());
77    }
78
79    #[test]
80    fn test_hardware_serialize() {
81        let hw = Hardware {
82            device_number: Some("HW-001".to_string()),
83            description: Some("Transformer unit".to_string()),
84            ..Default::default()
85        };
86
87        let json = serde_json::to_string(&hw).unwrap();
88        assert!(json.contains(r#""deviceNumber":"HW-001""#));
89        assert!(json.contains(r#""description":"Transformer unit""#));
90    }
91
92    #[test]
93    fn test_hardware_roundtrip() {
94        let hw = Hardware {
95            meta: Bo4eMeta::with_type("Hardware"),
96            device_number: Some("HW-2024-002".to_string()),
97            description: Some("Communication gateway".to_string()),
98            device_category: None,
99            device_type: None,
100        };
101
102        let json = serde_json::to_string(&hw).unwrap();
103        let parsed: Hardware = serde_json::from_str(&json).unwrap();
104        assert_eq!(hw, parsed);
105    }
106
107    #[test]
108    fn test_bo4e_object_impl() {
109        assert_eq!(Hardware::type_name_german(), "Hardware");
110        assert_eq!(Hardware::type_name_english(), "Hardware");
111    }
112}