1use std::{fmt::Display, str::FromStr};
2
3#[derive(Clone, Default, PartialEq, Debug)]
5pub enum Causality {
6 Parameter,
7 CalculatedParameter,
8 Input,
9 Output,
10 #[default]
11 Local,
12 Independent,
13}
14
15impl FromStr for Causality {
16 type Err = String;
17
18 fn from_str(s: &str) -> Result<Self, Self::Err> {
19 match s {
20 "parameter" => Ok(Causality::Parameter),
21 "calculatedParameter" => Ok(Causality::CalculatedParameter),
22 "input" => Ok(Causality::Input),
23 "output" => Ok(Causality::Output),
24 "local" => Ok(Causality::Local),
25 "independent" => Ok(Causality::Independent),
26 _ => Err(format!("Invalid Causality: {}", s)),
27 }
28 }
29}
30
31impl Display for Causality {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 let s = match self {
34 Causality::Parameter => "parameter",
35 Causality::CalculatedParameter => "calculatedParameter",
36 Causality::Input => "input",
37 Causality::Output => "output",
38 Causality::Local => "local",
39 Causality::Independent => "independent",
40 };
41 write!(f, "{}", s)
42 }
43}
44
45#[derive(Clone, Copy, Default, PartialEq, Debug)]
49pub enum Variability {
50 Constant,
52 Fixed,
54 Tunable,
56 Discrete,
59 #[default]
63 Continuous,
64}
65
66impl FromStr for Variability {
67 type Err = String;
68
69 fn from_str(s: &str) -> Result<Self, Self::Err> {
70 match s {
71 "constant" => Ok(Variability::Constant),
72 "fixed" => Ok(Variability::Fixed),
73 "tunable" => Ok(Variability::Tunable),
74 "discrete" => Ok(Variability::Discrete),
75 "continuous" => Ok(Variability::Continuous),
76 _ => Err(format!("Invalid Variability: {}", s)),
77 }
78 }
79}
80
81impl Display for Variability {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 let s = match self {
84 Variability::Constant => "constant",
85 Variability::Fixed => "fixed",
86 Variability::Tunable => "tunable",
87 Variability::Discrete => "discrete",
88 Variability::Continuous => "continuous",
89 };
90 write!(f, "{}", s)
91 }
92}
93
94#[derive(Clone, Default, PartialEq, Debug)]
95pub enum Initial {
96 #[default]
97 Exact,
98 Approx,
99 Calculated,
100}
101
102impl FromStr for Initial {
103 type Err = String;
104
105 fn from_str(s: &str) -> Result<Self, Self::Err> {
106 match s {
107 "exact" => Ok(Initial::Exact),
108 "approx" => Ok(Initial::Approx),
109 "calculated" => Ok(Initial::Calculated),
110 _ => Err(format!("Invalid Initial: {}", s)),
111 }
112 }
113}
114
115impl Display for Initial {
116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117 let s = match self {
118 Initial::Exact => "exact",
119 Initial::Approx => "approx",
120 Initial::Calculated => "calculated",
121 };
122 write!(f, "{}", s)
123 }
124}
125
126#[derive(Clone, Default, PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
127#[xml(tag = "Real")]
128pub struct Real {
129 #[xml(attr = "declaredType")]
131 pub declared_type: Option<String>,
132
133 #[xml(attr = "start")]
136 pub start: Option<f64>,
137
138 #[xml(attr = "derivative")]
141 pub derivative: Option<u32>,
142
143 #[xml(attr = "reinit")]
147 pub reinit: Option<bool>,
148}
149
150#[derive(Clone, Default, PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
151#[xml(tag = "Integer")]
152pub struct Integer {
153 #[xml(attr = "declaredType")]
155 pub declared_type: Option<String>,
156
157 #[xml(attr = "start")]
160 pub start: Option<i32>,
161}
162
163#[derive(Clone, Default, PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
164#[xml(tag = "Boolean")]
165pub struct Boolean {
166 #[xml(attr = "declaredType")]
168 pub declared_type: Option<String>,
169
170 #[xml(attr = "start")]
172 pub start: Option<bool>,
173}
174
175#[derive(Clone, PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
176pub enum ScalarVariableElement {
177 #[xml(tag = "Real")]
178 Real(Real),
179 #[xml(tag = "Integer")]
180 Integer(Integer),
181 #[xml(tag = "Boolean")]
182 Boolean(Boolean),
183 #[xml(tag = "String")]
184 String,
185 #[xml(tag = "Enumeration")]
186 Enumeration,
187}
188
189impl Default for ScalarVariableElement {
190 fn default() -> Self {
191 Self::Real(Real::default())
192 }
193}
194
195#[cfg(feature = "arrow")]
196impl ScalarVariableElement {
197 pub fn data_type(&self) -> arrow::datatypes::DataType {
198 match self {
199 ScalarVariableElement::Real(_) => arrow::datatypes::DataType::Float64,
200 ScalarVariableElement::Integer(_) => arrow::datatypes::DataType::Int32,
201 ScalarVariableElement::Boolean(_) => arrow::datatypes::DataType::Boolean,
202 ScalarVariableElement::String => arrow::datatypes::DataType::Utf8,
203 ScalarVariableElement::Enumeration => arrow::datatypes::DataType::Int32,
204 }
205 }
206}
207
208#[derive(Default, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
209#[xml(tag = "ScalarVariable", strict(unknown_attribute, unknown_element))]
210pub struct ScalarVariable {
211 #[xml(attr = "name")]
213 pub name: String,
214
215 #[xml(attr = "valueReference")]
217 pub value_reference: u32,
218
219 #[xml(attr = "description")]
221 pub description: Option<String>,
222
223 #[xml(attr = "causality", default)]
225 pub causality: Causality,
226
227 #[xml(attr = "variability")]
230 pub variability: Option<Variability>,
231
232 #[xml(attr = "initial")]
235 pub initial: Option<Initial>,
236
237 #[xml(
238 child = "Real",
239 child = "Integer",
240 child = "Boolean",
241 child = "String",
242 child = "Enumeration"
243 )]
244 pub elem: ScalarVariableElement,
245}
246
247impl ScalarVariable {
248 pub fn is_continuous_input(&self) -> bool {
249 matches!(
250 (&self.elem, &self.causality),
251 (ScalarVariableElement::Real { .. }, Causality::Input)
252 )
253 }
254}
255
256#[cfg(test)]
257mod tests {
258 use hard_xml::XmlRead;
259
260 use super::*;
261
262 #[test]
263 fn test_scalar_variable() {
264 let s = r#"
265 <ScalarVariable
266 name="inertia1.J"
267 valueReference="1073741824"
268 description="Moment of load inertia"
269 causality="parameter"
270 variability="fixed">
271 <Real declaredType="Modelica.SIunits.Inertia" start="1"/>
272 </ScalarVariable>
273 "#;
274 let sv = ScalarVariable::from_str(s).unwrap();
275 assert_eq!(sv.name, "inertia1.J");
276 assert_eq!(sv.value_reference, 1073741824);
277 assert_eq!(sv.description, Some("Moment of load inertia".into()));
278 assert_eq!(sv.causality, Causality::Parameter);
279 assert_eq!(sv.variability, Some(Variability::Fixed));
280 assert_eq!(
281 sv.elem,
282 ScalarVariableElement::Real(Real {
283 declared_type: Some("Modelica.SIunits.Inertia".to_string()),
284 start: Some(1.0),
285 derivative: None,
286 reinit: None
287 })
288 );
289 }
290}