autosar_data_abstraction/datatype/
values.rs

1use std::str::FromStr;
2
3use crate::{
4    AbstractionElement, ArPackage, AutosarAbstractionError, Element, IdentifiableAbstractionElement,
5    abstraction_element,
6    datatype::{ApplicationArrayElement, ApplicationPrimitiveCategory, ApplicationRecordElement, Unit},
7    software_component::{ArgumentDataPrototype, ParameterDataPrototype, VariableDataPrototype},
8};
9use autosar_data::{ElementName, EnumItem};
10
11//#########################################################
12
13/// Specification of a constant that can be part of a package, i.e. it can be defined stand-alone.
14/// These constant values can be referenced from value specifications.
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct ConstantSpecification(Element);
17abstraction_element!(ConstantSpecification, ConstantSpecification);
18impl IdentifiableAbstractionElement for ConstantSpecification {}
19
20impl ConstantSpecification {
21    pub(crate) fn new(
22        name: &str,
23        package: &ArPackage,
24        value: ValueSpecification,
25    ) -> Result<ConstantSpecification, AutosarAbstractionError> {
26        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
27
28        let const_spec_elem = elements
29            .create_named_sub_element(ElementName::ConstantSpecification, name)
30            .unwrap();
31        let const_spec = Self(const_spec_elem);
32        // let const_spec = Self(elements.create_named_sub_element(ElementName::ConstantSpecification, name)?);
33        const_spec.set_value_specification(value)?;
34
35        Ok(const_spec)
36    }
37
38    /// set the value specification of the constant
39    pub fn set_value_specification<T: Into<ValueSpecification>>(
40        &self,
41        value: T,
42    ) -> Result<(), AutosarAbstractionError> {
43        let value: ValueSpecification = value.into();
44        // remove the existing value
45        let _ = self.element().remove_sub_element_kind(ElementName::ValueSpec);
46        let value_spec_elem = self.element().create_sub_element(ElementName::ValueSpec)?;
47        value.store(&value_spec_elem)?;
48        Ok(())
49    }
50
51    /// get the value specification of the constant
52    #[must_use]
53    pub fn value_specification(&self) -> Option<ValueSpecification> {
54        let spec_elem = self
55            .element()
56            .get_sub_element(ElementName::ValueSpec)
57            .and_then(|vs_elem| vs_elem.get_sub_element_at(0))?;
58        ValueSpecification::load(&spec_elem)
59    }
60}
61
62//#########################################################
63
64/// array of values
65#[derive(Debug, Clone, PartialEq)]
66pub struct ArrayValueSpecification {
67    /// SHORT-LABEL: used to identify the array in a human readable way. This is used when the array is part of a record.
68    pub label: Option<String>,
69    /// the values of the array
70    pub values: Vec<ValueSpecification>,
71}
72
73impl ArrayValueSpecification {
74    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
75        let array_elem = parent.create_sub_element(ElementName::ArrayValueSpecification)?;
76        store_label(&array_elem, &self.label)?;
77        let elements_elem = array_elem.create_sub_element(ElementName::Elements)?;
78        for value in &self.values {
79            value.store(&elements_elem)?;
80        }
81        Ok(())
82    }
83
84    fn load(element: &Element) -> Option<Self> {
85        let label = load_label(element);
86        let elements_elem = element.get_sub_element(ElementName::Elements)?;
87        let values = elements_elem
88            .sub_elements()
89            .filter_map(|elem| ValueSpecification::load(&elem))
90            .collect::<Vec<_>>();
91
92        Some(Self { label, values })
93    }
94}
95
96impl From<ArrayValueSpecification> for ValueSpecification {
97    fn from(value_spec: ArrayValueSpecification) -> Self {
98        ValueSpecification::Array(value_spec)
99    }
100}
101
102//#########################################################
103
104/// record of values. The values may be named using short-labels, but these are not mandatory.
105#[derive(Debug, Clone, PartialEq)]
106pub struct RecordValueSpecification {
107    /// SHORT-LABEL: used to identify the record in a human readable way. This is used when the record is part of a record.
108    pub label: Option<String>,
109    /// the values of the record
110    /// The values may be named using short-labels, but these are not mandatory.
111    pub values: Vec<ValueSpecification>,
112}
113
114impl RecordValueSpecification {
115    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
116        let record_elem = parent.create_sub_element(ElementName::RecordValueSpecification)?;
117        store_label(&record_elem, &self.label)?;
118        let fields_elem = record_elem.create_sub_element(ElementName::Fields)?;
119        for value in &self.values {
120            value.store(&fields_elem)?;
121        }
122        Ok(())
123    }
124
125    fn load(element: &Element) -> Option<Self> {
126        let label = load_label(element);
127        let fields_elem = element.get_sub_element(ElementName::Fields)?;
128        let values = fields_elem
129            .sub_elements()
130            .filter_map(|elem| ValueSpecification::load(&elem))
131            .collect::<Vec<_>>();
132
133        Some(Self { label, values })
134    }
135}
136
137impl From<RecordValueSpecification> for ValueSpecification {
138    fn from(value_spec: RecordValueSpecification) -> Self {
139        ValueSpecification::Record(value_spec)
140    }
141}
142
143//#########################################################
144
145/// textual value
146#[derive(Debug, Clone, PartialEq)]
147pub struct TextValueSpecification {
148    /// SHORT-LABEL: used to identify the text in a human readable way. This is used when the text is part of a record.
149    pub label: Option<String>,
150    /// the text value
151    pub value: String,
152}
153
154impl TextValueSpecification {
155    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
156        let text_elem = parent.create_sub_element(ElementName::TextValueSpecification)?;
157        store_label(&text_elem, &self.label)?;
158        let value_elem = text_elem.create_sub_element(ElementName::Value)?;
159        value_elem.set_character_data(self.value.clone())?;
160        Ok(())
161    }
162
163    fn load(element: &Element) -> Option<Self> {
164        let label = load_label(element);
165        let value = element
166            .get_sub_element(ElementName::Value)?
167            .character_data()?
168            .string_value()?;
169
170        Some(Self { label, value })
171    }
172}
173
174impl From<TextValueSpecification> for ValueSpecification {
175    fn from(value_spec: TextValueSpecification) -> Self {
176        ValueSpecification::Text(value_spec)
177    }
178}
179
180//#########################################################
181
182/// numerical value
183#[derive(Debug, Clone, PartialEq)]
184pub struct NumericalValueSpecification {
185    /// SHORT-LABEL: used to identify the number in a human readable way. This is used when the number is part of a record.
186    pub label: Option<String>,
187    /// the number value
188    pub value: f64,
189}
190
191impl NumericalValueSpecification {
192    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
193        let num_elem = parent.create_sub_element(ElementName::NumericalValueSpecification)?;
194        store_label(&num_elem, &self.label)?;
195        let value_elem = num_elem.create_sub_element(ElementName::Value)?;
196        value_elem.set_character_data(self.value)?;
197        Ok(())
198    }
199
200    fn load(element: &Element) -> Option<Self> {
201        let label = load_label(element);
202        let value = element
203            .get_sub_element(ElementName::Value)?
204            .character_data()?
205            .parse_float()?;
206
207        Some(Self { label, value })
208    }
209}
210
211impl From<NumericalValueSpecification> for ValueSpecification {
212    fn from(value_spec: NumericalValueSpecification) -> Self {
213        ValueSpecification::Numerical(value_spec)
214    }
215}
216
217//#########################################################
218
219/// reference to a `ConstantValue`
220#[derive(Debug, Clone, PartialEq)]
221pub struct ConstantReference {
222    /// SHORT-LABEL: used to identify the constant in a human readable way. This is used when the constant is part of a record.
223    pub label: Option<String>,
224    /// Reference to the constant specification
225    pub constant: ConstantSpecification,
226}
227
228impl ConstantReference {
229    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
230        let const_ref_elem = parent.create_sub_element(ElementName::ConstantReference)?;
231        store_label(&const_ref_elem, &self.label)?;
232        const_ref_elem
233            .create_sub_element(ElementName::ConstantRef)
234            .and_then(|cr_elem| cr_elem.set_reference_target(self.constant.element()))?;
235        Ok(())
236    }
237
238    fn load(element: &Element) -> Option<Self> {
239        let label = load_label(element);
240        let constant_elem = element
241            .get_sub_element(ElementName::ConstantRef)?
242            .get_reference_target()
243            .ok()?;
244        let constant = ConstantSpecification::try_from(constant_elem).ok()?;
245
246        Some(Self { label, constant })
247    }
248}
249
250impl From<ConstantReference> for ValueSpecification {
251    fn from(value_spec: ConstantReference) -> Self {
252        ValueSpecification::ConstantReference(value_spec)
253    }
254}
255
256//#########################################################
257
258/// Application value
259#[derive(Debug, Clone, PartialEq)]
260pub struct ApplicationValueSpecification {
261    /// SHORT-LABEL: used to identify the application value in a human readable way. This is used when the application value is part of a record.
262    pub label: Option<String>,
263    /// category of the application value
264    pub category: ApplicationPrimitiveCategory,
265    /// axis values of a compound primitive data type. Required for categories `ResAxis`, Cure, Map, Cuboid, Cube4, Cube5
266    pub sw_axis_conts: Vec<SwAxisCont>,
267    /// values of a compound primitive data type
268    pub sw_value_cont: SwValueCont,
269}
270
271impl ApplicationValueSpecification {
272    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
273        let app_elem = parent.create_sub_element(ElementName::ApplicationValueSpecification)?;
274        store_label(&app_elem, &self.label)?;
275        let category_elem = app_elem.create_sub_element(ElementName::Category)?;
276        category_elem.set_character_data(self.category.to_string())?;
277        let sw_axis_conts_elem = app_elem.create_sub_element(ElementName::SwAxisConts)?;
278        for sw_axis in &self.sw_axis_conts {
279            sw_axis.store(&sw_axis_conts_elem)?;
280        }
281        let sw_value_cont_elem = app_elem.create_sub_element(ElementName::SwValueCont)?;
282        self.sw_value_cont.store(&sw_value_cont_elem)?;
283
284        Ok(())
285    }
286
287    fn load(element: &Element) -> Option<Self> {
288        let label = load_label(element);
289        let category_string = element
290            .get_sub_element(ElementName::Category)?
291            .character_data()?
292            .string_value()?;
293        let category = ApplicationPrimitiveCategory::from_str(&category_string).ok()?;
294        let sw_axis_conts_elem = element.get_sub_element(ElementName::SwAxisConts)?;
295        let sw_axis_conts = sw_axis_conts_elem
296            .sub_elements()
297            .filter_map(|elem| SwAxisCont::load(&elem))
298            .collect::<Vec<_>>();
299        let sw_value_cont_elem = element.get_sub_element(ElementName::SwValueCont)?;
300        let sw_value_cont = SwValueCont::load(&sw_value_cont_elem)?;
301
302        Some(Self {
303            label,
304            category,
305            sw_axis_conts,
306            sw_value_cont,
307        })
308    }
309}
310
311impl From<ApplicationValueSpecification> for ValueSpecification {
312    fn from(value_spec: ApplicationValueSpecification) -> Self {
313        ValueSpecification::Application(value_spec)
314    }
315}
316
317//#########################################################
318
319/// Default init pattern, which is used when an optional `ApplicationRecordElement` in not available
320#[derive(Debug, Clone, PartialEq)]
321pub struct NotAvailableValueSpecification {
322    /// SHORT-LABEL: used to identify the default pattern in a human readable way. This is used when the default pattern is part of a record.
323    pub label: Option<String>,
324    /// initialization pattern for memory occupied by unavailable application record elements; available in `AUTOSAR_00049` and newer
325    pub default_pattern: Option<u64>, // presumably this could be u8 to initialize bytes in memory. But the spec only says it's a positive integer
326}
327
328impl NotAvailableValueSpecification {
329    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
330        let not_available_elem = parent.create_sub_element(ElementName::NotAvailableValueSpecification)?;
331        store_label(&not_available_elem, &self.label)?;
332        if let Some(pattern) = &self.default_pattern {
333            // try to create the pattern element; it is not available in older versions of AUTOSAR
334            if let Ok(pattern_elem) = not_available_elem.create_sub_element(ElementName::DefaultPattern) {
335                pattern_elem.set_character_data(pattern.to_string())?;
336            }
337        }
338        Ok(())
339    }
340
341    fn load(element: &Element) -> Option<Self> {
342        let label = load_label(element);
343        let default_pattern = element
344            .get_sub_element(ElementName::DefaultPattern)
345            .and_then(|dp_elem| dp_elem.character_data())
346            .and_then(|cdata| cdata.parse_integer());
347        Some(Self { label, default_pattern })
348    }
349}
350
351impl From<NotAvailableValueSpecification> for ValueSpecification {
352    fn from(value_spec: NotAvailableValueSpecification) -> Self {
353        ValueSpecification::NotAvailable(value_spec)
354    }
355}
356
357//#########################################################
358
359/// reference to a `DataPrototype`, to be used as a pointer in the software
360#[derive(Debug, Clone, PartialEq)]
361pub struct ReferenceValueSpecification {
362    /// SHORT-LABEL: used to identify the reference in a human readable way. This is used when the reference is part of a record.
363    pub label: Option<String>,
364    /// data prototype that will be referenced as a pointer in the software
365    pub reference_value: DataPrototype,
366}
367
368impl ReferenceValueSpecification {
369    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
370        let ref_value_elem = parent.create_sub_element(ElementName::ReferenceValueSpecification)?;
371        store_label(&ref_value_elem, &self.label)?;
372        ref_value_elem
373            .create_sub_element(ElementName::ReferenceValueRef)
374            .and_then(|rvr_elem| rvr_elem.set_reference_target(self.reference_value.element()))?;
375        Ok(())
376    }
377
378    fn load(element: &Element) -> Option<Self> {
379        let label = load_label(element);
380        let reference_value_elem = element
381            .get_sub_element(ElementName::ReferenceValueRef)?
382            .get_reference_target()
383            .ok()?;
384        let reference_value = DataPrototype::try_from(reference_value_elem).ok()?;
385
386        Some(Self { label, reference_value })
387    }
388}
389
390impl From<ReferenceValueSpecification> for ValueSpecification {
391    fn from(value_spec: ReferenceValueSpecification) -> Self {
392        ValueSpecification::Reference(value_spec)
393    }
394}
395
396//#########################################################
397
398/// A rule to generate application values for an array value specification
399#[derive(Debug, Clone, PartialEq)]
400pub struct ApplicationRuleBasedValueSpecification {
401    /// SHORT-LABEL: used to identify the application value in a human readable way. This is used when the application value is part of a record.
402    pub label: Option<String>,
403    /// category of the application value
404    pub category: ApplicationPrimitiveCategory,
405    /// rule-based axis values of a compound primitive data type. Required for categories `ResAxis`, Cure, Map, Cuboid, Cube4, Cube5
406    pub sw_axis_cont: Vec<RuleBasedAxisCont>,
407    /// rule-based values of a compound primitive data type
408    pub sw_value_cont: RuleBasedValueCont,
409}
410
411impl ApplicationRuleBasedValueSpecification {
412    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
413        let app_rule_elem = parent.create_sub_element(ElementName::ApplicationRuleBasedValueSpecification)?;
414        store_label(&app_rule_elem, &self.label)?;
415        let category_elem = app_rule_elem.create_sub_element(ElementName::Category)?;
416        category_elem.set_character_data(self.category.to_string())?;
417        let sw_axis_cont_elem = app_rule_elem.create_sub_element(ElementName::SwAxisConts)?;
418        for sw_axis in &self.sw_axis_cont {
419            sw_axis.store(&sw_axis_cont_elem)?;
420        }
421        self.sw_value_cont.store(&app_rule_elem)?;
422
423        Ok(())
424    }
425
426    fn load(element: &Element) -> Option<Self> {
427        let label = load_label(element);
428
429        let category_string = element
430            .get_sub_element(ElementName::Category)?
431            .character_data()?
432            .string_value()?;
433        let category = ApplicationPrimitiveCategory::from_str(&category_string).ok()?;
434
435        let sw_axis_cont_elem = element.get_sub_element(ElementName::SwAxisConts)?;
436        let sw_axis_cont = sw_axis_cont_elem
437            .sub_elements()
438            .filter_map(|elem| RuleBasedAxisCont::load(&elem))
439            .collect::<Vec<_>>();
440
441        let sw_value_cont_elem = element.get_sub_element(ElementName::SwValueCont)?;
442        let sw_value_cont = RuleBasedValueCont::load(&sw_value_cont_elem)?;
443
444        Some(Self {
445            label,
446            category,
447            sw_axis_cont,
448            sw_value_cont,
449        })
450    }
451}
452
453impl From<ApplicationRuleBasedValueSpecification> for ValueSpecification {
454    fn from(value_spec: ApplicationRuleBasedValueSpecification) -> Self {
455        ValueSpecification::ApplicationRuleBased(value_spec)
456    }
457}
458
459//#########################################################
460
461/// A rule to generate composite values for an array value specification
462#[derive(Debug, Clone, PartialEq)]
463pub struct CompositeRuleBasedValueSpecification {
464    /// SHORT-LABEL: used to identify the composite value in a human readable way. This is used when the composite value is part of a record.
465    pub label: Option<String>,
466    /// collection of specified compound values. The last value is used by the filling rule to fill the array
467    pub argument: Vec<CompositeValueSpecification>,
468    /// collection of specified primitive values. The last value is used by the filling rule to fill the array
469    pub compound_primitive_argument: Vec<CompositeRuleBasedValueArgument>,
470    /// maximum size of the array to fill. It is used if the filling rule is set to `FILL_UNTIL_MAX_SIZE`
471    pub max_size_to_fill: Option<u64>,
472    /// rule to fill the array
473    pub rule: RuleBasedFillUntil,
474}
475
476impl CompositeRuleBasedValueSpecification {
477    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
478        let comp_rule_elem = parent.create_sub_element(ElementName::CompositeRuleBasedValueSpecification)?;
479        store_label(&comp_rule_elem, &self.label)?;
480        let arguments_elem = comp_rule_elem.create_sub_element(ElementName::Arguments)?;
481        for arg in &self.argument {
482            arg.store(&arguments_elem)?;
483        }
484        let compound_primitive_arguments_elem =
485            comp_rule_elem.create_sub_element(ElementName::CompoundPrimitiveArguments)?;
486        for arg in &self.compound_primitive_argument {
487            arg.store(&compound_primitive_arguments_elem)?;
488        }
489        if let Some(max_size) = self.max_size_to_fill {
490            let max_size_elem = comp_rule_elem.create_sub_element(ElementName::MaxSizeToFill)?;
491            max_size_elem.set_character_data(max_size.to_string())?;
492        }
493        let rule_elem = comp_rule_elem.create_sub_element(ElementName::Rule)?;
494        rule_elem.set_character_data(self.rule.to_string())?;
495
496        Ok(())
497    }
498
499    fn load(element: &Element) -> Option<Self> {
500        let label = load_label(element);
501        let arguments_elem = element.get_sub_element(ElementName::Arguments)?;
502        let argument = arguments_elem
503            .sub_elements()
504            .filter_map(|elem| CompositeValueSpecification::load(&elem))
505            .collect::<Vec<_>>();
506        let compound_primitive_arguments_elem = element.get_sub_element(ElementName::CompoundPrimitiveArguments)?;
507        let compound_primitive_argument = compound_primitive_arguments_elem
508            .sub_elements()
509            .filter_map(|elem| CompositeRuleBasedValueArgument::load(&elem))
510            .collect::<Vec<_>>();
511        let max_size_to_fill = element
512            .get_sub_element(ElementName::MaxSizeToFill)
513            .and_then(|ms_elem| ms_elem.character_data())
514            .and_then(|cdata| cdata.parse_integer());
515        let rule_string = element
516            .get_sub_element(ElementName::Rule)?
517            .character_data()?
518            .string_value()?;
519        let rule = RuleBasedFillUntil::from_str(&rule_string).ok()?;
520
521        Some(Self {
522            label,
523            argument,
524            compound_primitive_argument,
525            max_size_to_fill,
526            rule,
527        })
528    }
529}
530
531impl From<CompositeRuleBasedValueSpecification> for ValueSpecification {
532    fn from(value_spec: CompositeRuleBasedValueSpecification) -> Self {
533        ValueSpecification::CompositeRuleBased(value_spec)
534    }
535}
536
537//#########################################################
538
539/// A rule to generate numerical values for an array value specification
540#[derive(Debug, Clone, PartialEq)]
541pub struct NumericalRuleBasedValueSpecification {
542    /// SHORT-LABEL: used to identify the numerical value in a human readable way. This is used when the numerical value is part of a record.
543    pub label: Option<String>,
544    /// rule-based values for the array
545    pub rule_based_values: RuleBasedValueSpecification,
546}
547
548impl NumericalRuleBasedValueSpecification {
549    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
550        let num_rule_elem = parent.create_sub_element(ElementName::NumericalRuleBasedValueSpecification)?;
551        store_label(&num_rule_elem, &self.label)?;
552        self.rule_based_values.store(&num_rule_elem)?;
553
554        Ok(())
555    }
556
557    fn load(element: &Element) -> Option<Self> {
558        let label = load_label(element);
559        let rule_based_values_elem = element.get_sub_element(ElementName::RuleBasedValues)?;
560        let rule_based_values = RuleBasedValueSpecification::load(&rule_based_values_elem)?;
561
562        Some(Self {
563            label,
564            rule_based_values,
565        })
566    }
567}
568
569impl From<NumericalRuleBasedValueSpecification> for ValueSpecification {
570    fn from(value_spec: NumericalRuleBasedValueSpecification) -> Self {
571        ValueSpecification::NumericalRuleBased(value_spec)
572    }
573}
574
575//#########################################################
576
577#[derive(Debug, Clone, PartialEq)]
578/// Specification of a value. It is used for constants, signal init values and port init values.
579pub enum ValueSpecification {
580    /// array of values
581    Array(ArrayValueSpecification),
582    /// record of values. The values may be named using short-labels, but these are not mandatory.
583    Record(RecordValueSpecification),
584    /// textual value
585    Text(TextValueSpecification),
586    /// numerical value
587    Numerical(NumericalValueSpecification),
588    /// reference to a `ConstantValue`
589    ConstantReference(ConstantReference),
590    /// Application value
591    Application(ApplicationValueSpecification),
592    /// Default init pattern, which is used when an optional `ApplicationRecordElement` in not available
593    NotAvailable(NotAvailableValueSpecification),
594    /// reference to a `DataPrototype`, to be used as a pointer in the software
595    Reference(ReferenceValueSpecification),
596    /// A rule to generate application values for an array value specification
597    ApplicationRuleBased(ApplicationRuleBasedValueSpecification),
598    /// A rule to generate composite values for an array value specification
599    CompositeRuleBased(CompositeRuleBasedValueSpecification),
600    /// A rule to generate numerical values for an array value specification
601    NumericalRuleBased(NumericalRuleBasedValueSpecification),
602}
603
604impl ValueSpecification {
605    pub(crate) fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
606        match self {
607            Self::Array(array_spec) => array_spec.store(parent),
608            Self::Record(record_spec) => record_spec.store(parent),
609            Self::Text(text_spec) => text_spec.store(parent),
610            Self::Numerical(num_spec) => num_spec.store(parent),
611            Self::ConstantReference(constant_ref) => constant_ref.store(parent),
612            Self::Application(app_spec) => app_spec.store(parent),
613            Self::NotAvailable(not_available_spec) => not_available_spec.store(parent),
614            Self::Reference(ref_value_spec) => ref_value_spec.store(parent),
615            Self::ApplicationRuleBased(app_rule_spec) => app_rule_spec.store(parent),
616            Self::CompositeRuleBased(comp_rule_spec) => comp_rule_spec.store(parent),
617            Self::NumericalRuleBased(num_rule_spec) => num_rule_spec.store(parent),
618        }
619    }
620
621    pub(crate) fn load(elem: &Element) -> Option<ValueSpecification> {
622        match elem.element_name() {
623            ElementName::ArrayValueSpecification => ArrayValueSpecification::load(elem).map(Self::Array),
624            ElementName::RecordValueSpecification => RecordValueSpecification::load(elem).map(Self::Record),
625            ElementName::TextValueSpecification => TextValueSpecification::load(elem).map(Self::Text),
626            ElementName::NumericalValueSpecification => NumericalValueSpecification::load(elem).map(Self::Numerical),
627            ElementName::ConstantReference => ConstantReference::load(elem).map(Self::ConstantReference),
628            ElementName::ApplicationValueSpecification => {
629                ApplicationValueSpecification::load(elem).map(Self::Application)
630            }
631            ElementName::NotAvailableValueSpecification => {
632                NotAvailableValueSpecification::load(elem).map(Self::NotAvailable)
633            }
634            ElementName::ReferenceValueSpecification => ReferenceValueSpecification::load(elem).map(Self::Reference),
635            ElementName::ApplicationRuleBasedValueSpecification => {
636                ApplicationRuleBasedValueSpecification::load(elem).map(Self::ApplicationRuleBased)
637            }
638            ElementName::CompositeRuleBasedValueSpecification => {
639                CompositeRuleBasedValueSpecification::load(elem).map(Self::CompositeRuleBased)
640            }
641            ElementName::NumericalRuleBasedValueSpecification => {
642                NumericalRuleBasedValueSpecification::load(elem).map(Self::NumericalRuleBased)
643            }
644            _ => None,
645        }
646    }
647}
648
649fn store_label(parent: &Element, label: &Option<String>) -> Result<(), AutosarAbstractionError> {
650    if let Some(label) = label {
651        let label_elem = parent.create_sub_element(ElementName::ShortLabel)?;
652        label_elem.set_character_data(label.clone())?;
653    }
654    Ok(())
655}
656
657fn load_label(element: &Element) -> Option<String> {
658    let label_elem = element.get_sub_element(ElementName::ShortLabel)?;
659    label_elem.character_data()?.string_value()
660}
661
662//#########################################################
663
664/// standard fill rules for rule based value specifications
665#[derive(Debug, Clone, Copy, PartialEq, Eq)]
666pub enum RuleBasedFillUntil {
667    /// `FILL_UNTIL_END`: fills the value of the last RuleBasedValueSpecification.arguments
668    /// until the last element of the array has been filled
669    End,
670    /// `FILL_UNTIL_MAX_SIZE`: fills the value of the last RuleBasedValueSpecification.arguments
671    /// until maxSizeToFill elements of the array have been filled
672    MaxSize,
673}
674
675impl FromStr for RuleBasedFillUntil {
676    type Err = AutosarAbstractionError;
677
678    fn from_str(value: &str) -> Result<Self, Self::Err> {
679        match value {
680            "FILL_UNTIL_END" => Ok(RuleBasedFillUntil::End),
681            "FILL_UNTIL_MAX_SIZE" => Ok(RuleBasedFillUntil::MaxSize),
682            _ => Err(AutosarAbstractionError::ValueConversionError {
683                value: value.to_string(),
684                dest: "RuleBasedFillUntil".to_string(),
685            }),
686        }
687    }
688}
689
690impl std::fmt::Display for RuleBasedFillUntil {
691    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
692        match self {
693            RuleBasedFillUntil::End => f.write_str("FILL_UNTIL_END"),
694            RuleBasedFillUntil::MaxSize => f.write_str("FILL_UNTIL_MAX_SIZE"),
695        }
696    }
697}
698
699//#########################################################
700
701/// specification of the axis values of a compound primitive data type (curve, map)
702#[derive(Debug, Clone, PartialEq)]
703pub struct SwAxisCont {
704    /// category of the axis; one of `STD_AXIS`, `COM_AXIS`, `COM_AXIS`, `RES_AXIS`
705    pub category: SwAxisContCategory,
706    /// dimensions of the axis, used if the category is `RES_AXIS`, otherwise it should be empty
707    pub sw_array_size: Vec<u64>,
708    /// index of the axis. Here 1 is the x axis, 2 is the y axis, ...
709    pub sw_axis_index: u64,
710    /// axis values in the physical domain
711    pub sw_values_phys: Vec<SwValue>,
712    /// pyhsical unit of the axis values
713    pub unit: Option<Unit>,
714    /// display name of the unit
715    pub unit_display_name: Option<String>,
716}
717
718impl SwAxisCont {
719    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
720        let sw_axis_cont_elem = parent.create_sub_element(ElementName::SwAxisCont)?;
721        let category_elem = sw_axis_cont_elem.create_sub_element(ElementName::Category)?;
722        category_elem.set_character_data::<EnumItem>(self.category.into())?;
723        let sw_array_size_elem = sw_axis_cont_elem.create_sub_element(ElementName::SwArraysize)?;
724        for size in &self.sw_array_size {
725            let size_elem = sw_array_size_elem.create_sub_element(ElementName::Vf)?;
726            size_elem.set_character_data(*size)?;
727        }
728        let sw_axis_index_elem = sw_axis_cont_elem.create_sub_element(ElementName::SwAxisIndex)?;
729        sw_axis_index_elem.set_character_data(self.sw_axis_index.to_string())?;
730        let sw_values_phys_elem = sw_axis_cont_elem.create_sub_element(ElementName::SwValuesPhys)?;
731        for value in &self.sw_values_phys {
732            value.store(&sw_values_phys_elem)?;
733        }
734
735        if let Some(unit) = &self.unit {
736            sw_axis_cont_elem
737                .create_sub_element(ElementName::UnitRef)
738                .and_then(|unit_elem| unit_elem.set_reference_target(unit.element()))?;
739        }
740        if let Some(unit_display_name) = &self.unit_display_name {
741            // try to create the UnitDisplayName element; it is not available in older versions of AUTOSAR, so errors are ignored
742            let _ = sw_axis_cont_elem
743                .create_sub_element(ElementName::UnitDisplayName)
744                .and_then(|udn_elem| udn_elem.set_character_data(unit_display_name.clone()));
745        }
746
747        Ok(())
748    }
749
750    fn load(element: &Element) -> Option<Self> {
751        let category_elem = element.get_sub_element(ElementName::Category)?;
752        let category = SwAxisContCategory::try_from(category_elem.character_data()?.enum_value()?).ok()?;
753        let sw_array_size_elem = element.get_sub_element(ElementName::SwArraysize)?;
754        // The SW-ARRAY-SIZE element can contain either one V or many VF elements
755        // The iterator doesn't care, and parse_integer works regardless
756        let sw_array_size = sw_array_size_elem
757            .sub_elements()
758            .filter_map(|elem| elem.character_data()?.parse_integer())
759            .collect::<Vec<_>>();
760
761        let sw_axis_index_elem = element.get_sub_element(ElementName::SwAxisIndex)?;
762        let sw_axis_index = sw_axis_index_elem.character_data()?.parse_integer()?;
763
764        let sw_values_phys_elem = element.get_sub_element(ElementName::SwValuesPhys)?;
765        let sw_values_phys = sw_values_phys_elem
766            .sub_elements()
767            .filter_map(|elem| SwValue::load(&elem))
768            .collect::<Vec<_>>();
769
770        let unit = element
771            .get_sub_element(ElementName::UnitRef)
772            .and_then(|unit_elem| unit_elem.get_reference_target().ok())
773            .and_then(|unit_elem| Unit::try_from(unit_elem).ok());
774        let unit_display_name = element
775            .get_sub_element(ElementName::UnitDisplayName)
776            .and_then(|udn_elem| udn_elem.character_data())
777            .and_then(|cdata| cdata.string_value());
778
779        Some(Self {
780            category,
781            sw_array_size,
782            sw_axis_index,
783            sw_values_phys,
784            unit,
785            unit_display_name,
786        })
787    }
788}
789
790//#########################################################
791
792/// enumeration of the axis categories.
793/// This is a restricted version of the `CalprmAxisCategoryEnum`: `FixAxis` is not permitted in `SwAxisCont`
794#[derive(Debug, Clone, Copy, PartialEq, Eq)]
795pub enum SwAxisContCategory {
796    /// standard axis
797    StdAxis,
798    /// commmon axis
799    ComAxis,
800    /// rescale axis
801    ResAxis,
802}
803
804impl TryFrom<EnumItem> for SwAxisContCategory {
805    type Error = AutosarAbstractionError;
806
807    fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
808        match value {
809            EnumItem::StdAxis => Ok(SwAxisContCategory::StdAxis), // old form: STD-AXIS
810            EnumItem::Stdaxis => Ok(SwAxisContCategory::StdAxis), // new form: STD_AXIS
811            EnumItem::ComAxis => Ok(SwAxisContCategory::ComAxis), // old form: COM-AXIS
812            EnumItem::Comaxis => Ok(SwAxisContCategory::ComAxis), // new form: COM_AXIS
813            EnumItem::ResAxis => Ok(SwAxisContCategory::ResAxis), // old form: RES-AXIS
814            EnumItem::Resaxis => Ok(SwAxisContCategory::ResAxis), // new form: RES_AXIS
815            _ => Err(AutosarAbstractionError::ValueConversionError {
816                value: value.to_string(),
817                dest: "SwAxisContCategory".to_string(),
818            }),
819        }
820    }
821}
822
823impl From<SwAxisContCategory> for EnumItem {
824    fn from(value: SwAxisContCategory) -> Self {
825        match value {
826            SwAxisContCategory::StdAxis => EnumItem::Stdaxis,
827            SwAxisContCategory::ComAxis => EnumItem::Comaxis,
828            SwAxisContCategory::ResAxis => EnumItem::Resaxis,
829        }
830    }
831}
832
833//#########################################################
834
835/// specification of the values of a compound primitive data type (curve, map)
836#[derive(Debug, Clone, PartialEq)]
837pub struct SwValueCont {
838    /// dimensions of the array
839    pub sw_array_size: Vec<u64>,
840    /// values in the physical domain
841    pub sw_values_phys: Vec<SwValue>,
842}
843
844impl SwValueCont {
845    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
846        let sw_array_size_elem = parent.create_sub_element(ElementName::SwArraysize)?;
847        for size in &self.sw_array_size {
848            let size_elem = sw_array_size_elem.create_sub_element(ElementName::Vf)?;
849            size_elem.set_character_data(*size)?;
850        }
851
852        let sw_values_phys_elem = parent.create_sub_element(ElementName::SwValuesPhys)?;
853        for value in &self.sw_values_phys {
854            value.store(&sw_values_phys_elem)?;
855        }
856        Ok(())
857    }
858
859    fn load(element: &Element) -> Option<Self> {
860        let sw_array_size_elem = element.get_sub_element(ElementName::SwArraysize)?;
861        let sw_array_size = sw_array_size_elem
862            .sub_elements()
863            .filter_map(|elem| elem.character_data()?.parse_integer())
864            .collect::<Vec<_>>();
865
866        let sw_values_phys_elem = element.get_sub_element(ElementName::SwValuesPhys)?;
867        let sw_values_phys = sw_values_phys_elem
868            .sub_elements()
869            .filter_map(|elem| SwValue::load(&elem))
870            .collect::<Vec<_>>();
871
872        Some(Self {
873            sw_array_size,
874            sw_values_phys,
875        })
876    }
877}
878
879//#########################################################
880
881/// a single value of a compound primitive data type (curve, map)
882#[derive(Debug, Clone, PartialEq)]
883pub enum SwValue {
884    /// numerical value
885    V(f64),
886    /// numerical value
887    Vf(f64),
888    /// value group
889    Vg {
890        /// label of the value group
891        label: Option<String>,
892        /// content of the value group
893        vg_content: Vec<SwValue>,
894    },
895    /// textual value
896    Vt(String),
897    /// Vtf element with numerical value
898    VtfNumber(f64),
899    /// Vtf element with textual value
900    VtfText(String),
901}
902
903impl SwValue {
904    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
905        match self {
906            SwValue::V(value) => {
907                let value_elem = parent.create_sub_element(ElementName::V)?;
908                value_elem.set_character_data(value.to_string())?;
909            }
910            SwValue::Vf(value) => {
911                let value_elem = parent.create_sub_element(ElementName::Vf)?;
912                value_elem.set_character_data(value.to_string())?;
913            }
914            SwValue::Vg { label, vg_content } => {
915                let value_group_elem = parent.create_sub_element(ElementName::Vg)?;
916                if let Some(label) = label {
917                    let label_elem = value_group_elem
918                        .create_sub_element(ElementName::Label)?
919                        .create_sub_element(ElementName::L4)?;
920                    label_elem.set_character_data(label.clone())?;
921                }
922                for value in vg_content {
923                    value.store(&value_group_elem)?;
924                }
925            }
926            SwValue::Vt(value) => {
927                let value_elem = parent.create_sub_element(ElementName::Vt)?;
928                value_elem.set_character_data(value.clone())?;
929            }
930            SwValue::VtfNumber(value) => {
931                let value_elem = parent
932                    .create_sub_element(ElementName::Vtf)?
933                    .create_sub_element(ElementName::Vf)?;
934                value_elem.set_character_data(*value)?;
935            }
936            SwValue::VtfText(value) => {
937                let value_elem = parent
938                    .create_sub_element(ElementName::Vtf)?
939                    .create_sub_element(ElementName::Vt)?;
940                value_elem.set_character_data(value.clone())?;
941            }
942        }
943        Ok(())
944    }
945
946    fn load(element: &Element) -> Option<Self> {
947        let value = match element.element_name() {
948            ElementName::V => {
949                let value = element.character_data()?.parse_float()?;
950                SwValue::V(value)
951            }
952            ElementName::Vf => {
953                let value = element.character_data()?.parse_float()?;
954                SwValue::Vf(value)
955            }
956            ElementName::Vg => {
957                let label = element
958                    .get_sub_element(ElementName::Label)
959                    .and_then(|label_elem| label_elem.get_sub_element(ElementName::L4))
960                    .and_then(|sl_elem| sl_elem.character_data())
961                    .and_then(|cdata| cdata.string_value());
962                let vg_content = element
963                    .sub_elements()
964                    .filter_map(|elem| SwValue::load(&elem))
965                    .collect::<Vec<_>>();
966                SwValue::Vg { label, vg_content }
967            }
968            ElementName::Vt => {
969                let value = element.character_data()?.string_value()?;
970                SwValue::Vt(value)
971            }
972            ElementName::Vtf => {
973                // The VTF element can contain either a Vf or a Vt element
974                if let Some(vf) = element.get_sub_element(ElementName::Vf) {
975                    SwValue::VtfNumber(vf.character_data()?.parse_float()?)
976                } else if let Some(vt) = element.get_sub_element(ElementName::Vt) {
977                    SwValue::VtfText(vt.character_data()?.string_value()?)
978                } else {
979                    return None;
980                }
981            }
982            _ => return None,
983        };
984        Some(value)
985    }
986}
987
988//#########################################################
989
990/// specification of the axis values of a compound primitive data type (curve, map) in a rule-based definition
991#[derive(Debug, Clone, PartialEq)]
992pub struct RuleBasedAxisCont {
993    /// category of the axis; one of `STD_AXIS`, `COM_AXIS`, `COM_AXIS`, `RES_AXIS`
994    pub category: SwAxisContCategory,
995    /// dimensions of the axis, used if the category is `RES_AXIS`, otherwise it should be empty
996    pub sw_array_size: Vec<u64>,
997    /// index of the axis. Here 1 is the x axis, 2 is the y axis, ...
998    pub sw_axis_index: u64,
999    /// axis values in the physical domain
1000    pub rule_based_values: RuleBasedValueSpecification,
1001    /// pyhsical unit of the axis values
1002    pub unit: Option<Unit>,
1003}
1004
1005impl RuleBasedAxisCont {
1006    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
1007        let axis_cont_elem = parent.create_sub_element(ElementName::RuleBasedAxisCont)?;
1008        let category_elem = axis_cont_elem.create_sub_element(ElementName::Category)?;
1009        category_elem.set_character_data::<EnumItem>(self.category.into())?;
1010        let sw_array_size_elem = axis_cont_elem.create_sub_element(ElementName::SwArraysize)?;
1011        for size in &self.sw_array_size {
1012            let size_elem = sw_array_size_elem.create_sub_element(ElementName::Vf)?;
1013            size_elem.set_character_data(*size)?;
1014        }
1015        let sw_axis_index_elem = axis_cont_elem.create_sub_element(ElementName::SwAxisIndex)?;
1016        sw_axis_index_elem.set_character_data(self.sw_axis_index.to_string())?;
1017        self.rule_based_values.store(&axis_cont_elem)?;
1018
1019        if let Some(unit) = &self.unit {
1020            axis_cont_elem
1021                .create_sub_element(ElementName::UnitRef)
1022                .and_then(|unit_elem| unit_elem.set_reference_target(unit.element()))?;
1023        }
1024
1025        Ok(())
1026    }
1027
1028    fn load(element: &Element) -> Option<Self> {
1029        let category_elem = element.get_sub_element(ElementName::Category)?;
1030        let category = SwAxisContCategory::try_from(category_elem.character_data()?.enum_value()?).ok()?;
1031        let sw_array_size_elem = element.get_sub_element(ElementName::SwArraysize)?;
1032        // The SW-ARRAY-SIZE element can contain either one V or many VF elements
1033        // The iterator doesn't care, and parse_integer works regardless
1034        let sw_array_size = sw_array_size_elem
1035            .sub_elements()
1036            .filter_map(|elem| elem.character_data()?.parse_integer())
1037            .collect::<Vec<_>>();
1038
1039        let sw_axis_index_elem = element.get_sub_element(ElementName::SwAxisIndex)?;
1040        let sw_axis_index = sw_axis_index_elem.character_data()?.parse_integer()?;
1041
1042        let rule_based_values_elem = element.get_sub_element(ElementName::RuleBasedValues)?;
1043        let rule_based_values = RuleBasedValueSpecification::load(&rule_based_values_elem)?;
1044
1045        let unit = element
1046            .get_sub_element(ElementName::UnitRef)
1047            .and_then(|unit_elem| unit_elem.get_reference_target().ok())
1048            .and_then(|unit_elem| Unit::try_from(unit_elem).ok());
1049
1050        Some(Self {
1051            category,
1052            sw_array_size,
1053            sw_axis_index,
1054            rule_based_values,
1055            unit,
1056        })
1057    }
1058}
1059
1060//#########################################################
1061
1062/// specification of the values of a compound primitive data type (curve, map) in a rule-based definition
1063#[derive(Debug, Clone, PartialEq)]
1064pub struct RuleBasedValueCont {
1065    /// values
1066    pub rule_based_values: RuleBasedValueSpecification,
1067    /// dimensions of the array
1068    pub sw_array_size: Vec<u64>,
1069    /// physical unit of the values
1070    pub unit: Option<Unit>,
1071}
1072
1073impl RuleBasedValueCont {
1074    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
1075        let sw_value_cont_elem = parent.create_sub_element(ElementName::SwValueCont)?;
1076        self.rule_based_values.store(&sw_value_cont_elem)?;
1077        let sw_array_size_elem = sw_value_cont_elem.create_sub_element(ElementName::SwArraysize)?;
1078        for size in &self.sw_array_size {
1079            let size_elem = sw_array_size_elem.create_sub_element(ElementName::Vf)?;
1080            size_elem.set_character_data(*size)?;
1081        }
1082        if let Some(unit) = &self.unit {
1083            sw_value_cont_elem
1084                .create_sub_element(ElementName::UnitRef)
1085                .and_then(|unit_elem| unit_elem.set_reference_target(unit.element()))?;
1086        }
1087        Ok(())
1088    }
1089
1090    fn load(element: &Element) -> Option<Self> {
1091        let rule_based_values_elem = element.get_sub_element(ElementName::RuleBasedValues)?;
1092        let rule_based_values = RuleBasedValueSpecification::load(&rule_based_values_elem)?;
1093        let sw_array_size_elem = element.get_sub_element(ElementName::SwArraysize)?;
1094        let sw_array_size = sw_array_size_elem
1095            .sub_elements()
1096            .filter_map(|elem| elem.character_data()?.parse_integer())
1097            .collect::<Vec<_>>();
1098        let unit = element
1099            .get_sub_element(ElementName::UnitRef)
1100            .and_then(|unit_elem| unit_elem.get_reference_target().ok())
1101            .and_then(|unit_elem| Unit::try_from(unit_elem).ok());
1102
1103        Some(Self {
1104            rule_based_values,
1105            sw_array_size,
1106            unit,
1107        })
1108    }
1109}
1110
1111//#########################################################
1112
1113/// rule based value specification
1114#[derive(Debug, Clone, PartialEq)]
1115pub struct RuleBasedValueSpecification {
1116    /// arguments of the rule-based value specification; they are filled in-order, andf the last one is repeated as required
1117    pub arguments: Vec<RuleArgument>,
1118    /// maximum size of the array to fill. It is used if the filling rule is set to `FILL_UNTIL_MAX_SIZE`
1119    pub max_size_to_fill: Option<u64>,
1120    /// rule to fill the array
1121    pub rule: RuleBasedFillUntil,
1122}
1123
1124impl RuleBasedValueSpecification {
1125    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
1126        let rule_based_value_elem = parent.create_sub_element(ElementName::RuleBasedValues)?;
1127        // store the arguments
1128        let arguments_elem = rule_based_value_elem
1129            .create_sub_element(ElementName::Argumentss)?
1130            .create_sub_element(ElementName::RuleArguments)?;
1131        for argument in &self.arguments {
1132            argument.store(&arguments_elem)?;
1133        }
1134        if let Some(max_size) = self.max_size_to_fill {
1135            let max_size_elem = rule_based_value_elem.create_sub_element(ElementName::MaxSizeToFill)?;
1136            max_size_elem.set_character_data(max_size.to_string())?;
1137        }
1138        let rule_elem = rule_based_value_elem.create_sub_element(ElementName::Rule)?;
1139        rule_elem.set_character_data(self.rule.to_string())?;
1140        Ok(())
1141    }
1142
1143    fn load(element: &Element) -> Option<Self> {
1144        let arguments = element
1145            .get_sub_element(ElementName::Argumentss)?
1146            .get_sub_element(ElementName::RuleArguments)?
1147            .sub_elements()
1148            .filter_map(|elem| RuleArgument::load(&elem))
1149            .collect::<Vec<_>>();
1150
1151        let max_size_to_fill = element
1152            .get_sub_element(ElementName::MaxSizeToFill)
1153            .and_then(|elem| elem.character_data())
1154            .and_then(|cdata| cdata.parse_integer());
1155
1156        let rule_text = element
1157            .get_sub_element(ElementName::Rule)?
1158            .character_data()?
1159            .string_value()?;
1160        let rule = RuleBasedFillUntil::from_str(&rule_text).ok()?;
1161
1162        Some(Self {
1163            arguments,
1164            max_size_to_fill,
1165            rule,
1166        })
1167    }
1168}
1169
1170//#########################################################
1171
1172/// specification of a composite value
1173#[derive(Debug, Clone, PartialEq)]
1174pub enum CompositeValueSpecification {
1175    /// array of values
1176    Array(ArrayValueSpecification),
1177    /// record of values
1178    Record(RecordValueSpecification),
1179}
1180
1181impl CompositeValueSpecification {
1182    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
1183        match self {
1184            Self::Array(array) => array.store(parent),
1185            Self::Record(record) => record.store(parent),
1186        }
1187    }
1188
1189    fn load(element: &Element) -> Option<Self> {
1190        match element.element_name() {
1191            ElementName::ArrayValueSpecification => ArrayValueSpecification::load(element).map(Self::Array),
1192            ElementName::RecordValueSpecification => RecordValueSpecification::load(element).map(Self::Record),
1193            _ => None,
1194        }
1195    }
1196}
1197
1198//#########################################################
1199
1200/// specification of a composite value argument
1201#[derive(Debug, Clone, PartialEq)]
1202pub enum CompositeRuleBasedValueArgument {
1203    /// argument is an application value
1204    Application(ApplicationValueSpecification),
1205    /// argument is a rule-based application value
1206    ApplicationRuleBased(ApplicationRuleBasedValueSpecification),
1207}
1208
1209impl CompositeRuleBasedValueArgument {
1210    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
1211        match self {
1212            Self::Application(app) => app.store(parent),
1213            Self::ApplicationRuleBased(app_rule) => app_rule.store(parent),
1214        }
1215    }
1216
1217    fn load(element: &Element) -> Option<Self> {
1218        match element.element_name() {
1219            ElementName::ApplicationValueSpecification => {
1220                ApplicationValueSpecification::load(element).map(Self::Application)
1221            }
1222            ElementName::ApplicationRuleBasedValueSpecification => {
1223                ApplicationRuleBasedValueSpecification::load(element).map(Self::ApplicationRuleBased)
1224            }
1225            _ => None,
1226        }
1227    }
1228}
1229
1230//#########################################################
1231
1232#[derive(Debug, Clone, PartialEq)]
1233/// argument of a rule-based value specification
1234pub enum RuleArgument {
1235    /// V: argument is a numerical value
1236    V(f64),
1237    /// VF: argument is a numerical value
1238    Vf(f64),
1239    /// VT: argument is a text value
1240    Vt(String),
1241    /// VTF: argument is a numerical value
1242    VtfNumber(f64),
1243    /// VTF: argument is a text value
1244    VtfText(String),
1245}
1246
1247impl RuleArgument {
1248    fn store(&self, parent: &Element) -> Result<(), AutosarAbstractionError> {
1249        match self {
1250            RuleArgument::V(value) => {
1251                let value_elem = parent.create_sub_element(ElementName::V)?;
1252                value_elem.set_character_data(value.to_string())?;
1253            }
1254            RuleArgument::Vf(value) => {
1255                let value_elem = parent.create_sub_element(ElementName::Vf)?;
1256                value_elem.set_character_data(value.to_string())?;
1257            }
1258            RuleArgument::Vt(value) => {
1259                let value_elem = parent.create_sub_element(ElementName::Vt)?;
1260                value_elem.set_character_data(value.clone())?;
1261            }
1262            RuleArgument::VtfNumber(value) => {
1263                let value_elem = parent
1264                    .create_sub_element(ElementName::Vtf)?
1265                    .create_sub_element(ElementName::Vf)?;
1266                value_elem.set_character_data(*value)?;
1267            }
1268            RuleArgument::VtfText(value) => {
1269                let value_elem = parent
1270                    .create_sub_element(ElementName::Vtf)?
1271                    .create_sub_element(ElementName::Vt)?;
1272                value_elem.set_character_data(value.clone())?;
1273            }
1274        }
1275        Ok(())
1276    }
1277
1278    fn load(element: &Element) -> Option<Self> {
1279        let value = match element.element_name() {
1280            ElementName::V => {
1281                let value = element.character_data()?.parse_float()?;
1282                RuleArgument::V(value)
1283            }
1284            ElementName::Vf => {
1285                let value = element.character_data()?.parse_float()?;
1286                RuleArgument::Vf(value)
1287            }
1288            ElementName::Vt => {
1289                let value = element.character_data()?.string_value()?;
1290                RuleArgument::Vt(value)
1291            }
1292            ElementName::Vtf => {
1293                // The VTF element can contain either a Vf or a Vt element
1294                if let Some(vf) = element.get_sub_element(ElementName::Vf) {
1295                    RuleArgument::VtfNumber(vf.character_data()?.parse_float()?)
1296                } else if let Some(vt) = element.get_sub_element(ElementName::Vt) {
1297                    RuleArgument::VtfText(vt.character_data()?.string_value()?)
1298                } else {
1299                    return None;
1300                }
1301            }
1302            _ => return None,
1303        };
1304        Some(value)
1305    }
1306}
1307
1308//#########################################################
1309
1310/// enum of all data prototypes
1311#[derive(Debug, Clone, PartialEq, Eq)]
1312pub enum DataPrototype {
1313    /// argument data prototype
1314    ArgumentDataPrototype(ArgumentDataPrototype),
1315    /// parameter data prototype
1316    ParameterDataPrototype(ParameterDataPrototype),
1317    /// variable data prototype
1318    VariableDataPrototype(VariableDataPrototype),
1319    /// application array element
1320    ApplicationArrayElement(ApplicationArrayElement),
1321    /// application record element
1322    ApplicationRecordElement(ApplicationRecordElement),
1323}
1324
1325impl TryFrom<Element> for DataPrototype {
1326    type Error = AutosarAbstractionError;
1327
1328    fn try_from(value: Element) -> Result<Self, Self::Error> {
1329        match value.element_name() {
1330            ElementName::ArgumentDataPrototype => {
1331                ArgumentDataPrototype::try_from(value).map(Self::ArgumentDataPrototype)
1332            }
1333            ElementName::ParameterDataPrototype => {
1334                ParameterDataPrototype::try_from(value).map(Self::ParameterDataPrototype)
1335            }
1336            ElementName::VariableDataPrototype => {
1337                VariableDataPrototype::try_from(value).map(Self::VariableDataPrototype)
1338            }
1339            ElementName::Element => ApplicationArrayElement::try_from(value).map(Self::ApplicationArrayElement),
1340            ElementName::ApplicationRecordElement => {
1341                ApplicationRecordElement::try_from(value).map(Self::ApplicationRecordElement)
1342            }
1343            _ => Err(AutosarAbstractionError::ConversionError {
1344                element: value,
1345                dest: "DataPrototype".to_string(),
1346            }),
1347        }
1348    }
1349}
1350
1351impl AbstractionElement for DataPrototype {
1352    fn element(&self) -> &Element {
1353        match self {
1354            DataPrototype::ArgumentDataPrototype(arg) => arg.element(),
1355            DataPrototype::ParameterDataPrototype(param) => param.element(),
1356            DataPrototype::VariableDataPrototype(var) => var.element(),
1357            DataPrototype::ApplicationArrayElement(arr) => arr.element(),
1358            DataPrototype::ApplicationRecordElement(rec) => rec.element(),
1359        }
1360    }
1361}
1362
1363//#########################################################
1364
1365#[cfg(test)]
1366mod test {
1367    use std::vec;
1368
1369    use super::*;
1370    use crate::{
1371        AutosarModelAbstraction,
1372        datatype::{BaseTypeEncoding, ImplementationDataTypeSettings},
1373        software_component::{ArgumentDirection, ClientServerInterface},
1374    };
1375    use autosar_data::AutosarVersion;
1376
1377    #[test]
1378    fn constant_specification() {
1379        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1380        let package = model.get_or_create_package("/Pkg").unwrap();
1381
1382        let constant = package
1383            .create_constant_specification(
1384                "ConstantSpec",
1385                NumericalValueSpecification {
1386                    label: None,
1387                    value: 12.0,
1388                },
1389            )
1390            .unwrap();
1391        assert_eq!(constant.name().unwrap(), "ConstantSpec");
1392
1393        let spec = ArrayValueSpecification {
1394            label: Some("ArrayValue".to_string()),
1395            values: vec![
1396                NumericalValueSpecification {
1397                    label: None,
1398                    value: 11.0,
1399                }
1400                .into(),
1401                NumericalValueSpecification {
1402                    label: None,
1403                    value: 12.3,
1404                }
1405                .into(),
1406            ],
1407        };
1408        constant.set_value_specification(spec.clone()).unwrap();
1409        assert_eq!(constant.value_specification().unwrap(), spec.into());
1410    }
1411
1412    #[test]
1413    fn numerical_value_specification() {
1414        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1415        let package = model.get_or_create_package("/Pkg").unwrap();
1416
1417        let spec = NumericalValueSpecification {
1418            label: Some("NumericalValue".to_string()),
1419            value: 33.3,
1420        };
1421        let constant = package
1422            .create_constant_specification("ConstantSpec", spec.clone())
1423            .unwrap();
1424        let spec_read = constant.value_specification().unwrap();
1425        assert_eq!(spec_read, spec.into());
1426    }
1427
1428    #[test]
1429    fn array_value_specification() {
1430        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1431        let package = model.get_or_create_package("/Pkg").unwrap();
1432
1433        let spec = ArrayValueSpecification {
1434            label: Some("ArrayValue".to_string()),
1435            values: vec![
1436                NumericalValueSpecification {
1437                    label: None,
1438                    value: 11.0,
1439                }
1440                .into(),
1441                NumericalValueSpecification {
1442                    label: None,
1443                    value: 12.3,
1444                }
1445                .into(),
1446            ],
1447        };
1448        let constant = package
1449            .create_constant_specification("ConstantSpec", spec.clone())
1450            .unwrap();
1451        let spec_read = constant.value_specification().unwrap();
1452        assert_eq!(spec_read, spec.into());
1453    }
1454
1455    #[test]
1456    fn record_value_specification() {
1457        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1458        let package = model.get_or_create_package("/Pkg").unwrap();
1459
1460        let spec = RecordValueSpecification {
1461            label: Some("RecordValue".to_string()),
1462            values: vec![
1463                NumericalValueSpecification {
1464                    label: None,
1465                    value: 1.0,
1466                }
1467                .into(),
1468                NumericalValueSpecification {
1469                    label: None,
1470                    value: 3.1,
1471                }
1472                .into(),
1473            ],
1474        };
1475        let constant = package
1476            .create_constant_specification("ConstantSpec", spec.clone())
1477            .unwrap();
1478        let spec_read = constant.value_specification().unwrap();
1479        assert_eq!(spec_read, spec.into());
1480    }
1481
1482    #[test]
1483    fn text_value_specification() {
1484        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1485        let package = model.get_or_create_package("/Pkg").unwrap();
1486
1487        let spec = TextValueSpecification {
1488            label: Some("TextValue".to_string()),
1489            value: "Hello World".to_string(),
1490        };
1491        let constant = package
1492            .create_constant_specification("ConstantSpec", spec.clone())
1493            .unwrap();
1494        let spec_read = constant.value_specification().unwrap();
1495        assert_eq!(spec_read, spec.into());
1496    }
1497
1498    #[test]
1499    fn reference_value_specification() {
1500        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1501        let package = model.get_or_create_package("/Pkg").unwrap();
1502
1503        let base_type = package
1504            .create_sw_base_type("base", 32, BaseTypeEncoding::None, None, None, None)
1505            .unwrap();
1506        let impl_settings = ImplementationDataTypeSettings::Value {
1507            name: "ImplementationValue".to_string(),
1508            base_type,
1509            compu_method: None,
1510            data_constraint: None,
1511        };
1512        let datatype = package.create_implementation_data_type(&impl_settings).unwrap();
1513        let app_data_type = package
1514            .create_application_primitive_data_type(
1515                "AppDataType",
1516                ApplicationPrimitiveCategory::Value,
1517                None,
1518                None,
1519                None,
1520            )
1521            .unwrap();
1522
1523        // create a constant using each different kind of DataPrototype
1524        // ArgumentDataPrototype of a ClientServerInterface
1525        let client_server_interface = ClientServerInterface::new("CS_Interface", &package).unwrap();
1526        let cs_operation = client_server_interface.create_operation("Operation").unwrap();
1527        let argument_data_prototype = cs_operation
1528            .create_argument("adp", &datatype, ArgumentDirection::In)
1529            .unwrap();
1530
1531        let spec = ReferenceValueSpecification {
1532            label: Some("ReferenceValue".to_string()),
1533            reference_value: DataPrototype::ArgumentDataPrototype(argument_data_prototype),
1534        };
1535        let constant = package
1536            .create_constant_specification("ConstantSpec1", spec.clone())
1537            .unwrap();
1538        let spec_read = constant.value_specification().unwrap();
1539        assert_eq!(spec_read, spec.into());
1540
1541        // ParameterDataPrototype of a ParameterInterface
1542        let parameter_interface = package.create_parameter_interface("P_Interface").unwrap();
1543        let parameter_data_prototype = parameter_interface.create_parameter("pdp", &datatype).unwrap();
1544
1545        let spec = ReferenceValueSpecification {
1546            label: Some("ReferenceValue".to_string()),
1547            reference_value: DataPrototype::ParameterDataPrototype(parameter_data_prototype),
1548        };
1549        let constant = package
1550            .create_constant_specification("ConstantSpec2", spec.clone())
1551            .unwrap();
1552        let spec_read = constant.value_specification().unwrap();
1553        assert_eq!(spec_read, spec.into());
1554
1555        // VariableDataPrototype of a SenderReceiverInterface
1556        let sender_receiver_interface = package.create_sender_receiver_interface("SR_Interface").unwrap();
1557        let variable_data_prototype = sender_receiver_interface.create_data_element("vdp", &datatype).unwrap();
1558
1559        let spec = ReferenceValueSpecification {
1560            label: Some("ReferenceValue".to_string()),
1561            reference_value: DataPrototype::VariableDataPrototype(variable_data_prototype),
1562        };
1563        let constant = package
1564            .create_constant_specification("ConstantSpec3", spec.clone())
1565            .unwrap();
1566        let spec_read = constant.value_specification().unwrap();
1567        assert_eq!(spec_read, spec.into());
1568
1569        // ApplicationArrayElement of an ApplicationArrayDataType
1570        let application_array_data_type = package
1571            .create_application_array_data_type(
1572                "ArrayDataType",
1573                &app_data_type,
1574                crate::datatype::ApplicationArraySize::Fixed(1),
1575            )
1576            .unwrap();
1577        let application_array_element = application_array_data_type.array_element().unwrap();
1578
1579        let spec = ReferenceValueSpecification {
1580            label: Some("ReferenceValue".to_string()),
1581            reference_value: DataPrototype::ApplicationArrayElement(application_array_element),
1582        };
1583        let constant = package
1584            .create_constant_specification("ConstantSpec4", spec.clone())
1585            .unwrap();
1586        let spec_read = constant.value_specification().unwrap();
1587        assert_eq!(spec_read, spec.into());
1588
1589        // ApplicationRecordElement of an ApplicationRecordDataType
1590        let application_record_data_type = package.create_application_record_data_type("RecordDataType").unwrap();
1591        let application_record_element = application_record_data_type
1592            .create_record_element("Element", &app_data_type)
1593            .unwrap();
1594
1595        let spec = ReferenceValueSpecification {
1596            label: Some("ReferenceValue".to_string()),
1597            reference_value: DataPrototype::ApplicationRecordElement(application_record_element),
1598        };
1599        let constant = package
1600            .create_constant_specification("ConstantSpec5", spec.clone())
1601            .unwrap();
1602        let spec_read = constant.value_specification().unwrap();
1603        assert_eq!(spec_read, spec.into());
1604    }
1605
1606    #[test]
1607    fn constant_reference_specification() {
1608        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1609        let package = model.get_or_create_package("/Pkg").unwrap();
1610
1611        let spec = NumericalValueSpecification {
1612            label: None,
1613            value: 1.0,
1614        };
1615        let target_constant = package.create_constant_specification("Target", spec).unwrap();
1616
1617        let spec = ConstantReference {
1618            label: Some("ConstantReference".to_string()),
1619            constant: target_constant,
1620        };
1621        let constant = package
1622            .create_constant_specification("ConstantSpec", spec.clone())
1623            .unwrap();
1624        let spec_read = constant.value_specification().unwrap();
1625        assert_eq!(spec_read, spec.into());
1626    }
1627
1628    #[test]
1629    fn application_value_specification() {
1630        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1631        let package = model.get_or_create_package("/Pkg").unwrap();
1632        let unit = package.create_unit("abc", Some("display_name")).unwrap();
1633
1634        let spec = ApplicationValueSpecification {
1635            label: Some("ApplicationValue".to_string()),
1636            category: ApplicationPrimitiveCategory::ResAxis,
1637            sw_axis_conts: vec![
1638                SwAxisCont {
1639                    category: SwAxisContCategory::StdAxis,
1640                    sw_array_size: vec![1, 2],
1641                    sw_axis_index: 1,
1642                    sw_values_phys: vec![SwValue::V(0.0), SwValue::Vf(1.0), SwValue::Vt("text".to_string())],
1643                    unit: Some(unit),
1644                    unit_display_name: Some("display_name".to_string()),
1645                },
1646                SwAxisCont {
1647                    category: SwAxisContCategory::ComAxis,
1648                    sw_array_size: vec![3, 4],
1649                    sw_axis_index: 2,
1650                    sw_values_phys: vec![
1651                        SwValue::Vg {
1652                            label: Some("label".to_string()),
1653                            vg_content: vec![SwValue::VtfNumber(42.0)],
1654                        },
1655                        SwValue::VtfText("text".to_string()),
1656                    ],
1657                    unit: None,
1658                    unit_display_name: None,
1659                },
1660            ],
1661            sw_value_cont: SwValueCont {
1662                sw_array_size: vec![1, 2],
1663                sw_values_phys: vec![SwValue::Vf(0.0), SwValue::Vf(1.0)],
1664            },
1665        };
1666        let constant = package
1667            .create_constant_specification("ConstantSpec", spec.clone())
1668            .unwrap();
1669        let spec_read = constant.value_specification().unwrap();
1670        assert_eq!(spec_read, spec.into());
1671    }
1672
1673    #[test]
1674    fn not_available_value_specification() {
1675        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1676        let package = model.get_or_create_package("/Pkg").unwrap();
1677
1678        let spec = NotAvailableValueSpecification {
1679            label: Some("NotAvailableValue".to_string()),
1680            default_pattern: Some(0x11),
1681        };
1682        let constant = package
1683            .create_constant_specification("ConstantSpec", spec.clone())
1684            .unwrap();
1685        let spec_read = constant.value_specification().unwrap();
1686        assert_eq!(spec_read, spec.into());
1687    }
1688
1689    #[test]
1690    fn aplication_rule_based_value_specification() {
1691        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1692        let package = model.get_or_create_package("/Pkg").unwrap();
1693        let unit = package.create_unit("abc", Some("display_name")).unwrap();
1694
1695        let spec = ApplicationRuleBasedValueSpecification {
1696            label: Some("ApplicationRuleBasedValue".to_string()),
1697            category: ApplicationPrimitiveCategory::ResAxis,
1698            sw_axis_cont: vec![
1699                RuleBasedAxisCont {
1700                    category: SwAxisContCategory::StdAxis,
1701                    sw_array_size: vec![1, 2],
1702                    sw_axis_index: 1,
1703                    rule_based_values: RuleBasedValueSpecification {
1704                        arguments: vec![
1705                            RuleArgument::V(0.0),
1706                            RuleArgument::Vf(1.0),
1707                            RuleArgument::Vt("text".to_string()),
1708                            RuleArgument::VtfNumber(2.0),
1709                            RuleArgument::VtfText("text2".to_string()),
1710                        ],
1711                        max_size_to_fill: Some(10),
1712                        rule: RuleBasedFillUntil::MaxSize,
1713                    },
1714                    unit: Some(unit.clone()),
1715                },
1716                RuleBasedAxisCont {
1717                    category: SwAxisContCategory::ComAxis,
1718                    sw_array_size: vec![3, 4],
1719                    sw_axis_index: 2,
1720                    rule_based_values: RuleBasedValueSpecification {
1721                        arguments: vec![RuleArgument::Vf(0.0), RuleArgument::Vf(1.0)],
1722                        max_size_to_fill: None,
1723                        rule: RuleBasedFillUntil::End,
1724                    },
1725                    unit: None,
1726                },
1727            ],
1728            sw_value_cont: RuleBasedValueCont {
1729                rule_based_values: RuleBasedValueSpecification {
1730                    arguments: vec![RuleArgument::Vf(0.0), RuleArgument::Vf(1.0)],
1731                    max_size_to_fill: None,
1732                    rule: RuleBasedFillUntil::End,
1733                },
1734                sw_array_size: vec![1, 2],
1735                unit: Some(unit),
1736            },
1737        };
1738        let constant = package
1739            .create_constant_specification("ConstantSpec", spec.clone())
1740            .unwrap();
1741        let spec_read = constant.value_specification().unwrap();
1742        assert_eq!(spec_read, spec.into());
1743    }
1744
1745    #[test]
1746    fn composite_rule_based_value_specification() {
1747        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1748        let package = model.get_or_create_package("/Pkg").unwrap();
1749
1750        let spec = CompositeRuleBasedValueSpecification {
1751            label: Some("CompositeRuleBasedValue".to_string()),
1752            argument: vec![CompositeValueSpecification::Array(ArrayValueSpecification {
1753                label: Some("ArrayValue".to_string()),
1754                values: vec![
1755                    NumericalValueSpecification {
1756                        label: None,
1757                        value: 123.4,
1758                    }
1759                    .into(),
1760                    NumericalValueSpecification {
1761                        label: None,
1762                        value: 0.12345,
1763                    }
1764                    .into(),
1765                ],
1766            })],
1767            compound_primitive_argument: vec![
1768                CompositeRuleBasedValueArgument::Application(ApplicationValueSpecification {
1769                    label: Some("ApplicationValue".to_string()),
1770                    category: ApplicationPrimitiveCategory::ResAxis,
1771                    sw_axis_conts: vec![],
1772                    sw_value_cont: SwValueCont {
1773                        sw_array_size: vec![1, 2],
1774                        sw_values_phys: vec![SwValue::Vf(0.0), SwValue::Vf(1.0)],
1775                    },
1776                }),
1777                CompositeRuleBasedValueArgument::ApplicationRuleBased(ApplicationRuleBasedValueSpecification {
1778                    label: Some("ApplicationRuleBasedValue".to_string()),
1779                    category: ApplicationPrimitiveCategory::ResAxis,
1780                    sw_axis_cont: vec![],
1781                    sw_value_cont: RuleBasedValueCont {
1782                        rule_based_values: RuleBasedValueSpecification {
1783                            arguments: vec![RuleArgument::Vf(0.0), RuleArgument::Vf(1.0)],
1784                            max_size_to_fill: None,
1785                            rule: RuleBasedFillUntil::End,
1786                        },
1787                        sw_array_size: vec![1, 2],
1788                        unit: None,
1789                    },
1790                }),
1791            ],
1792            max_size_to_fill: Some(10),
1793            rule: RuleBasedFillUntil::MaxSize,
1794        };
1795        let constant = package
1796            .create_constant_specification("ConstantSpec", spec.clone())
1797            .unwrap();
1798        let spec_read = constant.value_specification().unwrap();
1799        assert_eq!(spec_read, spec.into());
1800    }
1801
1802    #[test]
1803    fn numerical_rule_based_value_specification() {
1804        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1805        let package = model.get_or_create_package("/Pkg").unwrap();
1806
1807        let spec = NumericalRuleBasedValueSpecification {
1808            label: Some("NumericalRuleBasedValue".to_string()),
1809            rule_based_values: RuleBasedValueSpecification {
1810                arguments: vec![RuleArgument::Vf(0.0), RuleArgument::Vf(1.0)],
1811                max_size_to_fill: Some(10),
1812                rule: RuleBasedFillUntil::MaxSize,
1813            },
1814        };
1815        let constant = package
1816            .create_constant_specification("ConstantSpec", spec.clone())
1817            .unwrap();
1818        let spec_read = constant.value_specification().unwrap();
1819        assert_eq!(spec_read, spec.into());
1820    }
1821
1822    #[test]
1823    fn conversions() {
1824        // RuleBasedFillUntil
1825        let value = RuleBasedFillUntil::End;
1826        let value_str = value.to_string();
1827        assert_eq!(value_str, "FILL_UNTIL_END");
1828        assert_eq!(RuleBasedFillUntil::from_str(&value_str).unwrap(), value);
1829
1830        let value = RuleBasedFillUntil::MaxSize;
1831        let value_str = value.to_string();
1832        assert_eq!(value_str, "FILL_UNTIL_MAX_SIZE");
1833        assert_eq!(RuleBasedFillUntil::from_str(&value_str).unwrap(), value);
1834
1835        // SwAxisContCategory
1836        let value = SwAxisContCategory::StdAxis;
1837        let enum_val: EnumItem = value.into();
1838        assert_eq!(enum_val, EnumItem::Stdaxis);
1839        assert_eq!(SwAxisContCategory::try_from(enum_val).unwrap(), value);
1840        // alternative form: EnumItem::StdAxis
1841        let enum_val = EnumItem::StdAxis;
1842        assert_eq!(SwAxisContCategory::try_from(enum_val).unwrap(), value);
1843
1844        let value = SwAxisContCategory::ComAxis;
1845        let enum_val: EnumItem = value.into();
1846        assert_eq!(enum_val, EnumItem::Comaxis);
1847        assert_eq!(SwAxisContCategory::try_from(enum_val).unwrap(), value);
1848        // alternative form: EnumItem::ComAxis
1849        let enum_val = EnumItem::ComAxis;
1850        assert_eq!(SwAxisContCategory::try_from(enum_val).unwrap(), value);
1851
1852        let value = SwAxisContCategory::ResAxis;
1853        let enum_val: EnumItem = value.into();
1854        assert_eq!(enum_val, EnumItem::Resaxis);
1855        assert_eq!(SwAxisContCategory::try_from(enum_val).unwrap(), value);
1856        // alternative form: EnumItem::ResAxis
1857        let enum_val = EnumItem::ResAxis;
1858        assert_eq!(SwAxisContCategory::try_from(enum_val).unwrap(), value);
1859
1860        // invalid conversion
1861        assert!(SwAxisContCategory::try_from(EnumItem::Aa).is_err());
1862    }
1863}