autosar_data_abstraction/ecu_configuration/values/
parameter.rs

1use crate::{
2    AbstractionElement, AutosarAbstractionError, IdentifiableAbstractionElement, abstraction_element,
3    ecu_configuration::{EcucAddInfoParamDef, EcucParamDef, EcucParameterDef},
4};
5use autosar_data::{Element, ElementName};
6
7//#########################################################
8
9/// The `EcucAddInfoParamValue` holds descriptive text and takes the role of a parameter in the ECU configuration
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11pub struct EcucAddInfoParamValue(Element);
12abstraction_element!(EcucAddInfoParamValue, EcucAddInfoParamValue);
13
14impl EcucAddInfoParamValue {
15    pub(crate) fn new(parent: &Element, definition: &EcucAddInfoParamDef) -> Result<Self, AutosarAbstractionError> {
16        let add_info_param_elem = parent.create_sub_element(ElementName::EcucAddInfoParamValue)?;
17        add_info_param_elem
18            .get_or_create_sub_element(ElementName::DefinitionRef)?
19            .set_reference_target(definition.element())?;
20        Ok(Self(add_info_param_elem))
21    }
22
23    // Stub - does anyone actually use this?
24}
25
26//#########################################################
27
28/// The `EcucNumericalParamValue` holds a numerical value and can represent boolean, float or int parameter definitions.
29///
30/// Internally this value is stored as a string; in additon to the `value()` function, there are also
31/// `value_bool()`, `value_int()` and `value_float()` functions, which parse the string and should be used as appropriate.
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33pub struct EcucNumericalParamValue(Element);
34abstraction_element!(EcucNumericalParamValue, EcucNumericalParamValue);
35
36impl EcucNumericalParamValue {
37    pub(crate) fn new<T: EcucParamDef>(
38        parent: &Element,
39        definition: &T,
40        value: &str,
41    ) -> Result<Self, AutosarAbstractionError> {
42        let numerical_param_elem = parent.create_sub_element(ElementName::EcucNumericalParamValue)?;
43
44        let numerical_param = Self(numerical_param_elem);
45        numerical_param.set_definition(definition)?;
46        numerical_param.set_value(value)?;
47
48        Ok(numerical_param)
49    }
50
51    /// set the parameter definition reference
52    pub fn set_definition<T: EcucParamDef>(&self, definition: &T) -> Result<(), AutosarAbstractionError> {
53        self.element()
54            .get_or_create_sub_element(ElementName::DefinitionRef)?
55            .set_reference_target(definition.element())?;
56
57        Ok(())
58    }
59
60    /// get the parameter definition
61    ///
62    /// This function returns the definition as an `EcucParameterDef` enum, which
63    /// could contain either an `EcucFloatParamDef` or an `EcucIntegerParamDef`.
64    /// If the definition is not loaded, use `definition_ref()` instead.
65    #[must_use]
66    pub fn definition(&self) -> Option<EcucParameterDef> {
67        let definition_elem = self
68            .element()
69            .get_sub_element(ElementName::DefinitionRef)?
70            .get_reference_target()
71            .ok()?;
72        EcucParameterDef::try_from(definition_elem).ok()
73    }
74
75    /// get the parameter definition reference as a string
76    ///
77    /// This function is an alternative to `definition()`; it is useful when the
78    /// referenced definition is not loaded and can't be resolved.
79    #[must_use]
80    pub fn definition_ref(&self) -> Option<String> {
81        self.element()
82            .get_sub_element(ElementName::DefinitionRef)?
83            .character_data()?
84            .string_value()
85    }
86
87    /// set the numerical value as a string
88    pub fn set_value(&self, value: &str) -> Result<(), AutosarAbstractionError> {
89        self.element()
90            .get_or_create_sub_element(ElementName::Value)?
91            .set_character_data(value)?;
92
93        Ok(())
94    }
95
96    /// get the numerical value as a string
97    #[must_use]
98    pub fn value(&self) -> Option<String> {
99        self.element()
100            .get_sub_element(ElementName::Value)?
101            .character_data()?
102            .string_value()
103    }
104
105    /// get the numerical value as a boolean
106    #[must_use]
107    pub fn value_bool(&self) -> Option<bool> {
108        self.element()
109            .get_sub_element(ElementName::Value)?
110            .character_data()?
111            .parse_bool()
112    }
113
114    /// get the numerical value as an integer
115    #[must_use]
116    pub fn value_int(&self) -> Option<i64> {
117        self.element()
118            .get_sub_element(ElementName::Value)?
119            .character_data()?
120            .parse_integer()
121    }
122
123    /// get the numerical value as a float
124    #[must_use]
125    pub fn value_float(&self) -> Option<f64> {
126        self.element()
127            .get_sub_element(ElementName::Value)?
128            .character_data()?
129            .parse_float()
130    }
131
132    /// set the index of the parameter
133    ///
134    /// If the parameter definition has `requiresIndex` set to `true`, then the parameter
135    /// must have an index. Otherwise the index is meaningless.
136    pub fn set_index(&self, index: Option<u64>) -> Result<(), AutosarAbstractionError> {
137        if let Some(index) = index {
138            self.element()
139                .get_or_create_sub_element(ElementName::Index)?
140                .set_character_data(index)?;
141        } else {
142            let _ = self.element().remove_sub_element_kind(ElementName::Index);
143        }
144
145        Ok(())
146    }
147
148    /// get the index of the parameter
149    ///
150    /// If the parameter definition has `requiresIndex` set to `true`, then the parameter
151    /// must have an index. Otherwise the index is meaningless.
152    #[must_use]
153    pub fn index(&self) -> Option<u64> {
154        self.element()
155            .get_sub_element(ElementName::Index)?
156            .character_data()?
157            .parse_integer()
158    }
159
160    /// set the isAutoValue flag
161    ///
162    /// If the parameter definition has `withAuto` set to `true`, then the parameter is allowed to have an auto value.
163    pub fn set_is_auto_value(&self, is_auto_value: Option<bool>) -> Result<(), AutosarAbstractionError> {
164        if let Some(is_auto_value) = is_auto_value {
165            self.element()
166                .get_or_create_sub_element(ElementName::IsAutoValue)?
167                .set_character_data(is_auto_value)?;
168        } else {
169            let _ = self.element().remove_sub_element_kind(ElementName::IsAutoValue);
170        }
171
172        Ok(())
173    }
174
175    /// get the isAutoValue flag
176    #[must_use]
177    pub fn is_auto_value(&self) -> Option<bool> {
178        self.element()
179            .get_sub_element(ElementName::IsAutoValue)?
180            .character_data()?
181            .parse_bool()
182    }
183}
184
185//#########################################################
186
187/// The `EcucTextualParamValue` holds a string value and can represent a enumeration,
188///  string, multi-line string, function name or linker symbol parameter definition.
189#[derive(Debug, Clone, PartialEq, Eq, Hash)]
190pub struct EcucTextualParamValue(Element);
191abstraction_element!(EcucTextualParamValue, EcucTextualParamValue);
192
193impl EcucTextualParamValue {
194    pub(crate) fn new<T: EcucParamDef>(
195        parent: &Element,
196        definition: &T,
197        value: &str,
198    ) -> Result<Self, AutosarAbstractionError> {
199        let textual_param_elem = parent.create_sub_element(ElementName::EcucTextualParamValue)?;
200
201        let textual_param = Self(textual_param_elem);
202        textual_param.set_definition(definition)?;
203        textual_param.set_value(value)?;
204
205        Ok(textual_param)
206    }
207
208    /// set the parameter definition reference
209    pub fn set_definition<T: EcucParamDef>(&self, definition: &T) -> Result<(), AutosarAbstractionError> {
210        self.element()
211            .get_or_create_sub_element(ElementName::DefinitionRef)?
212            .set_reference_target(definition.element())?;
213
214        Ok(())
215    }
216
217    /// get the parameter definition
218    ///
219    /// This function returns the definition as an `EcucParameterDef` enum, which
220    /// could contain either an `EcucStringParamDef`, `EcucMultiStringParamDef`,
221    /// `EcucFunctionNameDef` or `EcucLinkerSymbolDef`.
222    /// If the definition is not loaded, use `definition_ref()` instead.
223    #[must_use]
224    pub fn definition(&self) -> Option<EcucParameterDef> {
225        let definition_elem = self
226            .element()
227            .get_sub_element(ElementName::DefinitionRef)?
228            .get_reference_target()
229            .ok()?;
230        EcucParameterDef::try_from(definition_elem).ok()
231    }
232
233    /// get the parameter definition reference as a string
234    ///
235    /// This function is an alternative to `definition()`; it is useful when the
236    /// referenced definition is not loaded and can't be resolved.
237    #[must_use]
238    pub fn definition_ref(&self) -> Option<String> {
239        self.element()
240            .get_sub_element(ElementName::DefinitionRef)?
241            .character_data()?
242            .string_value()
243    }
244
245    /// set the textual value
246    pub fn set_value(&self, value: &str) -> Result<(), AutosarAbstractionError> {
247        self.element()
248            .get_or_create_sub_element(ElementName::Value)?
249            .set_character_data(value)?;
250
251        Ok(())
252    }
253
254    /// get the textual value
255    #[must_use]
256    pub fn value(&self) -> Option<String> {
257        self.element()
258            .get_sub_element(ElementName::Value)?
259            .character_data()?
260            .string_value()
261    }
262
263    /// set the index of the parameter
264    ///
265    /// If the parameter definition has `requiresIndex` set to `true`, then the parameter
266    /// must have an index. Otherwise the index is meaningless.
267    pub fn set_index(&self, index: Option<u64>) -> Result<(), AutosarAbstractionError> {
268        if let Some(index) = index {
269            self.element()
270                .get_or_create_sub_element(ElementName::Index)?
271                .set_character_data(index)?;
272        } else {
273            let _ = self.element().remove_sub_element_kind(ElementName::Index);
274        }
275
276        Ok(())
277    }
278
279    /// get the index of the parameter
280    ///
281    /// If the parameter definition has `requiresIndex` set to `true`, then the parameter
282    /// must have an index. Otherwise the index is meaningless.
283    #[must_use]
284    pub fn index(&self) -> Option<u64> {
285        self.element()
286            .get_sub_element(ElementName::Index)?
287            .character_data()?
288            .parse_integer()
289    }
290
291    /// set the isAutoValue flag
292    ///
293    /// If the parameter definition has `withAuto` set to `true`, then the parameter is allowed to have an auto value.
294    pub fn set_is_auto_value(&self, is_auto_value: Option<bool>) -> Result<(), AutosarAbstractionError> {
295        if let Some(is_auto_value) = is_auto_value {
296            self.element()
297                .get_or_create_sub_element(ElementName::IsAutoValue)?
298                .set_character_data(is_auto_value)?;
299        } else {
300            let _ = self.element().remove_sub_element_kind(ElementName::IsAutoValue);
301        }
302
303        Ok(())
304    }
305
306    /// get the isAutoValue flag
307    ///
308    /// If the parameter definition has `withAuto` set to `true`, then the parameter is allowed to have an auto value.
309    #[must_use]
310    pub fn is_auto_value(&self) -> Option<bool> {
311        self.element()
312            .get_sub_element(ElementName::IsAutoValue)?
313            .character_data()?
314            .parse_bool()
315    }
316}
317
318//#########################################################
319
320/// The `EcucParameterValue` is an enum that can hold an `EcucAddInfoParamValue`,
321/// an `EcucNumericalParamValue` or an `EcucTextualParamValue`.
322#[derive(Debug, Clone, PartialEq, Eq, Hash)]
323pub enum EcucParameterValue {
324    /// AddInfo parameter value
325    AddInfo(EcucAddInfoParamValue),
326    /// Numerical parameter value
327    Numerical(EcucNumericalParamValue),
328    /// Textual parameter value
329    Textual(EcucTextualParamValue),
330}
331
332impl AbstractionElement for EcucParameterValue {
333    fn element(&self) -> &Element {
334        match self {
335            EcucParameterValue::AddInfo(elem) => elem.element(),
336            EcucParameterValue::Numerical(elem) => elem.element(),
337            EcucParameterValue::Textual(elem) => elem.element(),
338        }
339    }
340}
341
342impl TryFrom<Element> for EcucParameterValue {
343    type Error = AutosarAbstractionError;
344
345    fn try_from(element: Element) -> Result<Self, Self::Error> {
346        match element.element_name() {
347            ElementName::EcucAddInfoParamValue => Ok(EcucParameterValue::AddInfo(EcucAddInfoParamValue(element))),
348            ElementName::EcucNumericalParamValue => Ok(EcucParameterValue::Numerical(EcucNumericalParamValue(element))),
349            ElementName::EcucTextualParamValue => Ok(EcucParameterValue::Textual(EcucTextualParamValue(element))),
350            _ => Err(AutosarAbstractionError::ConversionError {
351                element,
352                dest: "EcucParameterValue".to_string(),
353            }),
354        }
355    }
356}
357
358impl IdentifiableAbstractionElement for EcucParameterValue {}
359
360//#########################################################
361
362#[cfg(test)]
363mod test {
364    use crate::{
365        AbstractionElement, AutosarModelAbstraction,
366        ecu_configuration::{EcucParameterDef, EcucParameterValue},
367    };
368    use autosar_data::{AutosarVersion, ElementName};
369
370    #[test]
371    fn test_parameter_values() {
372        let definition_model = AutosarModelAbstraction::create("definition.arxml", AutosarVersion::LATEST);
373        let def_package = definition_model.get_or_create_package("/def_package").unwrap();
374
375        let values_model = AutosarModelAbstraction::create("values.arxml", AutosarVersion::LATEST);
376        let val_package = values_model.get_or_create_package("/val_package").unwrap();
377
378        // create a definition for the ECU configuration
379        let module_def = def_package.create_ecuc_module_def("ModuleDef").unwrap();
380        let container_def = module_def.create_param_conf_container_def("ContainerDef").unwrap();
381        let add_info_param_def = container_def
382            .create_add_info_param_def("AddInfoParam", "AUTOSAR_ECUC")
383            .unwrap();
384        let int_param_def = container_def
385            .create_integer_param_def("IntParam", "AUTOSAR_ECUC")
386            .unwrap();
387        let float_param_def = container_def
388            .create_float_param_def("FloatParam", "AUTOSAR_ECUC")
389            .unwrap();
390        let bool_param_def = container_def
391            .create_boolean_param_def("BoolParam", "AUTOSAR_ECUC")
392            .unwrap();
393        let string_param_def = container_def
394            .create_string_param_def("StringParam", "AUTOSAR_ECUC")
395            .unwrap();
396        let fnc_param_def = container_def
397            .create_function_name_param_def("FncParam", "AUTOSAR_ECUC")
398            .unwrap();
399        let link_param_def = container_def
400            .create_linker_symbol_param_def("LinkParam", "AUTOSAR_ECUC")
401            .unwrap();
402        let enum_param_def = container_def
403            .create_enumeration_param_def("EnumParam", "AUTOSAR_ECUC")
404            .unwrap();
405        enum_param_def.create_enumeration_literal("EnumLiteral_1").unwrap();
406        enum_param_def.create_enumeration_literal("EnumLiteral_2").unwrap();
407
408        // create an ecu configuration based on the definition model
409        let ecuc_value_collection = val_package.create_ecuc_value_collection("EcucValues").unwrap();
410        let ecuc_config_values = val_package
411            .create_ecuc_module_configuration_values("Module", &module_def)
412            .unwrap();
413        ecuc_value_collection
414            .add_module_configuration(&ecuc_config_values)
415            .unwrap();
416        let container_values = ecuc_config_values
417            .create_container_value("Container", &container_def)
418            .unwrap();
419
420        let add_info_param_value = container_values
421            .create_add_info_param_value(&add_info_param_def)
422            .unwrap();
423        // no assertions for add_info_param_value, since it is a stub type without any functionality
424        let int_param_value = container_values
425            .create_numerical_param_value(&int_param_def, "42")
426            .unwrap();
427        assert_eq!(int_param_value.value_int(), Some(42));
428        int_param_value.set_value("43").unwrap();
429        assert_eq!(int_param_value.value_int(), Some(43));
430        int_param_value.set_index(Some(1)).unwrap();
431        assert_eq!(int_param_value.index(), Some(1));
432        int_param_value.set_is_auto_value(Some(true)).unwrap();
433        assert_eq!(int_param_value.is_auto_value(), Some(true));
434        assert_eq!(int_param_value.definition_ref(), int_param_def.element().path().ok());
435        // the definition is not loaded in the same model, so we can't get it
436        assert!(int_param_value.definition().is_none());
437
438        let float_param_value = container_values
439            .create_numerical_param_value(&float_param_def, "3.14")
440            .unwrap();
441        assert_eq!(float_param_value.value().as_deref(), Some("3.14"));
442        assert_eq!(float_param_value.value_float(), Some(3.14));
443        float_param_value.set_value("2.71").unwrap();
444        assert_eq!(float_param_value.value_float(), Some(2.71));
445        float_param_value.set_index(Some(2)).unwrap();
446        assert_eq!(float_param_value.index(), Some(2));
447        float_param_value.set_is_auto_value(Some(false)).unwrap();
448        assert_eq!(float_param_value.is_auto_value(), Some(false));
449        assert_eq!(
450            float_param_value.definition_ref(),
451            float_param_def.element().path().ok()
452        );
453
454        let bool_param_value = container_values
455            .create_numerical_param_value(&bool_param_def, "true")
456            .unwrap();
457        assert_eq!(bool_param_value.value().as_deref(), Some("true"));
458        assert_eq!(bool_param_value.value_bool(), Some(true));
459        bool_param_value.set_value("false").unwrap();
460        assert_eq!(bool_param_value.value_bool(), Some(false));
461        bool_param_value.set_index(Some(3)).unwrap();
462        assert_eq!(bool_param_value.index(), Some(3));
463        bool_param_value.set_is_auto_value(None).unwrap();
464        assert_eq!(bool_param_value.is_auto_value(), None);
465        assert_eq!(bool_param_value.definition_ref(), bool_param_def.element().path().ok());
466
467        let string_param_value = container_values
468            .create_textual_param_value(&string_param_def, "Hello, World!")
469            .unwrap();
470        assert_eq!(string_param_value.value().as_deref(), Some("Hello, World!"));
471        string_param_value.set_value("Goodbye, World!").unwrap();
472        assert_eq!(string_param_value.value().as_deref(), Some("Goodbye, World!"));
473        string_param_value.set_index(Some(4)).unwrap();
474        assert_eq!(string_param_value.index(), Some(4));
475        string_param_value.set_is_auto_value(Some(true)).unwrap();
476        assert_eq!(string_param_value.is_auto_value(), Some(true));
477        assert_eq!(
478            string_param_value.definition_ref(),
479            string_param_def.element().path().ok()
480        );
481
482        let fnc_param_value = container_values
483            .create_textual_param_value(&fnc_param_def, "function_name")
484            .unwrap();
485        let link_param_value = container_values
486            .create_textual_param_value(&link_param_def, "linker_symbol")
487            .unwrap();
488
489        let enum_param_value = container_values
490            .create_textual_param_value(&enum_param_def, "EnumLiteral_1")
491            .unwrap();
492        assert_eq!(enum_param_value.value().as_deref(), Some("EnumLiteral_1"));
493        enum_param_value.set_value("EnumLiteral_2").unwrap();
494        assert_eq!(enum_param_value.value().as_deref(), Some("EnumLiteral_2"));
495        enum_param_value.set_index(Some(5)).unwrap();
496        assert_eq!(enum_param_value.index(), Some(5));
497        enum_param_value.set_is_auto_value(Some(false)).unwrap();
498        assert_eq!(enum_param_value.is_auto_value(), Some(false));
499        assert_eq!(enum_param_value.definition_ref(), enum_param_def.element().path().ok());
500
501        let mut parameters_iter = container_values.parameter_values();
502        assert_eq!(
503            parameters_iter.next().unwrap(),
504            EcucParameterValue::AddInfo(add_info_param_value.clone())
505        );
506        assert_eq!(
507            parameters_iter.next().unwrap(),
508            EcucParameterValue::Numerical(int_param_value.clone())
509        );
510        assert_eq!(
511            parameters_iter.next().unwrap(),
512            EcucParameterValue::Numerical(float_param_value.clone())
513        );
514        assert_eq!(
515            parameters_iter.next().unwrap(),
516            EcucParameterValue::Numerical(bool_param_value.clone())
517        );
518        assert_eq!(
519            parameters_iter.next().unwrap(),
520            EcucParameterValue::Textual(string_param_value.clone())
521        );
522        assert_eq!(
523            parameters_iter.next().unwrap(),
524            EcucParameterValue::Textual(fnc_param_value.clone())
525        );
526        assert_eq!(
527            parameters_iter.next().unwrap(),
528            EcucParameterValue::Textual(link_param_value.clone())
529        );
530        assert_eq!(
531            parameters_iter.next().unwrap(),
532            EcucParameterValue::Textual(enum_param_value.clone())
533        );
534        assert_eq!(container_values.parameter_values().count(), 8);
535        let ecuc_param = container_values.parameter_values().next().unwrap();
536        assert_eq!(ecuc_param.element(), add_info_param_value.element());
537
538        // copy the definition into the value model
539        // once the definition and values are in the same model, we can get the definition directly
540        values_model
541            .root_element()
542            .get_sub_element(ElementName::ArPackages)
543            .unwrap()
544            .create_copied_sub_element(def_package.element())
545            .unwrap();
546        // get the definitions from the value model
547        let int_param_def = EcucParameterDef::try_from(
548            values_model
549                .get_element_by_path(&int_param_def.element().path().unwrap())
550                .unwrap(),
551        )
552        .unwrap();
553        let float_param_def = EcucParameterDef::try_from(
554            values_model
555                .get_element_by_path(&float_param_def.element().path().unwrap())
556                .unwrap(),
557        )
558        .unwrap();
559        let bool_param_def = EcucParameterDef::try_from(
560            values_model
561                .get_element_by_path(&bool_param_def.element().path().unwrap())
562                .unwrap(),
563        )
564        .unwrap();
565        let string_param_def = EcucParameterDef::try_from(
566            values_model
567                .get_element_by_path(&string_param_def.element().path().unwrap())
568                .unwrap(),
569        )
570        .unwrap();
571        let enum_param_def = EcucParameterDef::try_from(
572            values_model
573                .get_element_by_path(&enum_param_def.element().path().unwrap())
574                .unwrap(),
575        )
576        .unwrap();
577
578        // get the definition from the value model
579        assert_eq!(int_param_value.definition().unwrap(), int_param_def);
580        assert_eq!(float_param_value.definition().unwrap(), float_param_def);
581        assert_eq!(bool_param_value.definition().unwrap(), bool_param_def);
582        assert_eq!(string_param_value.definition().unwrap(), string_param_def);
583        assert_eq!(enum_param_value.definition().unwrap(), enum_param_def);
584
585        assert_eq!(int_param_value.definition().unwrap().element(), int_param_def.element());
586    }
587}