autosar_data_abstraction/ecu_configuration/values/
mod.rs

1use crate::{
2    AbstractionElement, ArPackage, AutosarAbstractionError, IdentifiableAbstractionElement, System,
3    abstraction_element,
4    ecu_configuration::{
5        AbstractEcucContainerDef, AbstractEcucReferenceDef, EcucAddInfoParamDef, EcucContainerDef,
6        EcucInstanceReferenceDef, EcucModuleDef,
7    },
8};
9use autosar_data::{Element, ElementName};
10
11mod parameter;
12mod reference;
13
14pub use parameter::*;
15pub use reference::*;
16
17use super::EcucParamDef;
18
19//#########################################################
20
21/// `EcucValueCollection` collects references to all the separate modules that form the ECU configuration
22#[derive(Debug, Clone, PartialEq, Eq, Hash)]
23pub struct EcucValueCollection(Element);
24abstraction_element!(EcucValueCollection, EcucValueCollection);
25impl IdentifiableAbstractionElement for EcucValueCollection {}
26
27impl EcucValueCollection {
28    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
29        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
30        let ecuc_value_collection_elem = elements.create_named_sub_element(ElementName::EcucValueCollection, name)?;
31
32        Ok(Self(ecuc_value_collection_elem))
33    }
34
35    /// Add a reference to a module configuration to the collection
36    pub fn add_module_configuration(
37        &self,
38        module_configuration: &EcucModuleConfigurationValues,
39    ) -> Result<(), AutosarAbstractionError> {
40        let ecuc_values_elem = self.element().get_or_create_sub_element(ElementName::EcucValues)?;
41        ecuc_values_elem
42            .create_sub_element(ElementName::EcucModuleConfigurationValuesRefConditional)?
43            .create_sub_element(ElementName::EcucModuleConfigurationValuesRef)?
44            .set_reference_target(module_configuration.element())?;
45
46        Ok(())
47    }
48
49    /// Get the module configurations in the collection
50    pub fn module_configurations(&self) -> impl Iterator<Item = EcucModuleConfigurationValues> + Send + use<> {
51        self.element()
52            .get_sub_element(ElementName::EcucValues)
53            .into_iter()
54            .flat_map(|values_elem| values_elem.sub_elements())
55            .filter_map(|ref_cond| {
56                ref_cond
57                    .get_sub_element(ElementName::EcucModuleConfigurationValuesRef)
58                    .and_then(|module_config_ref| module_config_ref.get_reference_target().ok())
59                    .and_then(|module_elem| EcucModuleConfigurationValues::try_from(module_elem).ok())
60            })
61    }
62
63    /// Set the ecu extract reference, which links a `System` to the ECU configuration
64    pub fn set_ecu_extract_reference(&self, system: &System) -> Result<(), AutosarAbstractionError> {
65        self.element()
66            .get_or_create_sub_element(ElementName::EcuExtractRef)?
67            .set_reference_target(system.element())?;
68
69        Ok(())
70    }
71
72    /// Get the system that the ECU configuration is linked to
73    #[must_use]
74    pub fn ecu_extract_reference(&self) -> Option<System> {
75        let system_elem = self
76            .element()
77            .get_sub_element(ElementName::EcuExtractRef)?
78            .get_reference_target()
79            .ok()?;
80        System::try_from(system_elem).ok()
81    }
82}
83
84//#########################################################
85
86/// The `EcucModuleConfigurationValues` is a container for the configuration of a single base software module
87#[derive(Debug, Clone, PartialEq, Eq, Hash)]
88pub struct EcucModuleConfigurationValues(Element);
89abstraction_element!(EcucModuleConfigurationValues, EcucModuleConfigurationValues);
90impl IdentifiableAbstractionElement for EcucModuleConfigurationValues {}
91
92impl EcucModuleConfigurationValues {
93    pub(crate) fn new(
94        name: &str,
95        package: &ArPackage,
96        module_definition: &EcucModuleDef,
97    ) -> Result<Self, AutosarAbstractionError> {
98        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
99        let module_config_elem = elements.create_named_sub_element(ElementName::EcucModuleConfigurationValues, name)?;
100
101        let module_config = Self(module_config_elem);
102        module_config.set_definition(module_definition)?;
103
104        Ok(module_config)
105    }
106
107    /// set the module definition reference
108    pub fn set_definition(&self, module_definition: &EcucModuleDef) -> Result<(), AutosarAbstractionError> {
109        self.element()
110            .get_or_create_sub_element(ElementName::DefinitionRef)?
111            .set_reference_target(module_definition.element())?;
112
113        Ok(())
114    }
115
116    /// get the module definition
117    ///
118    /// This function returns the definition as an `EcucModuleDef` object.
119    /// If the definition is not loaded, use `definition_ref()` instead.
120    #[must_use]
121    pub fn definition(&self) -> Option<EcucModuleDef> {
122        let definition_elem = self
123            .element()
124            .get_sub_element(ElementName::DefinitionRef)?
125            .get_reference_target()
126            .ok()?;
127        EcucModuleDef::try_from(definition_elem).ok()
128    }
129
130    /// get the definition reference as a string
131    ///
132    /// This function is an alternative to `definition()`; it is useful when the
133    /// referenced definition is not loaded and can't be resolved.
134    #[must_use]
135    pub fn definition_ref(&self) -> Option<String> {
136        self.element()
137            .get_sub_element(ElementName::DefinitionRef)?
138            .character_data()?
139            .string_value()
140    }
141
142    /// Create a new `EcucContainerValue` in the module configuration
143    pub fn create_container_value<T: AbstractEcucContainerDef>(
144        &self,
145        name: &str,
146        definition: &T,
147    ) -> Result<EcucContainerValue, AutosarAbstractionError> {
148        let containers_elem = self.element().get_or_create_sub_element(ElementName::Containers)?;
149        EcucContainerValue::new(name, &containers_elem, definition)
150    }
151
152    /// create an iterator over the container values in the module configuration
153    pub fn container_values(&self) -> impl Iterator<Item = EcucContainerValue> + Send + use<> {
154        self.element()
155            .get_sub_element(ElementName::Containers)
156            .into_iter()
157            .flat_map(|containers_elem| containers_elem.sub_elements())
158            .filter_map(|container_elem| EcucContainerValue::try_from(container_elem).ok())
159    }
160}
161
162//#########################################################
163
164/// The `EcucContainerValue` is a container in the ECU configuration
165#[derive(Debug, Clone, PartialEq, Eq, Hash)]
166pub struct EcucContainerValue(Element);
167abstraction_element!(EcucContainerValue, EcucContainerValue);
168impl IdentifiableAbstractionElement for EcucContainerValue {}
169
170impl EcucContainerValue {
171    pub(crate) fn new<T: AbstractEcucContainerDef>(
172        name: &str,
173        parent: &Element,
174        definition: &T,
175    ) -> Result<Self, AutosarAbstractionError> {
176        let container_value_elem = parent.create_named_sub_element(ElementName::EcucContainerValue, name)?;
177        let container_value = Self(container_value_elem);
178
179        container_value.set_definition(definition)?;
180
181        Ok(container_value)
182    }
183
184    /// set the container definition reference
185    pub fn set_definition<T: AbstractEcucContainerDef>(&self, definition: &T) -> Result<(), AutosarAbstractionError> {
186        self.element()
187            .get_or_create_sub_element(ElementName::DefinitionRef)?
188            .set_reference_target(definition.element())?;
189
190        Ok(())
191    }
192
193    /// get the container definition
194    ///
195    /// This function returns the definition as an `EcucContainerDef` object.
196    /// If the definition is not loaded, use `definition_ref()` instead.
197    #[must_use]
198    pub fn definition(&self) -> Option<EcucContainerDef> {
199        let definition_elem = self
200            .element()
201            .get_sub_element(ElementName::DefinitionRef)?
202            .get_reference_target()
203            .ok()?;
204        EcucContainerDef::try_from(definition_elem).ok()
205    }
206
207    /// get the definition reference as a string
208    ///
209    /// This function is an alternative to `definition()`; it is useful when the
210    /// referenced definition is not loaded and can't be resolved.
211    #[must_use]
212    pub fn definition_ref(&self) -> Option<String> {
213        self.element()
214            .get_sub_element(ElementName::DefinitionRef)?
215            .character_data()?
216            .string_value()
217    }
218
219    /// create a sub-container
220    pub fn create_sub_container<T: AbstractEcucContainerDef>(
221        &self,
222        name: &str,
223        definition: &T,
224    ) -> Result<EcucContainerValue, AutosarAbstractionError> {
225        let sub_containers_elem = self.element().get_or_create_sub_element(ElementName::SubContainers)?;
226        EcucContainerValue::new(name, &sub_containers_elem, definition)
227    }
228
229    /// iterate over the sub-containers in this container
230    pub fn sub_containers(&self) -> impl Iterator<Item = EcucContainerValue> + Send + use<> {
231        self.element()
232            .get_sub_element(ElementName::SubContainers)
233            .into_iter()
234            .flat_map(|sub_containers| sub_containers.sub_elements())
235            .filter_map(|elem| EcucContainerValue::try_from(elem).ok())
236    }
237
238    /// set the index of the container
239    ///
240    /// If the container definition has `requiresIndex` set to `true`, then the container
241    /// must have an index. Otherwise the index is meaningless.
242    pub fn set_index(&self, index: Option<u64>) -> Result<(), AutosarAbstractionError> {
243        if let Some(index) = index {
244            self.element()
245                .get_or_create_sub_element(ElementName::Index)?
246                .set_character_data(index)?;
247        } else {
248            self.element().remove_sub_element_kind(ElementName::Index)?;
249        }
250
251        Ok(())
252    }
253
254    /// get the index of the container
255    ///
256    /// If the container definition has `requiresIndex` set to `true`, then the container
257    /// must have an index. Otherwise the index is meaningless.
258    #[must_use]
259    pub fn index(&self) -> Option<u64> {
260        self.element()
261            .get_sub_element(ElementName::Index)?
262            .character_data()?
263            .parse_integer()
264    }
265    /// create a new `EcucNumericalParamValue` in the container
266    pub fn create_numerical_param_value<T: EcucParamDef>(
267        &self,
268        definition: &T,
269        value: &str,
270    ) -> Result<EcucNumericalParamValue, AutosarAbstractionError> {
271        let parameter_values_elem = self.element().get_or_create_sub_element(ElementName::ParameterValues)?;
272        EcucNumericalParamValue::new(&parameter_values_elem, definition, value)
273    }
274
275    /// create a new `EcucTextualParamValue` in the container
276    pub fn create_textual_param_value<T: EcucParamDef>(
277        &self,
278        definition: &T,
279        value: &str,
280    ) -> Result<EcucTextualParamValue, AutosarAbstractionError> {
281        let parameter_values_elem = self.element().get_or_create_sub_element(ElementName::ParameterValues)?;
282        EcucTextualParamValue::new(&parameter_values_elem, definition, value)
283    }
284
285    /// create a new `EcucAddInfoParamValue` in the container
286    pub fn create_add_info_param_value(
287        &self,
288        definition: &EcucAddInfoParamDef,
289    ) -> Result<EcucAddInfoParamValue, AutosarAbstractionError> {
290        let parameter_values_elem = self.element().get_or_create_sub_element(ElementName::ParameterValues)?;
291        EcucAddInfoParamValue::new(&parameter_values_elem, definition)
292    }
293
294    /// iterate over the parameter values in the container
295    pub fn parameter_values(&self) -> impl Iterator<Item = EcucParameterValue> + Send + use<> {
296        self.element()
297            .get_sub_element(ElementName::ParameterValues)
298            .into_iter()
299            .flat_map(|param_values_elem| param_values_elem.sub_elements())
300            .filter_map(|param_elem| EcucParameterValue::try_from(param_elem).ok())
301    }
302
303    /// create a new instance reference value in the container
304    pub fn create_instance_reference(
305        &self,
306        definition: &EcucInstanceReferenceDef,
307        target_context: &[&Element],
308        target: &Element,
309    ) -> Result<EcucInstanceReferenceValue, AutosarAbstractionError> {
310        let reference_values_elem = self.element().get_or_create_sub_element(ElementName::ReferenceValues)?;
311        EcucInstanceReferenceValue::new(&reference_values_elem, definition, target_context, target)
312    }
313
314    /// create a new reference value in the container
315    pub fn create_reference_value<T: AbstractEcucReferenceDef>(
316        &self,
317        definition: &T,
318        target: &Element,
319    ) -> Result<EcucReferenceValue, AutosarAbstractionError> {
320        let reference_values_elem = self.element().get_or_create_sub_element(ElementName::ReferenceValues)?;
321        EcucReferenceValue::new(&reference_values_elem, definition, target)
322    }
323
324    /// iterate over the reference values in the container
325    pub fn reference_values(&self) -> impl Iterator<Item = EcucAnyReferenceValue> + Send + use<> {
326        self.element()
327            .get_sub_element(ElementName::ReferenceValues)
328            .into_iter()
329            .flat_map(|reference_values_elem| reference_values_elem.sub_elements())
330            .filter_map(|reference_elem| EcucAnyReferenceValue::try_from(reference_elem).ok())
331    }
332}
333
334//#########################################################
335
336#[cfg(test)]
337mod test {
338    use crate::{AbstractionElement, AutosarModelAbstraction, system};
339    use autosar_data::{AutosarVersion, ElementName};
340
341    #[test]
342    fn test_ecu_configuration_values() {
343        let definition_model = AutosarModelAbstraction::create("definition.arxml", AutosarVersion::LATEST);
344        let def_package = definition_model.get_or_create_package("/def_package").unwrap();
345
346        let values_model = AutosarModelAbstraction::create("values.arxml", AutosarVersion::LATEST);
347        let val_package = values_model.get_or_create_package("/val_package").unwrap();
348
349        // create a definition for the ECU configuration
350        let module_def = def_package.create_ecuc_module_def("ModuleDef").unwrap();
351        let container_def = module_def.create_param_conf_container_def("ContainerDef").unwrap();
352
353        // create an ecu configuration based on the definition model
354        let ecuc_value_collection = val_package.create_ecuc_value_collection("EcucValues").unwrap();
355        assert_eq!(ecuc_value_collection.ecu_extract_reference(), None);
356        let system = val_package
357            .create_system("System", system::SystemCategory::EcuExtract)
358            .unwrap();
359        ecuc_value_collection.set_ecu_extract_reference(&system).unwrap();
360        assert_eq!(ecuc_value_collection.ecu_extract_reference().unwrap(), system);
361        assert_eq!(ecuc_value_collection.module_configurations().count(), 0);
362
363        let ecuc_config_values = val_package
364            .create_ecuc_module_configuration_values("Module", &module_def)
365            .unwrap();
366        ecuc_value_collection
367            .add_module_configuration(&ecuc_config_values)
368            .unwrap();
369        assert_eq!(ecuc_value_collection.module_configurations().count(), 1);
370        assert_eq!(ecuc_config_values.definition_ref(), module_def.element().path().ok());
371        // the definition is not loaded in the same model, so we can't get it
372        assert!(ecuc_config_values.definition().is_none());
373
374        let container_values = ecuc_config_values
375            .create_container_value("Container", &container_def)
376            .unwrap();
377        assert_eq!(container_values.definition_ref(), container_def.element().path().ok());
378        assert!(container_values.definition().is_none());
379        assert_eq!(container_values.index(), None);
380        container_values.set_index(Some(0)).unwrap();
381        assert_eq!(container_values.index(), Some(0));
382        assert_eq!(ecuc_config_values.container_values().count(), 1);
383
384        let sub_container_value = container_values
385            .create_sub_container("SubContainer", &container_def)
386            .unwrap();
387        assert_eq!(
388            sub_container_value.definition_ref(),
389            container_def.element().path().ok()
390        );
391        assert_eq!(container_values.sub_containers().count(), 1);
392
393        // copy the definition into the value model
394        // once the definition and values are in the same model, we can get the definition directly
395        values_model
396            .root_element()
397            .get_sub_element(ElementName::ArPackages)
398            .unwrap()
399            .create_copied_sub_element(def_package.element())
400            .unwrap();
401        // get the definitions from the value model
402    }
403}