1use yaserde_derive::{YaDeserialize, YaSerialize};
2
3use super::{
4 Float32Attributes, Float64Attributes, Int8Attributes, Int16Attributes, Int32Attributes,
5 Int64Attributes, IntegerBaseAttributes, RealBaseAttributes, RealVariableAttributes,
6 UInt8Attributes, UInt16Attributes, UInt32Attributes, UInt64Attributes,
7};
8
9use crate::{Error, default_wrapper};
10
11#[derive(Debug, PartialEq)]
13pub enum VariableType {
14 FmiFloat32,
15 FmiFloat64,
16 FmiInt8,
17 FmiUInt8,
18 FmiInt16,
19 FmiUInt16,
20 FmiInt32,
21 FmiUInt32,
22 FmiInt64,
23 FmiUInt64,
24 FmiBoolean,
25 FmiString,
26 FmiBinary,
27}
28
29#[cfg(feature = "arrow")]
30impl From<VariableType> for arrow::datatypes::DataType {
31 fn from(v: VariableType) -> Self {
32 match v {
33 VariableType::FmiFloat32 => arrow::datatypes::DataType::Float32,
34 VariableType::FmiFloat64 => arrow::datatypes::DataType::Float64,
35 VariableType::FmiInt8 => arrow::datatypes::DataType::Int8,
36 VariableType::FmiUInt8 => arrow::datatypes::DataType::UInt8,
37 VariableType::FmiInt16 => arrow::datatypes::DataType::Int16,
38 VariableType::FmiUInt16 => arrow::datatypes::DataType::UInt16,
39 VariableType::FmiInt32 => arrow::datatypes::DataType::Int32,
40 VariableType::FmiUInt32 => arrow::datatypes::DataType::UInt32,
41 VariableType::FmiInt64 => arrow::datatypes::DataType::Int64,
42 VariableType::FmiUInt64 => arrow::datatypes::DataType::UInt64,
43 VariableType::FmiBoolean => arrow::datatypes::DataType::Boolean,
44 VariableType::FmiString => arrow::datatypes::DataType::Utf8,
45 VariableType::FmiBinary => arrow::datatypes::DataType::Binary,
46 }
47 }
48}
49
50pub trait AbstractVariableTrait {
51 fn name(&self) -> &str;
53 fn value_reference(&self) -> u32;
56 fn description(&self) -> Option<&str>;
58 fn causality(&self) -> Causality;
60 fn variability(&self) -> Variability;
61 fn can_handle_multiple_set_per_time_instant(&self) -> Option<bool>;
62 fn data_type(&self) -> VariableType;
63}
64
65pub trait ArrayableVariableTrait: AbstractVariableTrait {
66 fn dimensions(&self) -> &[Dimension];
67 fn intermediate_update(&self) -> Option<bool>;
68 fn previous(&self) -> Option<u32>;
69}
70
71pub trait TypedArrayableVariableTrait: ArrayableVariableTrait {
72 fn declared_type(&self) -> Option<&str>;
73}
74
75pub trait InitializableVariableTrait: TypedArrayableVariableTrait {
76 fn initial(&self) -> Option<Initial>;
77}
78
79macro_rules! impl_abstract_variable {
80 ($name:ident, $default_variability:expr) => {
81 impl AbstractVariableTrait for $name {
82 fn name(&self) -> &str {
83 &self
84 .init_var
85 .typed_arrayable_var
86 .arrayable_var
87 .abstract_var
88 .name
89 }
90 fn value_reference(&self) -> u32 {
91 self.init_var
92 .typed_arrayable_var
93 .arrayable_var
94 .abstract_var
95 .value_reference
96 }
97 fn description(&self) -> Option<&str> {
98 self.init_var
99 .typed_arrayable_var
100 .arrayable_var
101 .abstract_var
102 .description
103 .as_deref()
104 }
105 fn causality(&self) -> Causality {
106 self.init_var
107 .typed_arrayable_var
108 .arrayable_var
109 .abstract_var
110 .causality
111 }
112 fn variability(&self) -> Variability {
113 self.init_var
114 .typed_arrayable_var
115 .arrayable_var
116 .abstract_var
117 .variability
118 .unwrap_or($default_variability)
119 }
120 fn can_handle_multiple_set_per_time_instant(&self) -> Option<bool> {
121 self.init_var
122 .typed_arrayable_var
123 .arrayable_var
124 .abstract_var
125 .can_handle_multiple_set_per_time_instant
126 }
127 fn data_type(&self) -> VariableType {
128 VariableType::$name
129 }
130 }
131 };
132}
133
134macro_rules! impl_arrayable_variable {
135 ($name:ident) => {
136 impl ArrayableVariableTrait for $name {
137 fn dimensions(&self) -> &[Dimension] {
138 &self.init_var.typed_arrayable_var.arrayable_var.dimensions
139 }
140 fn intermediate_update(&self) -> Option<bool> {
141 self.init_var
142 .typed_arrayable_var
143 .arrayable_var
144 .intermediate_update
145 }
146 fn previous(&self) -> Option<u32> {
147 self.init_var.typed_arrayable_var.arrayable_var.previous
148 }
149 }
150 };
151}
152
153macro_rules! impl_typed_arrayable_variable {
154 ($name:ident) => {
155 impl TypedArrayableVariableTrait for $name {
156 fn declared_type(&self) -> Option<&str> {
157 self.init_var.typed_arrayable_var.declared_type.as_deref()
158 }
159 }
160 };
161}
162
163macro_rules! impl_initializable_variable {
164 ($name:ident) => {
165 impl InitializableVariableTrait for $name {
166 fn initial(&self) -> Option<Initial> {
167 self.init_var.initial
168 }
169 }
170 };
171}
172
173macro_rules! impl_float_type {
174 ($name:ident, $root:literal, $type:ty, $float_attr:ident) => {
175 #[derive(Default, PartialEq, Debug, YaDeserialize, YaSerialize)]
176 #[yaserde(rename = $root)]
177 pub struct $name {
178 #[yaserde(flatten = true)]
179 pub base_attr: RealBaseAttributes,
180 #[yaserde(flatten = true)]
181 pub attr: $float_attr,
182 #[yaserde(flatten = true)]
183 pub init_var: InitializableVariable,
184 #[yaserde(attribute = true, rename = "start")]
185 pub start: Vec<$type>,
186 #[yaserde(flatten = true)]
187 pub real_var_attr: RealVariableAttributes,
188 }
189
190 impl_abstract_variable!($name, Variability::Continuous);
191 impl_arrayable_variable!($name);
192 impl_typed_arrayable_variable!($name);
193 impl_initializable_variable!($name);
194
195 impl $name {
196 pub fn start(&self) -> &[$type] {
197 &self.start
198 }
199
200 pub fn derivative(&self) -> Option<u32> {
201 self.real_var_attr.derivative
202 }
203
204 pub fn reinit(&self) -> Option<bool> {
205 self.real_var_attr.reinit
206 }
207 }
208 };
209}
210
211macro_rules! impl_integer_type {
212 ($name:ident, $root:literal, $type:ty, $int_attr:ident) => {
213 #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
214 #[yaserde(rename = $root)]
215 pub struct $name {
216 #[yaserde(flatten = true)]
217 pub base_attr: IntegerBaseAttributes,
218 #[yaserde(flatten = true)]
219 pub int_attr: $int_attr,
220 #[yaserde(attribute = true)]
222 pub start: Option<$type>,
223 #[yaserde(flatten = true)]
224 pub init_var: InitializableVariable,
225 }
226
227 impl_abstract_variable!($name, Variability::Discrete);
228 };
229}
230
231#[derive(Clone, Copy, Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
233pub enum Causality {
234 #[yaserde(rename = "parameter")]
236 Parameter,
237 #[yaserde(rename = "calculatedParameter")]
240 CalculatedParameter,
241 #[yaserde(rename = "input")]
243 Input,
244 #[yaserde(rename = "output")]
246 Output,
247 #[yaserde(rename = "local")]
249 #[default]
250 Local,
251 #[yaserde(rename = "independent")]
253 Independent,
254 #[yaserde(rename = "dependent")]
255 Dependent,
256 #[yaserde(rename = "structuralParameter")]
258 StructuralParameter,
259}
260
261#[derive(Clone, Copy, Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
267pub enum Variability {
268 #[yaserde(rename = "constant")]
270 Constant,
271 #[yaserde(rename = "fixed")]
276 Fixed,
277 #[yaserde(rename = "tunable")]
282 Tunable,
283 #[yaserde(rename = "discrete")]
290 #[default]
291 Discrete,
292 #[yaserde(rename = "continuous")]
298 Continuous,
299}
300
301#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
302pub struct Dimension {
303 #[yaserde(attribute = true)]
306 pub start: Option<u64>,
307 #[yaserde(attribute = true, rename = "valueReference")]
315 pub value_reference: Option<u32>,
316}
317
318#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
319pub struct AbstractVariable {
320 #[yaserde(attribute = true)]
321 pub name: String,
322 #[yaserde(attribute = true, rename = "valueReference")]
323 pub value_reference: u32,
324 #[yaserde(attribute = true)]
325 pub description: Option<String>,
326 #[yaserde(attribute = true, default = "default_wrapper")]
327 pub causality: Causality,
328 #[yaserde(attribute = true)]
329 pub variability: Option<Variability>,
330 #[yaserde(attribute = true, rename = "canHandleMultipleSetPerTimeInstant")]
331 pub can_handle_multiple_set_per_time_instant: Option<bool>,
332}
333
334#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
335pub struct ArrayableVariable {
336 #[yaserde(flatten = true)]
337 pub abstract_var: AbstractVariable,
338 #[yaserde(rename = "Dimension")]
340 pub dimensions: Vec<Dimension>,
341 #[yaserde(attribute = true, rename = "intermediateUpdate")]
342 pub intermediate_update: Option<bool>,
343 #[yaserde(attribute = true, rename = "previous")]
344 pub previous: Option<u32>,
345}
346
347#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
348pub struct TypedArrayableVariable {
349 #[yaserde(flatten = true)]
350 pub arrayable_var: ArrayableVariable,
351 #[yaserde(attribute = true, rename = "declaredType")]
352 pub declared_type: Option<String>,
353}
354
355#[derive(Clone, Copy, Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
356pub enum Initial {
357 #[yaserde(rename = "exact")]
358 #[default]
359 Exact,
360 #[yaserde(rename = "approx")]
361 Approx,
362 #[yaserde(rename = "calculated")]
363 Calculated,
364}
365
366#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
367pub struct InitializableVariable {
368 #[yaserde(flatten = true)]
369 pub typed_arrayable_var: TypedArrayableVariable,
370 #[yaserde(attribute = true)]
371 pub initial: Option<Initial>,
372}
373
374impl_float_type!(FmiFloat32, "Float32", f32, Float32Attributes);
375impl_float_type!(FmiFloat64, "Float64", f64, Float64Attributes);
376
377impl_integer_type!(FmiInt8, "Int8", i8, Int8Attributes);
378impl_arrayable_variable!(FmiInt8);
379impl_typed_arrayable_variable!(FmiInt8);
380impl_initializable_variable!(FmiInt8);
381
382impl_integer_type!(FmiUInt8, "UInt8", u8, UInt8Attributes);
383impl_arrayable_variable!(FmiUInt8);
384impl_typed_arrayable_variable!(FmiUInt8);
385impl_initializable_variable!(FmiUInt8);
386
387impl_integer_type!(FmiInt16, "Int16", i16, Int16Attributes);
388impl_arrayable_variable!(FmiInt16);
389impl_typed_arrayable_variable!(FmiInt16);
390impl_initializable_variable!(FmiInt16);
391
392impl_integer_type!(FmiUInt16, "UInt16", u16, UInt16Attributes);
393impl_arrayable_variable!(FmiUInt16);
394impl_typed_arrayable_variable!(FmiUInt16);
395impl_initializable_variable!(FmiUInt16);
396
397impl_integer_type!(FmiInt32, "Int32", i32, Int32Attributes);
398impl_arrayable_variable!(FmiInt32);
399impl_typed_arrayable_variable!(FmiInt32);
400impl_initializable_variable!(FmiInt32);
401
402impl_integer_type!(FmiUInt32, "UInt32", u32, UInt32Attributes);
403impl_arrayable_variable!(FmiUInt32);
404impl_typed_arrayable_variable!(FmiUInt32);
405impl_initializable_variable!(FmiUInt32);
406
407impl_integer_type!(FmiInt64, "Int64", i64, Int64Attributes);
408impl_arrayable_variable!(FmiInt64);
409impl_typed_arrayable_variable!(FmiInt64);
410impl_initializable_variable!(FmiInt64);
411
412impl_integer_type!(FmiUInt64, "UInt64", u64, UInt64Attributes);
413impl_arrayable_variable!(FmiUInt64);
414impl_typed_arrayable_variable!(FmiUInt64);
415impl_initializable_variable!(FmiUInt64);
416
417#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
418pub struct FmiBoolean {
419 #[yaserde(attribute = true, flatten = true)]
420 pub start: Vec<bool>,
421 #[yaserde(flatten = true)]
422 pub init_var: InitializableVariable,
423}
424
425impl_abstract_variable!(FmiBoolean, Variability::Discrete);
426impl_arrayable_variable!(FmiBoolean);
427impl_typed_arrayable_variable!(FmiBoolean);
428impl_initializable_variable!(FmiBoolean);
429
430#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
431pub struct StringStart {
432 #[yaserde(attribute = true, rename = "value")]
433 pub value: String,
434}
435
436#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
437pub struct FmiString {
438 #[yaserde(rename = "Start")]
439 pub start: Vec<StringStart>,
440 #[yaserde(flatten = true)]
441 pub init_var: InitializableVariable,
442}
443
444impl FmiString {
445 pub fn start(&self) -> impl Iterator<Item = &str> {
447 self.start.iter().map(|s| s.value.as_str())
448 }
449}
450
451impl_abstract_variable!(FmiString, Variability::Discrete);
452impl_arrayable_variable!(FmiString);
453impl_typed_arrayable_variable!(FmiString);
454impl_initializable_variable!(FmiString);
455
456#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
457pub struct BinaryStart {
458 #[yaserde(attribute = true, rename = "value")]
459 pub value: String,
460}
461
462impl BinaryStart {
463 pub fn as_bytes(&self) -> Result<Vec<u8>, Error> {
465 let raw: &str = self.value.as_ref();
466 let s = raw
467 .strip_prefix("0x")
468 .or_else(|| raw.strip_prefix("0X"))
469 .unwrap_or(raw);
470 let s: String = s
471 .chars()
472 .filter(|c| !c.is_ascii_whitespace() && *c != '_')
473 .collect();
474 assert!(
475 s.len() % 2 == 0,
476 "hex string must have an even number of digits"
477 );
478 (0..s.len())
479 .step_by(2)
480 .map(|i| u8::from_str_radix(&s[i..i + 2], 16))
481 .collect::<Result<Vec<u8>, _>>()
482 .map_err(|e| Error::Model(format!("failed to parse hex string: {}", e)))
483 }
484}
485
486#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
487pub struct FmiBinary {
488 #[yaserde(rename = "Start")]
489 pub start: Vec<BinaryStart>,
490 #[yaserde(attribute = true, rename = "mimeType", default = "default_mime_type")]
491 pub mime_type: String,
492 #[yaserde(attribute = true, rename = "maxSize")]
493 pub max_size: Option<u32>,
494 #[yaserde(flatten = true)]
495 pub init_var: InitializableVariable,
496}
497
498fn default_mime_type() -> String {
499 "application/octet-stream".into()
500}
501
502impl FmiBinary {
503 pub fn start(&self) -> impl Iterator<Item = &BinaryStart> {
505 self.start.iter()
506 }
507}
508
509impl_abstract_variable!(FmiBinary, Variability::Discrete);
510impl_arrayable_variable!(FmiBinary);
511impl_typed_arrayable_variable!(FmiBinary);
512impl_initializable_variable!(FmiBinary);
513
514#[cfg(test)]
530mod tests {
531 use super::*;
532
533 #[test]
534 fn test_int16() {
535 let xml = r#"<Int16 name="Int16_input" valueReference="15" causality="input" start="0"/>"#;
536 let var: FmiInt16 = yaserde::de::from_str(xml).unwrap();
537
538 assert_eq!(var.name(), "Int16_input");
539 assert_eq!(var.value_reference(), 15);
540 assert_eq!(var.causality(), Causality::Input);
541 assert_eq!(var.start, Some(0));
542 assert_eq!(var.variability(), Variability::Discrete); }
544
545 #[test]
546 fn test_float64() {
547 let xml = r#"<Float64
548 name="g"
549 valueReference="5"
550 causality="parameter"
551 variability="fixed"
552 initial="exact"
553 declaredType="Acceleration"
554 start="-9.81"
555 derivative="1"
556 description="Gravity acting on the ball"
557 />"#;
558 let var: FmiFloat64 = yaserde::de::from_str(xml).unwrap();
559
560 assert_eq!(var.name(), "g");
561 assert_eq!(var.value_reference(), 5);
562 assert_eq!(var.variability(), Variability::Fixed);
563 assert_eq!(var.initial(), Some(Initial::Exact));
564 assert_eq!(var.causality(), Causality::Parameter);
565 assert_eq!(var.declared_type(), Some("Acceleration"));
566 assert_eq!(var.start(), &[-9.81]);
567 assert_eq!(var.derivative(), Some(1));
568 assert_eq!(var.description(), Some("Gravity acting on the ball"));
569 assert_eq!(var.can_handle_multiple_set_per_time_instant(), None);
570 assert_eq!(var.intermediate_update(), None);
571 }
572
573 #[test]
574 fn test_dim_f64() {
575 let xml = r#"<Float64
576 name="A"
577 valueReference="4"
578 description="Matrix coefficient A"
579 causality="parameter"
580 variability="tunable"
581 start="1 0 0 0 1 0 0 0 1">
582 <Dimension valueReference="2"/>
583 <Dimension valueReference="2"/>
584 </Float64>"#;
585
586 let var: FmiFloat64 = yaserde::de::from_str(xml).unwrap();
587 assert_eq!(var.name(), "A");
588 assert_eq!(var.value_reference(), 4);
589 assert_eq!(var.variability(), Variability::Tunable);
590 assert_eq!(var.causality(), Causality::Parameter);
591 assert_eq!(var.description(), Some("Matrix coefficient A"));
592 assert_eq!(var.start, vec![1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]);
593 assert_eq!(var.dimensions().len(), 2);
594 assert_eq!(var.dimensions()[0].value_reference, Some(2));
595 }
596
597 #[test]
598 fn test_string() {
599 let xml = r#"<String name="String_parameter" valueReference="29" causality="parameter" variability="fixed">
600 <Start value="Set me!"/>
601 </String>"#;
602
603 let var: FmiString = yaserde::de::from_str(xml).unwrap();
604 assert_eq!(var.name(), "String_parameter");
605 assert_eq!(var.value_reference(), 29);
606 assert_eq!(var.variability(), Variability::Fixed);
607 assert_eq!(var.causality(), Causality::Parameter);
608 assert_eq!(var.start().next().unwrap(), "Set me!");
609 }
610
611 #[test]
612 fn test_binary() {
613 let xml = r#"
614 <Binary name="Binary_input" valueReference="31" causality="input">
615 <Start value="666f6f"/>
616 </Binary>"#;
617
618 let var: FmiBinary = yaserde::de::from_str(xml).unwrap();
619 assert_eq!(var.name(), "Binary_input");
620 assert_eq!(var.value_reference(), 31);
621 assert_eq!(var.causality(), Causality::Input);
622 let start0 = var.start().next().unwrap();
623 assert_eq!(start0.value.as_str(), "666f6f");
624 assert_eq!(start0.as_bytes(), Ok(vec![0x66, 0x6f, 0x6f]));
625 }
626
627 #[test]
628 fn test_float32() {
629 let xml =
630 r#"<Float32 name="float32_var" valueReference="10" causality="output" start="3.14"/>"#;
631 let var: FmiFloat32 = yaserde::de::from_str(xml).unwrap();
632
633 assert_eq!(var.name(), "float32_var");
634 assert_eq!(var.value_reference(), 10);
635 assert_eq!(var.causality(), Causality::Output);
636 assert_eq!(var.start(), &[3.14]);
637 assert_eq!(var.variability(), Variability::Continuous); assert_eq!(var.derivative(), None);
639 assert_eq!(var.reinit(), None);
640 }
641
642 #[test]
643 fn test_int8() {
644 let xml = r#"<Int8 name="int8_var" valueReference="20" causality="parameter" variability="fixed" start="-128"/>"#;
645 let var: FmiInt8 = yaserde::de::from_str(xml).unwrap();
646
647 assert_eq!(var.name(), "int8_var");
648 assert_eq!(var.value_reference(), 20);
649 assert_eq!(var.causality(), Causality::Parameter);
650 assert_eq!(var.start, Some(-128));
651 assert_eq!(var.variability(), Variability::Fixed);
652 }
653
654 #[test]
655 fn test_uint8() {
656 let xml = r#"<UInt8 name="uint8_var" valueReference="21" causality="local" start="255"/>"#;
657 let var: FmiUInt8 = yaserde::de::from_str(xml).unwrap();
658
659 assert_eq!(var.name(), "uint8_var");
660 assert_eq!(var.value_reference(), 21);
661 assert_eq!(var.causality(), Causality::Local);
662 assert_eq!(var.start, Some(255));
663 assert_eq!(var.variability(), Variability::Discrete); }
665
666 #[test]
667 fn test_uint16() {
668 let xml = r#"<UInt16 name="uint16_var" valueReference="22" causality="calculatedParameter" start="65535"/>"#;
669 let var: FmiUInt16 = yaserde::de::from_str(xml).unwrap();
670
671 assert_eq!(var.name(), "uint16_var");
672 assert_eq!(var.value_reference(), 22);
673 assert_eq!(var.causality(), Causality::CalculatedParameter);
674 assert_eq!(var.start, Some(65535));
675 }
676
677 #[test]
678 fn test_int32() {
679 let xml = r#"<Int32 name="int32_var" valueReference="23" causality="structuralParameter" variability="tunable" start="-2147483648"/>"#;
680 let var: FmiInt32 = yaserde::de::from_str(xml).unwrap();
681
682 assert_eq!(var.name(), "int32_var");
683 assert_eq!(var.value_reference(), 23);
684 assert_eq!(var.causality(), Causality::StructuralParameter);
685 assert_eq!(var.start, Some(-2147483648));
686 assert_eq!(var.variability(), Variability::Tunable);
687 }
688
689 #[test]
690 fn test_uint32() {
691 let xml = r#"<UInt32 name="uint32_var" valueReference="24" causality="independent" start="4294967295"/>"#;
692 let var: FmiUInt32 = yaserde::de::from_str(xml).unwrap();
693
694 assert_eq!(var.name(), "uint32_var");
695 assert_eq!(var.value_reference(), 24);
696 assert_eq!(var.causality(), Causality::Independent);
697 assert_eq!(var.start, Some(4294967295));
698 }
699
700 #[test]
701 fn test_int64() {
702 let xml = r#"<Int64 name="int64_var" valueReference="25" causality="dependent" start="-9223372036854775808"/>"#;
703 let var: FmiInt64 = yaserde::de::from_str(xml).unwrap();
704
705 assert_eq!(var.name(), "int64_var");
706 assert_eq!(var.value_reference(), 25);
707 assert_eq!(var.causality(), Causality::Dependent);
708 assert_eq!(var.start, Some(-9223372036854775808));
709 }
710
711 #[test]
712 fn test_uint64() {
713 let xml = r#"<UInt64 name="uint64_var" valueReference="26" causality="input" variability="constant" start="18446744073709551615"/>"#;
714 let var: FmiUInt64 = yaserde::de::from_str(xml).unwrap();
715
716 assert_eq!(var.name(), "uint64_var");
717 assert_eq!(var.value_reference(), 26);
718 assert_eq!(var.causality(), Causality::Input);
719 assert_eq!(var.start, Some(18446744073709551615));
720 assert_eq!(var.variability(), Variability::Constant);
721 }
722
723 #[test]
724 fn test_boolean() {
725 let xml = r#"<Boolean name="boolean_var" valueReference="30" causality="output" start="true false true"/>"#;
726 let var: FmiBoolean = yaserde::de::from_str(xml).unwrap();
727
728 assert_eq!(var.name(), "boolean_var");
729 assert_eq!(var.value_reference(), 30);
730 assert_eq!(var.causality(), Causality::Output);
731 assert_eq!(var.start, vec![true, false, true]);
732 assert_eq!(var.variability(), Variability::Discrete); }
734
735 #[test]
736 fn test_variable_with_all_attributes() {
737 let xml = r#"<Float64
738 name="complex_var"
739 valueReference="100"
740 description="A complex variable with many attributes"
741 causality="output"
742 variability="continuous"
743 canHandleMultipleSetPerTimeInstant="true"
744 intermediateUpdate="false"
745 previous="99"
746 initial="calculated"
747 declaredType="CustomType"
748 start="1.0 2.0"
749 derivative="101"
750 reinit="true">
751 <Dimension start="2"/>
752 </Float64>"#;
753
754 let var: FmiFloat64 = yaserde::de::from_str(xml).unwrap();
755 assert_eq!(var.name(), "complex_var");
756 assert_eq!(var.value_reference(), 100);
757 assert_eq!(
758 var.description(),
759 Some("A complex variable with many attributes")
760 );
761 assert_eq!(var.causality(), Causality::Output);
762 assert_eq!(var.variability(), Variability::Continuous);
763 assert_eq!(var.can_handle_multiple_set_per_time_instant(), Some(true));
764 assert_eq!(var.intermediate_update(), Some(false));
765 assert_eq!(var.previous(), Some(99));
766 assert_eq!(var.initial(), Some(Initial::Calculated));
767 assert_eq!(var.declared_type(), Some("CustomType"));
768 assert_eq!(var.start(), &[1.0, 2.0]);
769 assert_eq!(var.derivative(), Some(101));
770 assert_eq!(var.reinit(), Some(true));
771 assert_eq!(var.dimensions().len(), 1);
772 assert_eq!(var.dimensions()[0].start, Some(2));
773 }
774
775 #[test]
776 fn test_dimension_with_value_reference() {
777 let xml = r#"<Float32
778 name="matrix_var"
779 valueReference="200"
780 causality="parameter"
781 start="1.0 2.0 3.0 4.0">
782 <Dimension valueReference="201"/>
783 <Dimension start="2"/>
784 </Float32>"#;
785
786 let var: FmiFloat32 = yaserde::de::from_str(xml).unwrap();
787 assert_eq!(var.name(), "matrix_var");
788 assert_eq!(var.dimensions().len(), 2);
789 assert_eq!(var.dimensions()[0].value_reference, Some(201));
790 assert_eq!(var.dimensions()[0].start, None);
791 assert_eq!(var.dimensions()[1].value_reference, None);
792 assert_eq!(var.dimensions()[1].start, Some(2));
793 assert_eq!(var.start(), &[1.0, 2.0, 3.0, 4.0]);
794 }
795
796 #[test]
797 fn test_string_multiple_starts() {
798 let xml = r#"<String name="multi_string" valueReference="300" causality="parameter">
799 <Start value="First string"/>
800 <Start value="Second string"/>
801 <Start value="Third string"/>
802 </String>"#;
803
804 let var: FmiString = yaserde::de::from_str(xml).unwrap();
805 assert_eq!(var.name(), "multi_string");
806 let start_values: Vec<&str> = var.start().collect();
807 assert_eq!(
808 start_values,
809 vec!["First string", "Second string", "Third string"]
810 );
811 }
812
813 #[test]
814 fn test_binary_multiple_starts_and_attributes() {
815 let xml = r#"<Binary
816 name="multi_binary"
817 valueReference="400"
818 causality="input"
819 mimeType="application/custom"
820 maxSize="1024">
821 <Start value="48656c6c6f"/>
822 <Start value="576f726c64"/>
823 </Binary>"#;
824
825 let var: FmiBinary = yaserde::de::from_str(xml).unwrap();
826 assert_eq!(var.name(), "multi_binary");
827 assert_eq!(var.mime_type, "application/custom");
828 assert_eq!(var.max_size, Some(1024));
829
830 let start_values: Vec<&BinaryStart> = var.start().collect();
831 assert_eq!(start_values.len(), 2);
832 assert_eq!(start_values[0].value, "48656c6c6f");
833 assert_eq!(start_values[1].value, "576f726c64");
834
835 assert_eq!(
837 start_values[0].as_bytes(),
838 Ok(vec![0x48, 0x65, 0x6c, 0x6c, 0x6f])
839 ); assert_eq!(
841 start_values[1].as_bytes(),
842 Ok(vec![0x57, 0x6f, 0x72, 0x6c, 0x64])
843 ); }
845
846 #[test]
847 fn test_binary_hex_parsing_with_prefix() {
848 let xml = r#"<Binary name="hex_binary" valueReference="500" causality="input">
849 <Start value="0x48656C6C6F"/>
850 </Binary>"#;
851
852 let var: FmiBinary = yaserde::de::from_str(xml).unwrap();
853 let start0 = var.start().next().unwrap();
854 assert_eq!(start0.as_bytes(), Ok(vec![0x48, 0x65, 0x6C, 0x6C, 0x6F])); }
856
857 #[test]
858 fn test_binary_hex_parsing_with_whitespace() {
859 let xml = r#"<Binary name="spaced_binary" valueReference="600" causality="input">
860 <Start value="48 65 6c 6c 6f 20 57 6f 72 6c 64"/>
861 </Binary>"#;
862
863 let var: FmiBinary = yaserde::de::from_str(xml).unwrap();
864 let start0 = var.start().next().unwrap();
865 assert_eq!(
866 start0.as_bytes(),
867 Ok(vec![
868 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64
869 ])
870 ); }
872
873 #[test]
874 fn test_initial_values() {
875 let xml_exact =
876 r#"<Float64 name="exact_var" valueReference="700" initial="exact" start="1.0"/>"#;
877 let var_exact: FmiFloat64 = yaserde::de::from_str(xml_exact).unwrap();
878 assert_eq!(var_exact.initial(), Some(Initial::Exact));
879
880 let xml_approx =
881 r#"<Float64 name="approx_var" valueReference="701" initial="approx" start="1.0"/>"#;
882 let var_approx: FmiFloat64 = yaserde::de::from_str(xml_approx).unwrap();
883 assert_eq!(var_approx.initial(), Some(Initial::Approx));
884
885 let xml_calculated =
886 r#"<Float64 name="calc_var" valueReference="702" initial="calculated" start="1.0"/>"#;
887 let var_calculated: FmiFloat64 = yaserde::de::from_str(xml_calculated).unwrap();
888 assert_eq!(var_calculated.initial(), Some(Initial::Calculated));
889 }
890
891 #[test]
892 fn test_data_type_enum() {
893 let float32_var: FmiFloat32 = Default::default();
894 assert_eq!(float32_var.data_type(), VariableType::FmiFloat32);
895
896 let float64_var: FmiFloat64 = Default::default();
897 assert_eq!(float64_var.data_type(), VariableType::FmiFloat64);
898
899 let int8_var: FmiInt8 = Default::default();
900 assert_eq!(int8_var.data_type(), VariableType::FmiInt8);
901
902 let uint8_var: FmiUInt8 = Default::default();
903 assert_eq!(uint8_var.data_type(), VariableType::FmiUInt8);
904
905 let int16_var: FmiInt16 = Default::default();
906 assert_eq!(int16_var.data_type(), VariableType::FmiInt16);
907
908 let uint16_var: FmiUInt16 = Default::default();
909 assert_eq!(uint16_var.data_type(), VariableType::FmiUInt16);
910
911 let int32_var: FmiInt32 = Default::default();
912 assert_eq!(int32_var.data_type(), VariableType::FmiInt32);
913
914 let uint32_var: FmiUInt32 = Default::default();
915 assert_eq!(uint32_var.data_type(), VariableType::FmiUInt32);
916
917 let int64_var: FmiInt64 = Default::default();
918 assert_eq!(int64_var.data_type(), VariableType::FmiInt64);
919
920 let uint64_var: FmiUInt64 = Default::default();
921 assert_eq!(uint64_var.data_type(), VariableType::FmiUInt64);
922
923 let boolean_var: FmiBoolean = Default::default();
924 assert_eq!(boolean_var.data_type(), VariableType::FmiBoolean);
925
926 let string_var: FmiString = Default::default();
927 assert_eq!(string_var.data_type(), VariableType::FmiString);
928
929 let binary_var: FmiBinary = Default::default();
930 assert_eq!(binary_var.data_type(), VariableType::FmiBinary);
931 }
932
933 #[cfg(feature = "arrow")]
934 #[test]
935 fn test_arrow_data_type_conversion() {
936 use arrow::datatypes::DataType;
937
938 assert_eq!(DataType::from(VariableType::FmiFloat32), DataType::Float32);
939 assert_eq!(DataType::from(VariableType::FmiFloat64), DataType::Float64);
940 assert_eq!(DataType::from(VariableType::FmiInt8), DataType::Int8);
941 assert_eq!(DataType::from(VariableType::FmiUInt8), DataType::UInt8);
942 assert_eq!(DataType::from(VariableType::FmiInt16), DataType::Int16);
943 assert_eq!(DataType::from(VariableType::FmiUInt16), DataType::UInt16);
944 assert_eq!(DataType::from(VariableType::FmiInt32), DataType::Int32);
945 assert_eq!(DataType::from(VariableType::FmiUInt32), DataType::UInt32);
946 assert_eq!(DataType::from(VariableType::FmiInt64), DataType::Int64);
947 assert_eq!(DataType::from(VariableType::FmiUInt64), DataType::UInt64);
948 assert_eq!(DataType::from(VariableType::FmiBoolean), DataType::Boolean);
949 assert_eq!(DataType::from(VariableType::FmiString), DataType::Utf8);
950 assert_eq!(DataType::from(VariableType::FmiBinary), DataType::Binary);
951 }
952}