1use super::Annotations;
2
3use crate::utils::AttrList;
4
5use std::{
6 fmt::{Debug, Display},
7 str::FromStr,
8};
9
10mod dimension;
11mod model_variables;
12#[cfg(test)]
13mod tests;
14
15pub use dimension::Dimension;
16pub use model_variables::{AppendToModelVariables, ModelVariables, Variable};
17
18#[derive(PartialEq, Debug, Default, hard_xml::XmlRead, hard_xml::XmlWrite)]
20#[xml(tag = "Alias")]
21pub struct VariableAlias {
22 #[xml(attr = "name")]
23 pub name: String,
24 #[xml(attr = "description")]
25 pub description: Option<String>,
26}
27
28#[derive(PartialEq, Debug, Default, hard_xml::XmlRead, hard_xml::XmlWrite)]
30#[xml(tag = "Alias")]
31pub struct FloatVariableAlias {
32 #[xml(attr = "name")]
33 pub name: String,
34 #[xml(attr = "description")]
35 pub description: Option<String>,
36 #[xml(attr = "displayUnit")]
37 pub display_unit: Option<String>,
38}
39
40#[derive(Clone, Copy, Default, PartialEq, Debug)]
44pub enum IntervalVariability {
45 Constant,
46 Fixed,
47 Tunable,
48 Changing,
49 Countdown,
50 #[default]
52 Triggered,
53}
54
55impl FromStr for IntervalVariability {
56 type Err = String;
57
58 fn from_str(s: &str) -> Result<Self, Self::Err> {
59 match s {
60 "constant" => Ok(Self::Constant),
61 "fixed" => Ok(Self::Fixed),
62 "tunable" => Ok(Self::Tunable),
63 "changing" => Ok(Self::Changing),
64 "countdown" => Ok(Self::Countdown),
65 "triggered" => Ok(Self::Triggered),
66 _ => Err(format!("Invalid IntervalVariability: {}", s)),
67 }
68 }
69}
70
71impl Display for IntervalVariability {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 let s = match self {
74 Self::Constant => "constant",
75 Self::Fixed => "fixed",
76 Self::Tunable => "tunable",
77 Self::Changing => "changing",
78 Self::Countdown => "countdown",
79 Self::Triggered => "triggered",
80 };
81 write!(f, "{}", s)
82 }
83}
84
85#[derive(Debug, PartialEq, Clone, Copy)]
87pub enum VariableType {
88 FmiFloat32,
89 FmiFloat64,
90 FmiInt8,
91 FmiUInt8,
92 FmiInt16,
93 FmiUInt16,
94 FmiInt32,
95 FmiUInt32,
96 FmiInt64,
97 FmiUInt64,
98 FmiBoolean,
99 FmiString,
100 FmiBinary,
101 FmiClock,
102}
103
104#[cfg(feature = "arrow")]
105impl From<VariableType> for arrow::datatypes::DataType {
106 fn from(v: VariableType) -> Self {
107 match v {
108 VariableType::FmiFloat32 => arrow::datatypes::DataType::Float32,
109 VariableType::FmiFloat64 => arrow::datatypes::DataType::Float64,
110 VariableType::FmiInt8 => arrow::datatypes::DataType::Int8,
111 VariableType::FmiUInt8 => arrow::datatypes::DataType::UInt8,
112 VariableType::FmiInt16 => arrow::datatypes::DataType::Int16,
113 VariableType::FmiUInt16 => arrow::datatypes::DataType::UInt16,
114 VariableType::FmiInt32 => arrow::datatypes::DataType::Int32,
115 VariableType::FmiUInt32 => arrow::datatypes::DataType::UInt32,
116 VariableType::FmiInt64 => arrow::datatypes::DataType::Int64,
117 VariableType::FmiUInt64 => arrow::datatypes::DataType::UInt64,
118 VariableType::FmiBoolean => arrow::datatypes::DataType::Boolean,
119 VariableType::FmiString => arrow::datatypes::DataType::Utf8,
120 VariableType::FmiBinary => arrow::datatypes::DataType::Binary,
121 VariableType::FmiClock => arrow::datatypes::DataType::Boolean,
122 }
123 }
124}
125
126pub trait AbstractVariableTrait {
127 fn name(&self) -> &str;
129 fn value_reference(&self) -> u32;
132 fn description(&self) -> Option<&str>;
134 fn causality(&self) -> Causality;
136 fn variability(&self) -> Variability;
137 fn can_handle_multiple_set_per_time_instant(&self) -> Option<bool>;
138 fn clocks(&self) -> Option<&[u32]>;
139 fn data_type(&self) -> VariableType;
140 fn annotations(&self) -> Option<&Annotations>;
141}
142
143pub trait ArrayableVariableTrait: AbstractVariableTrait {
144 fn dimensions(&self) -> &[Dimension];
146 fn add_dimensions(&mut self, dims: &[Dimension]);
148 fn intermediate_update(&self) -> Option<bool>;
150 fn previous(&self) -> Option<u32>;
152}
153
154pub trait TypedVariableTrait {
155 fn declared_type(&self) -> Option<&str>;
156}
157
158pub trait TypedArrayableVariableTrait: ArrayableVariableTrait + TypedVariableTrait {}
159impl<T> TypedArrayableVariableTrait for T where T: ArrayableVariableTrait + TypedVariableTrait {}
160
161pub trait InitializableVariableTrait {
162 type StartType;
163 fn initial(&self) -> Option<Initial>;
164
165 fn start(&self) -> Option<&[Self::StartType]>;
166}
167
168macro_rules! impl_abstract_variable {
169 ($name: ident, $default_variability: expr, $variable_type: expr) => {
170 impl AbstractVariableTrait for $name {
171 fn name(&self) -> &str {
172 &self.name
173 }
174 fn value_reference(&self) -> u32 {
175 self.value_reference
176 }
177 fn description(&self) -> Option<&str> {
178 self.description.as_deref()
179 }
180 fn causality(&self) -> Causality {
181 self.causality.unwrap_or_default()
182 }
183 fn variability(&self) -> Variability {
184 self.variability.unwrap_or($default_variability)
185 }
186 fn can_handle_multiple_set_per_time_instant(&self) -> Option<bool> {
187 self.can_handle_multiple_set_per_time_instant
188 }
189 fn clocks(&self) -> Option<&[u32]> {
190 self.clocks.as_ref().map(|c| c.0.as_slice())
191 }
192 fn data_type(&self) -> VariableType {
193 $variable_type
194 }
195 fn annotations(&self) -> Option<&Annotations> {
196 self.annotations.as_ref()
197 }
198 }
199 };
200}
201
202macro_rules! impl_arrayable_variable {
203 ($name:ident) => {
204 impl ArrayableVariableTrait for $name {
205 fn dimensions(&self) -> &[Dimension] {
206 &self.dimensions
207 }
208 fn add_dimensions(&mut self, dims: &[Dimension]) {
209 self.dimensions.extend_from_slice(dims);
210 }
211 fn intermediate_update(&self) -> Option<bool> {
212 self.intermediate_update
213 }
214 fn previous(&self) -> Option<u32> {
215 self.previous
216 }
217 }
218 };
219}
220
221macro_rules! impl_typed_variable {
222 ($name:ident) => {
223 impl TypedVariableTrait for $name {
224 fn declared_type(&self) -> Option<&str> {
225 self.declared_type.as_deref()
226 }
227 }
228 };
229}
230
231macro_rules! impl_initializable_variable {
232 ($name: ident, $type: ty) => {
233 impl InitializableVariableTrait for $name {
234 type StartType = $type;
235
236 fn initial(&self) -> Option<Initial> {
237 self.initial
238 }
239
240 fn start(&self) -> Option<&[Self::StartType]> {
241 self.start.as_ref().map(|s| s.0.as_slice())
242 }
243 }
244 };
245}
246
247macro_rules! impl_float_type {
248 ($name:ident, $tag:expr, $type:ty, $variable_type:expr) => {
250 #[derive(PartialEq, Debug, Default, hard_xml::XmlRead, hard_xml::XmlWrite)]
251 #[xml(tag = $tag, strict(unknown_attribute, unknown_element))]
252 pub struct $name {
253 #[xml(attr = "name")]
254 pub name: String,
255 #[xml(attr = "valueReference")]
256 pub value_reference: u32,
257 #[xml(attr = "description")]
258 pub description: Option<String>,
259 #[xml(attr = "causality")]
260 pub causality: Option<Causality>,
261 #[xml(attr = "variability")]
262 pub variability: Option<Variability>,
263 #[xml(attr = "canHandleMultipleSetPerTimeInstant")]
264 pub can_handle_multiple_set_per_time_instant: Option<bool>,
265 #[xml(attr = "clocks")]
266 pub clocks: Option<AttrList<u32>>,
267 #[xml(attr = "declaredType")]
268 pub declared_type: Option<String>,
269 #[xml(child = "Dimension")]
270 pub dimensions: Vec<Dimension>,
271 #[xml(attr = "intermediateUpdate")]
272 pub intermediate_update: Option<bool>,
273 #[xml(attr = "previous")]
274 pub previous: Option<u32>,
275 #[xml(attr = "start")]
277 pub start: Option<AttrList<$type>>,
278 #[xml(attr = "initial")]
279 pub initial: Option<Initial>,
280 #[xml(attr = "min")]
281 pub min: Option<$type>,
282 #[xml(attr = "max")]
283 pub max: Option<$type>,
284 #[xml(attr = "derivative")]
285 pub derivative: Option<u32>,
286 #[xml(attr = "reinit")]
287 pub reinit: Option<bool>,
288 #[xml(child = "Annotations")]
289 pub annotations: Option<Annotations>,
290 #[xml(child = "Alias")]
291 pub aliases: Vec<FloatVariableAlias>,
292 }
293
294 impl_abstract_variable!($name, Variability::Continuous, $variable_type);
295 impl_arrayable_variable!($name);
296 impl_typed_variable!($name);
297 impl_initializable_variable!($name, $type);
298
299 impl $name {
300 pub fn derivative(&self) -> Option<u32> {
301 self.derivative
302 }
303
304 pub fn reinit(&self) -> Option<bool> {
305 self.reinit
306 }
307
308 pub fn new(
309 name: String,
310 value_reference: u32,
311 description: Option<String>,
312 causality: Causality,
313 variability: Variability,
314 start: Option<Vec<$type>>,
315 initial: Option<Initial>,
316 ) -> Self {
317 Self {
318 name,
319 value_reference,
320 description,
321 causality: Some(causality),
322 variability: Some(variability),
323 start: start.map(AttrList),
324 initial,
325 ..Default::default()
326 }
327 }
328 }
329 };
330}
331
332macro_rules! impl_integer_type {
333 ($name:ident, $tag:expr, $type:ty, $variable_type:expr) => {
335 #[derive(PartialEq, Debug, Default, hard_xml::XmlRead, hard_xml::XmlWrite)]
336 #[xml(tag = $tag, strict(unknown_attribute, unknown_element))]
337 pub struct $name {
338 #[xml(attr = "name")]
339 pub name: String,
340 #[xml(attr = "valueReference")]
341 pub value_reference: u32,
342 #[xml(attr = "description")]
343 pub description: Option<String>,
344 #[xml(attr = "causality")]
345 pub causality: Option<Causality>,
346 #[xml(attr = "variability")]
347 pub variability: Option<Variability>,
348 #[xml(attr = "canHandleMultipleSetPerTimeInstant")]
349 pub can_handle_multiple_set_per_time_instant: Option<bool>,
350 #[xml(attr = "clocks")]
351 pub clocks: Option<AttrList<u32>>,
352 #[xml(attr = "declaredType")]
353 pub declared_type: Option<String>,
354 #[xml(child = "Dimension")]
355 pub dimensions: Vec<Dimension>,
356 #[xml(attr = "intermediateUpdate")]
357 pub intermediate_update: Option<bool>,
358 #[xml(attr = "previous")]
359 pub previous: Option<u32>,
360 #[xml(attr = "start")]
362 pub start: Option<AttrList<$type>>,
363 #[xml(attr = "initial")]
364 pub initial: Option<Initial>,
365 #[xml(attr = "min")]
366 pub min: Option<$type>,
367 #[xml(attr = "max")]
368 pub max: Option<$type>,
369 #[xml(attr = "quantity")]
370 pub quantity: Option<String>,
371 #[xml(child = "Annotations")]
372 pub annotations: Option<Annotations>,
373 #[xml(child = "Alias")]
374 pub aliases: Vec<VariableAlias>,
375 }
376
377 impl_abstract_variable!($name, Variability::Discrete, $variable_type);
378 impl_arrayable_variable!($name);
379 impl_typed_variable!($name);
380 impl_initializable_variable!($name, $type);
381
382 impl $name {
383 pub fn new(
384 name: String,
385 value_reference: u32,
386 description: Option<String>,
387 causality: Causality,
388 variability: Variability,
389 start: Option<Vec<$type>>,
390 initial: Option<Initial>,
391 ) -> Self {
392 Self {
393 name,
394 value_reference,
395 description,
396 causality: Some(causality),
397 variability: Some(variability),
398 start: start.map(AttrList),
399 initial,
400 ..Default::default()
401 }
402 }
403 }
404 };
405}
406
407#[derive(Clone, Copy, Default, PartialEq, Debug)]
411pub enum Causality {
412 Parameter,
414 CalculatedParameter,
417 Input,
419 Output,
421 #[default]
423 Local,
424 Independent,
426 Dependent,
427 StructuralParameter,
429}
430
431impl FromStr for Causality {
432 type Err = String;
433
434 fn from_str(s: &str) -> Result<Self, Self::Err> {
435 match s {
436 "parameter" => Ok(Causality::Parameter),
437 "calculatedParameter" => Ok(Causality::CalculatedParameter),
438 "input" => Ok(Causality::Input),
439 "output" => Ok(Causality::Output),
440 "local" => Ok(Causality::Local),
441 "independent" => Ok(Causality::Independent),
442 "dependent" => Ok(Causality::Dependent),
443 "structuralParameter" => Ok(Causality::StructuralParameter),
444 _ => Err(format!("Invalid Causality: {}", s)),
445 }
446 }
447}
448
449impl Display for Causality {
450 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
451 match self {
452 Causality::Parameter => write!(f, "parameter"),
453 Causality::CalculatedParameter => write!(f, "calculatedParameter"),
454 Causality::Input => write!(f, "input"),
455 Causality::Output => write!(f, "output"),
456 Causality::Local => write!(f, "local"),
457 Causality::Independent => write!(f, "independent"),
458 Causality::Dependent => write!(f, "dependent"),
459 Causality::StructuralParameter => write!(f, "structuralParameter"),
460 }
461 }
462}
463
464#[derive(Clone, Copy, Default, PartialEq, Debug)]
470pub enum Variability {
471 Constant,
473 Fixed,
478 Tunable,
483 #[default]
490 Discrete,
491 Continuous,
497}
498
499impl FromStr for Variability {
500 type Err = String;
501
502 fn from_str(s: &str) -> Result<Self, Self::Err> {
503 match s {
504 "constant" => Ok(Variability::Constant),
505 "fixed" => Ok(Variability::Fixed),
506 "tunable" => Ok(Variability::Tunable),
507 "discrete" => Ok(Variability::Discrete),
508 "continuous" => Ok(Variability::Continuous),
509 _ => Err(format!("Invalid Variability: {}", s)),
510 }
511 }
512}
513
514impl Display for Variability {
515 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
516 match self {
517 Variability::Constant => write!(f, "constant"),
518 Variability::Fixed => write!(f, "fixed"),
519 Variability::Tunable => write!(f, "tunable"),
520 Variability::Discrete => write!(f, "discrete"),
521 Variability::Continuous => write!(f, "continuous"),
522 }
523 }
524}
525
526#[derive(Clone, Copy, Default, PartialEq, Debug)]
527pub enum Initial {
528 #[default]
529 Exact,
530 Approx,
531 Calculated,
532}
533
534impl FromStr for Initial {
535 type Err = String;
536
537 fn from_str(s: &str) -> Result<Self, Self::Err> {
538 match s {
539 "exact" => Ok(Initial::Exact),
540 "approx" => Ok(Initial::Approx),
541 "calculated" => Ok(Initial::Calculated),
542 _ => Err(format!("Invalid Initial: {}", s)),
543 }
544 }
545}
546
547impl Display for Initial {
548 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
549 match self {
550 Initial::Exact => write!(f, "exact"),
551 Initial::Approx => write!(f, "approx"),
552 Initial::Calculated => write!(f, "calculated"),
553 }
554 }
555}
556
557impl_float_type!(FmiFloat32, "Float32", f32, VariableType::FmiFloat32);
558impl_float_type!(FmiFloat64, "Float64", f64, VariableType::FmiFloat64);
559impl_integer_type!(FmiInt8, "Int8", i8, VariableType::FmiInt8);
560impl_integer_type!(FmiUInt8, "UInt8", u8, VariableType::FmiUInt8);
561impl_integer_type!(FmiInt16, "Int16", i16, VariableType::FmiInt16);
562impl_integer_type!(FmiUInt16, "UInt16", u16, VariableType::FmiUInt16);
563impl_integer_type!(FmiInt32, "Int32", i32, VariableType::FmiInt32);
564impl_integer_type!(FmiUInt32, "UInt32", u32, VariableType::FmiUInt32);
565impl_integer_type!(FmiInt64, "Int64", i64, VariableType::FmiInt64);
566impl_integer_type!(FmiUInt64, "UInt64", u64, VariableType::FmiUInt64);
567
568#[derive(Default, PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
569#[xml(tag = "Boolean", strict(unknown_attribute, unknown_element))]
570pub struct FmiBoolean {
571 #[xml(attr = "name")]
572 pub name: String,
573 #[xml(attr = "valueReference")]
574 pub value_reference: u32,
575 #[xml(attr = "description")]
576 pub description: Option<String>,
577 #[xml(attr = "causality")]
578 pub causality: Option<Causality>,
579 #[xml(attr = "variability")]
580 pub variability: Option<Variability>,
581 #[xml(attr = "canHandleMultipleSetPerTimeInstant")]
582 pub can_handle_multiple_set_per_time_instant: Option<bool>,
583 #[xml(attr = "clocks")]
584 pub clocks: Option<AttrList<u32>>,
585 #[xml(attr = "declaredType")]
586 pub declared_type: Option<String>,
587 #[xml(child = "Dimension")]
588 pub dimensions: Vec<Dimension>,
589 #[xml(attr = "intermediateUpdate")]
590 pub intermediate_update: Option<bool>,
591 #[xml(attr = "previous")]
592 pub previous: Option<u32>,
593 #[xml(attr = "initial")]
594 pub initial: Option<Initial>,
595 #[xml(attr = "start")]
596 pub start: Option<AttrList<bool>>,
597 #[xml(child = "Annotations")]
598 pub annotations: Option<Annotations>,
599 #[xml(child = "Alias")]
600 pub aliases: Vec<VariableAlias>,
601}
602
603impl_abstract_variable!(FmiBoolean, Variability::Discrete, VariableType::FmiBoolean);
604impl_arrayable_variable!(FmiBoolean);
605impl_typed_variable!(FmiBoolean);
606impl_initializable_variable!(FmiBoolean, bool);
607
608impl FmiBoolean {
609 pub fn new(
611 name: String,
612 value_reference: u32,
613 description: Option<String>,
614 causality: Causality,
615 variability: Variability,
616 start: Option<Vec<bool>>,
617 initial: Option<Initial>,
618 ) -> Self {
619 Self {
620 start: start.map(AttrList),
621 name,
622 value_reference,
623 description,
624 causality: Some(causality),
625 variability: Some(variability),
626 can_handle_multiple_set_per_time_instant: None,
627 clocks: None,
628 annotations: None,
629 dimensions: vec![],
630 intermediate_update: None,
631 previous: None,
632 declared_type: None,
633 initial,
634 aliases: vec![],
635 }
636 }
637}
638
639#[derive(PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
641#[xml(tag = "Start")]
642pub struct StringStart {
643 #[xml(attr = "value")]
644 pub value: String,
645}
646
647#[derive(Default, PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
648#[xml(tag = "String", strict(unknown_attribute, unknown_element))]
649pub struct FmiString {
650 #[xml(attr = "name")]
651 pub name: String,
652 #[xml(attr = "valueReference")]
653 pub value_reference: u32,
654 #[xml(attr = "description")]
655 pub description: Option<String>,
656 #[xml(attr = "causality")]
657 pub causality: Option<Causality>,
658 #[xml(attr = "variability")]
659 pub variability: Option<Variability>,
660 #[xml(attr = "canHandleMultipleSetPerTimeInstant")]
661 pub can_handle_multiple_set_per_time_instant: Option<bool>,
662 #[xml(attr = "clocks")]
663 pub clocks: Option<AttrList<u32>>,
664 #[xml(attr = "declaredType")]
665 pub declared_type: Option<String>,
666 #[xml(child = "Dimension")]
667 pub dimensions: Vec<Dimension>,
668 #[xml(attr = "intermediateUpdate")]
669 pub intermediate_update: Option<bool>,
670 #[xml(attr = "previous")]
671 pub previous: Option<u32>,
672 #[xml(child = "Start")]
674 pub start: Vec<StringStart>,
675 #[xml(attr = "initial")]
676 pub initial: Option<Initial>,
677 #[xml(child = "Annotations")]
678 pub annotations: Option<Annotations>,
679 #[xml(child = "Alias")]
680 pub aliases: Vec<VariableAlias>,
681}
682
683impl FmiString {
684 pub fn new(
686 name: String,
687 value_reference: u32,
688 description: Option<String>,
689 causality: Causality,
690 variability: Variability,
691 start: Option<Vec<String>>,
692 initial: Option<Initial>,
693 ) -> Self {
694 Self {
695 start: start
696 .unwrap_or_default()
697 .into_iter()
698 .map(|value| StringStart { value })
699 .collect(),
700 name,
701 value_reference,
702 description,
703 causality: Some(causality),
704 variability: Some(variability),
705 can_handle_multiple_set_per_time_instant: None,
706 clocks: None,
707 annotations: None,
708 dimensions: vec![],
709 intermediate_update: None,
710 previous: None,
711 declared_type: None,
712 initial,
713 aliases: vec![],
714 }
715 }
716}
717
718impl_abstract_variable!(FmiString, Variability::Discrete, VariableType::FmiString);
719impl_arrayable_variable!(FmiString);
720impl_typed_variable!(FmiString);
721impl InitializableVariableTrait for FmiString {
722 type StartType = StringStart;
723
724 fn initial(&self) -> Option<Initial> {
725 self.initial
726 }
727
728 fn start(&self) -> Option<&[Self::StartType]> {
729 if self.start.is_empty() {
730 None
731 } else {
732 Some(&self.start)
733 }
734 }
735}
736
737#[derive(PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
738#[xml(tag = "Start")]
739pub struct BinaryStart {
740 #[xml(attr = "value")]
741 pub value: String,
742}
743
744#[derive(Default, PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
745#[xml(tag = "Binary")]
746pub struct FmiBinary {
747 #[xml(attr = "name")]
748 pub name: String,
749 #[xml(attr = "valueReference")]
750 pub value_reference: u32,
751 #[xml(attr = "description")]
752 pub description: Option<String>,
753 #[xml(attr = "causality")]
754 pub causality: Option<Causality>,
755 #[xml(attr = "variability")]
756 pub variability: Option<Variability>,
757 #[xml(attr = "canHandleMultipleSetPerTimeInstant")]
758 pub can_handle_multiple_set_per_time_instant: Option<bool>,
759 #[xml(attr = "clocks")]
760 pub clocks: Option<AttrList<u32>>,
761 #[xml(attr = "declaredType")]
762 pub declared_type: Option<String>,
763 #[xml(child = "Dimension")]
764 pub dimensions: Vec<Dimension>,
765 #[xml(attr = "intermediateUpdate")]
766 pub intermediate_update: Option<bool>,
767 #[xml(attr = "previous")]
768 pub previous: Option<u32>,
769 #[xml(child = "Start")]
770 pub start: Vec<BinaryStart>,
771 #[xml(attr = "mimeType")]
772 pub mime_type: Option<String>,
773 #[xml(attr = "maxSize")]
774 pub max_size: Option<u32>,
775 #[xml(attr = "initial")]
776 pub initial: Option<Initial>,
777 #[xml(child = "Annotations")]
778 pub annotations: Option<Annotations>,
779 #[xml(child = "Alias")]
780 pub aliases: Vec<VariableAlias>,
781}
782
783fn default_mime_type() -> String {
784 "application/octet-stream".into()
785}
786
787impl FmiBinary {
788 pub fn new(
790 name: String,
791 value_reference: u32,
792 description: Option<String>,
793 causality: Causality,
794 variability: Variability,
795 start: Option<Vec<String>>,
796 initial: Option<Initial>,
797 ) -> Self {
798 Self {
799 start: start
800 .unwrap_or_default()
801 .into_iter()
802 .map(|value| BinaryStart { value })
803 .collect(),
804 mime_type: Some(default_mime_type()),
805 max_size: None,
806 name,
807 value_reference,
808 description,
809 causality: Some(causality),
810 variability: Some(variability),
811 can_handle_multiple_set_per_time_instant: None,
812 clocks: None,
813 annotations: None,
814 dimensions: vec![],
815 intermediate_update: None,
816 previous: None,
817 declared_type: None,
818 initial,
819 aliases: vec![],
820 }
821 }
822
823 pub fn decode_start_value(hex_string: &str) -> Result<Vec<u8>, std::num::ParseIntError> {
826 let cleaned = hex_string.replace(|c: char| c.is_whitespace(), "");
828 let hex_str = cleaned.strip_prefix("0x").unwrap_or(&cleaned);
829
830 (0..hex_str.len())
832 .step_by(2)
833 .map(|i| {
834 let byte_str = &hex_str[i..std::cmp::min(i + 2, hex_str.len())];
835 u8::from_str_radix(byte_str, 16)
836 })
837 .collect()
838 }
839}
840
841impl_abstract_variable!(FmiBinary, Variability::Discrete, VariableType::FmiBinary);
842impl_arrayable_variable!(FmiBinary);
843impl_typed_variable!(FmiBinary);
844
845impl InitializableVariableTrait for FmiBinary {
846 type StartType = BinaryStart;
847
848 fn initial(&self) -> Option<Initial> {
849 self.initial
850 }
851
852 fn start(&self) -> Option<&[Self::StartType]> {
853 if self.start.is_empty() {
854 None
855 } else {
856 Some(&self.start)
857 }
858 }
859}
860
861#[derive(Default, PartialEq, Debug, hard_xml::XmlRead, hard_xml::XmlWrite)]
863#[xml(tag = "Clock", strict(unknown_attribute, unknown_element))]
864pub struct FmiClock {
865 #[xml(attr = "name")]
866 pub name: String,
867 #[xml(attr = "valueReference")]
868 pub value_reference: u32,
869 #[xml(attr = "description")]
870 pub description: Option<String>,
871 #[xml(attr = "causality")]
872 pub causality: Option<Causality>,
873 #[xml(attr = "variability")]
874 pub variability: Option<Variability>,
875 #[xml(attr = "canHandleMultipleSetPerTimeInstant")]
876 pub can_handle_multiple_set_per_time_instant: Option<bool>,
877 #[xml(attr = "clocks")]
878 pub clocks: Option<AttrList<u32>>,
879 #[xml(attr = "declaredType")]
880 pub declared_type: Option<String>,
881 #[xml(attr = "canBeDeactivated")]
882 pub can_be_deactivated: Option<bool>,
883 #[xml(attr = "priority")]
884 pub priority: Option<i32>,
885 #[xml(attr = "intervalVariability")]
886 pub interval_variability: Option<IntervalVariability>,
887 #[xml(attr = "intervalDecimal")]
888 pub interval_decimal: Option<f64>,
889 #[xml(attr = "shiftDecimal")]
890 pub shift_decimal: Option<f64>,
891 #[xml(attr = "supportsFraction")]
892 pub supports_fraction: Option<bool>,
893 #[xml(attr = "resolution")]
894 pub resolution: Option<u64>,
895 #[xml(attr = "intervalCounter")]
896 pub interval_counter: Option<u64>,
897 #[xml(attr = "shiftCounter")]
898 pub shift_counter: Option<u64>,
899 #[xml(child = "Annotations")]
900 pub annotations: Option<Annotations>,
901 #[xml(child = "Alias")]
902 pub aliases: Vec<VariableAlias>,
903}
904
905impl_abstract_variable!(FmiClock, Variability::Discrete, VariableType::FmiClock);
906impl_typed_variable!(FmiClock);
907
908impl FmiClock {
909 pub fn new(
910 name: String,
911 value_reference: u32,
912 description: Option<String>,
913 causality: Causality,
914 variability: Variability,
915 ) -> Self {
916 Self {
917 name,
918 value_reference,
919 description,
920 causality: Some(causality),
921 variability: Some(variability),
922 can_handle_multiple_set_per_time_instant: None,
923 clocks: None,
924 declared_type: None,
925 can_be_deactivated: None,
926 priority: None,
927 interval_variability: None,
928 interval_decimal: None,
929 shift_decimal: None,
930 supports_fraction: None,
931 resolution: None,
932 interval_counter: None,
933 shift_counter: None,
934 annotations: None,
935 aliases: vec![],
936 }
937 }
938
939 pub fn interval_variability(&self) -> IntervalVariability {
940 self.interval_variability.unwrap_or_default()
941 }
942}