bo4e_core/com/
energy_mix.rs1use serde::{Deserialize, Serialize};
4
5use crate::enums::{Division, EcoCertificate, EcoLabel};
6use crate::traits::{Bo4eMeta, Bo4eObject};
7
8use super::EnergySource;
9
10#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
40#[serde(rename_all = "camelCase")]
41pub struct EnergyMix {
42 #[serde(flatten)]
44 pub meta: Bo4eMeta,
45
46 #[serde(skip_serializing_if = "Option::is_none")]
48 pub energy_mix_number: Option<i32>,
49
50 #[serde(skip_serializing_if = "Option::is_none")]
52 pub division: Option<Division>,
53
54 #[serde(skip_serializing_if = "Option::is_none")]
56 pub designation: Option<String>,
57
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub valid_year: Option<i32>,
61
62 #[serde(default, skip_serializing_if = "Vec::is_empty")]
64 pub sources: Vec<EnergySource>,
65
66 #[serde(skip_serializing_if = "Option::is_none")]
68 pub notes: Option<String>,
69
70 #[serde(skip_serializing_if = "Option::is_none")]
72 pub co2_emission: Option<f64>,
73
74 #[serde(skip_serializing_if = "Option::is_none")]
76 pub nuclear_waste: Option<f64>,
77
78 #[serde(default, skip_serializing_if = "Vec::is_empty")]
80 pub eco_certificates: Vec<EcoCertificate>,
81
82 #[serde(default, skip_serializing_if = "Vec::is_empty")]
84 pub eco_labels: Vec<EcoLabel>,
85
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub in_eco_top_ten: Option<bool>,
89
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub website: Option<String>,
93}
94
95impl Bo4eObject for EnergyMix {
96 fn type_name_german() -> &'static str {
97 "Energiemix"
98 }
99
100 fn type_name_english() -> &'static str {
101 "EnergyMix"
102 }
103
104 fn meta(&self) -> &Bo4eMeta {
105 &self.meta
106 }
107
108 fn meta_mut(&mut self) -> &mut Bo4eMeta {
109 &mut self.meta
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use crate::enums::GenerationType;
117
118 #[test]
119 fn test_green_energy_mix() {
120 let mix = EnergyMix {
121 energy_mix_number: Some(1),
122 designation: Some("100% Renewable".to_string()),
123 valid_year: Some(2024),
124 sources: vec![
125 EnergySource {
126 generation_type: Some(GenerationType::Solar),
127 percentage_share: Some(40.0),
128 ..Default::default()
129 },
130 EnergySource {
131 generation_type: Some(GenerationType::Wind),
132 percentage_share: Some(60.0),
133 ..Default::default()
134 },
135 ],
136 co2_emission: Some(0.0),
137 nuclear_waste: Some(0.0),
138 in_eco_top_ten: Some(true),
139 ..Default::default()
140 };
141
142 assert_eq!(mix.sources.len(), 2);
143 assert_eq!(mix.co2_emission, Some(0.0));
144 assert_eq!(mix.in_eco_top_ten, Some(true));
145 }
146
147 #[test]
148 fn test_default() {
149 let mix = EnergyMix::default();
150 assert!(mix.energy_mix_number.is_none());
151 assert!(mix.designation.is_none());
152 assert!(mix.sources.is_empty());
153 }
154
155 #[test]
156 fn test_serialize() {
157 let mix = EnergyMix {
158 energy_mix_number: Some(42),
159 designation: Some("Test Mix".to_string()),
160 valid_year: Some(2024),
161 co2_emission: Some(150.5),
162 ..Default::default()
163 };
164
165 let json = serde_json::to_string(&mix).unwrap();
166 assert!(json.contains(r#""energyMixNumber":42"#));
167 assert!(json.contains(r#""designation":"Test Mix""#));
168 assert!(json.contains(r#""co2Emission":150.5"#));
169 }
170
171 #[test]
172 fn test_roundtrip() {
173 let mix = EnergyMix {
174 energy_mix_number: Some(1),
175 division: Some(Division::Electricity),
176 designation: Some("Ökostrom".to_string()),
177 valid_year: Some(2024),
178 sources: vec![EnergySource {
179 generation_type: Some(GenerationType::Hydro),
180 percentage_share: Some(100.0),
181 ..Default::default()
182 }],
183 co2_emission: Some(0.0),
184 eco_labels: vec![EcoLabel::GruenerStrom],
185 in_eco_top_ten: Some(true),
186 website: Some("https://example.com/energiemix".to_string()),
187 ..Default::default()
188 };
189
190 let json = serde_json::to_string(&mix).unwrap();
191 let parsed: EnergyMix = serde_json::from_str(&json).unwrap();
192 assert_eq!(mix, parsed);
193 }
194
195 #[test]
196 fn test_bo4e_object_impl() {
197 assert_eq!(EnergyMix::type_name_german(), "Energiemix");
198 assert_eq!(EnergyMix::type_name_english(), "EnergyMix");
199 }
200}