autosar_data_abstraction/datatype/
applicationtype.rs

1use crate::{
2    AbstractionElement, ArPackage, AutosarAbstractionError, Element, IdentifiableAbstractionElement,
3    abstraction_element,
4    datatype::{self, DataTypeMap},
5    get_reference_parents, is_used,
6    software_component::{ArgumentDataPrototype, ParameterDataPrototype, VariableDataPrototype},
7};
8use autosar_data::{ElementName, EnumItem};
9use datatype::{AbstractAutosarDataType, CompuMethod, DataConstr, Unit};
10
11//#########################################################
12
13/// An application array data type
14///
15/// Use [`ArPackage::create_application_array_data_type`] to create a new application array data type.
16#[derive(Debug, Clone, PartialEq, Eq, Hash)]
17pub struct ApplicationArrayDataType(Element);
18abstraction_element!(ApplicationArrayDataType, ApplicationArrayDataType);
19impl IdentifiableAbstractionElement for ApplicationArrayDataType {}
20impl AbstractAutosarDataType for ApplicationArrayDataType {}
21
22impl ApplicationArrayDataType {
23    /// create a new application array data type in the given package
24    pub(crate) fn new<T: Into<ApplicationDataType> + AbstractionElement>(
25        name: &str,
26        package: &ArPackage,
27        element_type: &T,
28        size: ApplicationArraySize,
29    ) -> Result<Self, AutosarAbstractionError> {
30        let element_type = element_type.clone().into();
31        Self::new_internal(name, package, &element_type, size)
32    }
33
34    /// remove the application array data type from the model
35    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
36        if let Some(array_element) = self.array_element() {
37            array_element.remove(deep)?;
38        }
39        let ref_parents = get_reference_parents(self.element())?;
40
41        AbstractionElement::remove(self, deep)?;
42
43        remove_helper(ref_parents, deep)
44    }
45
46    fn new_internal(
47        name: &str,
48        package: &ArPackage,
49        element_type: &ApplicationDataType,
50        size: ApplicationArraySize,
51    ) -> Result<Self, AutosarAbstractionError> {
52        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
53        let application_array_data_type =
54            elements.create_named_sub_element(ElementName::ApplicationArrayDataType, name)?;
55
56        application_array_data_type
57            .create_sub_element(ElementName::Category)?
58            .set_character_data("ARRAY")?;
59
60        let application_array_data_type = Self(application_array_data_type);
61        ApplicationArrayElement::new("Element", &application_array_data_type, element_type)?;
62
63        // set the size of the array after creating the array element, since some settings must be set in the array element
64        application_array_data_type.set_size(size)?;
65
66        Ok(application_array_data_type)
67    }
68
69    /// get the array element of the array data type
70    #[must_use]
71    pub fn array_element(&self) -> Option<ApplicationArrayElement> {
72        self.element().get_sub_element(ElementName::Element)?.try_into().ok()
73    }
74
75    /// set the size of the array
76    pub fn set_size(&self, size: ApplicationArraySize) -> Result<(), AutosarAbstractionError> {
77        let array_element = self.array_element().ok_or(AutosarAbstractionError::InvalidParameter(
78            "Array data type has no array element".to_string(),
79        ))?;
80        if let Some(datatype) = array_element.data_type() {
81            let is_array_datatype = matches!(datatype, ApplicationDataType::Array(_));
82            if is_array_datatype && matches!(size, ApplicationArraySize::VariableLinear(_)) {
83                return Err(AutosarAbstractionError::InvalidParameter(
84                    "When the size type is VariableLinear, the element type may not be an array".to_string(),
85                ));
86            } else if !is_array_datatype
87                && matches!(
88                    size,
89                    ApplicationArraySize::VariableSquare
90                        | ApplicationArraySize::VariableRectangular(_)
91                        | ApplicationArraySize::VariableFullyFlexible(_)
92                )
93            {
94                return Err(AutosarAbstractionError::InvalidParameter(
95                    "When the size type is VariableSquare, VariableRectangular or VariableFullyFlexible, the element type must be an array".to_string(),
96                ));
97            }
98        }
99        let array_element_elem = array_element.element();
100        match size {
101            ApplicationArraySize::Fixed(size) => {
102                let _ = self
103                    .element()
104                    .remove_sub_element_kind(ElementName::DynamicArraySizeProfile);
105                array_element_elem
106                    .get_or_create_sub_element(ElementName::MaxNumberOfElements)?
107                    .set_character_data(size)?;
108                array_element_elem
109                    .get_or_create_sub_element(ElementName::ArraySizeSemantics)?
110                    .set_character_data(EnumItem::FixedSize)?;
111                let _ = array_element_elem.remove_sub_element_kind(ElementName::ArraySizeHandling);
112            }
113            ApplicationArraySize::VariableLinear(max_size) => {
114                self.element()
115                    .get_or_create_sub_element(ElementName::DynamicArraySizeProfile)?
116                    .set_character_data("VSA_LINEAR")?;
117                array_element_elem
118                    .get_or_create_sub_element(ElementName::MaxNumberOfElements)?
119                    .set_character_data(max_size)?;
120                array_element_elem
121                    .get_or_create_sub_element(ElementName::ArraySizeSemantics)?
122                    .set_character_data(EnumItem::VariableSize)?;
123                array_element_elem
124                    .get_or_create_sub_element(ElementName::ArraySizeHandling)?
125                    .set_character_data(EnumItem::AllIndicesSameArraySize)?;
126            }
127            ApplicationArraySize::VariableSquare => {
128                self.element()
129                    .get_or_create_sub_element(ElementName::DynamicArraySizeProfile)?
130                    .set_character_data("VSA_SQUARE")?;
131                let _ = array_element_elem.remove_sub_element_kind(ElementName::MaxNumberOfElements);
132                array_element_elem
133                    .get_or_create_sub_element(ElementName::ArraySizeSemantics)?
134                    .set_character_data(EnumItem::VariableSize)?;
135                array_element_elem
136                    .get_or_create_sub_element(ElementName::ArraySizeHandling)?
137                    .set_character_data(EnumItem::InheritedFromArrayElementTypeSize)?;
138            }
139            ApplicationArraySize::VariableRectangular(max_size) => {
140                self.element()
141                    .get_or_create_sub_element(ElementName::DynamicArraySizeProfile)?
142                    .set_character_data("VSA_RECTANGULAR")?;
143                array_element_elem
144                    .get_or_create_sub_element(ElementName::MaxNumberOfElements)?
145                    .set_character_data(max_size)?;
146                array_element_elem
147                    .get_or_create_sub_element(ElementName::ArraySizeSemantics)?
148                    .set_character_data(EnumItem::VariableSize)?;
149                array_element_elem
150                    .get_or_create_sub_element(ElementName::ArraySizeHandling)?
151                    .set_character_data(EnumItem::AllIndicesSameArraySize)?;
152            }
153            ApplicationArraySize::VariableFullyFlexible(max_size) => {
154                self.element()
155                    .get_or_create_sub_element(ElementName::DynamicArraySizeProfile)?
156                    .set_character_data("VSA_FULLY_FLEXIBLE")?;
157                array_element_elem
158                    .get_or_create_sub_element(ElementName::MaxNumberOfElements)?
159                    .set_character_data(max_size)?;
160                array_element_elem
161                    .get_or_create_sub_element(ElementName::ArraySizeSemantics)?
162                    .set_character_data(EnumItem::VariableSize)?;
163                array_element_elem
164                    .get_or_create_sub_element(ElementName::ArraySizeHandling)?
165                    .set_character_data(EnumItem::AllIndicesDifferentArraySize)?;
166            }
167        }
168
169        Ok(())
170    }
171
172    /// get the size of the array
173    #[must_use]
174    pub fn size(&self) -> Option<ApplicationArraySize> {
175        let max_number_of_elements = self
176            .array_element()?
177            .element()
178            .get_sub_element(ElementName::MaxNumberOfElements);
179
180        if let Some(size_profile) = self
181            .element()
182            .get_sub_element(ElementName::DynamicArraySizeProfile)
183            .and_then(|elem| elem.character_data().and_then(|cdata| cdata.string_value()))
184        {
185            match size_profile.as_str() {
186                "VSA_LINEAR" => {
187                    let max_size = max_number_of_elements?.character_data()?.parse_integer()?;
188                    Some(ApplicationArraySize::VariableLinear(max_size))
189                }
190                "VSA_SQUARE" => Some(ApplicationArraySize::VariableSquare),
191                "VSA_RECTANGULAR" => {
192                    let max_size = max_number_of_elements?.character_data()?.parse_integer()?;
193                    Some(ApplicationArraySize::VariableRectangular(max_size))
194                }
195                "VSA_FULLY_FLEXIBLE" => {
196                    let max_size = max_number_of_elements?.character_data()?.parse_integer()?;
197                    Some(ApplicationArraySize::VariableFullyFlexible(max_size))
198                }
199                _ => None,
200            }
201        } else {
202            let size = max_number_of_elements?.character_data()?.parse_integer()?;
203            Some(ApplicationArraySize::Fixed(size))
204        }
205    }
206}
207
208//#########################################################
209
210/// definition of the size type of an application array data type
211#[derive(Debug, Clone, PartialEq, Eq, Hash)]
212pub enum ApplicationArraySize {
213    /// Fixed size array, with the given size
214    Fixed(u64),
215    /// Variable size array, with a single dimension. The maximum size is given
216    VariableLinear(u64),
217    /// Variable size "square" array, with two or more dimensions. All dimensions have the same maximum size
218    /// This maximum size is set in the innermost dimension; it is not set here.
219    /// When the size is set to `VariableSquare`, the array element data type must also be an `ApplicationArrayDataType`
220    VariableSquare,
221    /// Variable size "rectangular" array, with two or more dimensions. Each dimension has its own maximum size.
222    /// The array element data type must also be an `ApplicationArrayDataType`.
223    VariableRectangular(u64),
224    /// Fully flexible variable size array of arrays. The maximum number of elements of each contained array is not necessarily identical
225    /// The array element data type must also be an `ApplicationArrayDataType`.
226    VariableFullyFlexible(u64),
227}
228
229//#########################################################
230
231/// An element in an application array data type
232#[derive(Debug, Clone, PartialEq, Eq, Hash)]
233pub struct ApplicationArrayElement(Element);
234abstraction_element!(ApplicationArrayElement, Element);
235impl IdentifiableAbstractionElement for ApplicationArrayElement {}
236
237impl ApplicationArrayElement {
238    fn new(
239        name: &str,
240        parent: &ApplicationArrayDataType,
241        data_type: &ApplicationDataType,
242    ) -> Result<Self, AutosarAbstractionError> {
243        let application_array_element = parent.element().create_named_sub_element(ElementName::Element, name)?;
244        let application_array_element = Self(application_array_element);
245
246        application_array_element.set_data_type(data_type)?;
247
248        Ok(application_array_element)
249    }
250
251    /// remove the application array element from the model
252    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
253        let opt_data_type = self.data_type();
254
255        AbstractionElement::remove(self, deep)?;
256
257        if deep
258            && let Some(data_type) = opt_data_type
259            && !is_used(data_type.element())
260        {
261            data_type.remove(deep)?;
262        }
263
264        Ok(())
265    }
266
267    /// set the data type of the array element
268    pub fn set_data_type<T: Into<ApplicationDataType> + AbstractionElement>(
269        &self,
270        data_type: &T,
271    ) -> Result<(), AutosarAbstractionError> {
272        let data_type: ApplicationDataType = data_type.clone().into();
273        self.element()
274            .get_or_create_sub_element(ElementName::TypeTref)?
275            .set_reference_target(data_type.element())?;
276        // keep the category synced with the data type, as required by [constr_1152]
277        if let Some(category) = data_type.category() {
278            self.element()
279                .get_or_create_sub_element(ElementName::Category)?
280                .set_character_data(category)?;
281        } else {
282            // remove the category if the data type has no category
283            let _ = self.element().remove_sub_element_kind(ElementName::Category);
284        }
285
286        Ok(())
287    }
288
289    /// get the data type of the array element
290    #[must_use]
291    pub fn data_type(&self) -> Option<ApplicationDataType> {
292        self.element()
293            .get_sub_element(ElementName::TypeTref)?
294            .get_reference_target()
295            .ok()?
296            .try_into()
297            .ok()
298    }
299}
300
301//#########################################################
302
303/// An application record data type
304///
305/// Use [`ArPackage::create_application_record_data_type`] to create a new application record data type.
306#[derive(Debug, Clone, PartialEq, Eq, Hash)]
307pub struct ApplicationRecordDataType(Element);
308abstraction_element!(ApplicationRecordDataType, ApplicationRecordDataType);
309impl IdentifiableAbstractionElement for ApplicationRecordDataType {}
310impl AbstractAutosarDataType for ApplicationRecordDataType {}
311
312impl ApplicationRecordDataType {
313    /// create a new application record data type in the given package
314    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
315        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
316        let application_record_data_type =
317            elements.create_named_sub_element(ElementName::ApplicationRecordDataType, name)?;
318
319        application_record_data_type
320            .create_sub_element(ElementName::Category)?
321            .set_character_data("STRUCTURE")?;
322
323        Ok(Self(application_record_data_type))
324    }
325
326    /// remove the application record data type from the model
327    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
328        for record_element in self.record_elements() {
329            record_element.remove(deep)?;
330        }
331        let ref_parents = get_reference_parents(self.element())?;
332
333        AbstractionElement::remove(self, deep)?;
334
335        remove_helper(ref_parents, deep)
336    }
337
338    /// create a new element in the record data type
339    pub fn create_record_element<T: Into<ApplicationDataType> + Clone>(
340        &self,
341        name: &str,
342        data_type: &T,
343    ) -> Result<ApplicationRecordElement, AutosarAbstractionError> {
344        ApplicationRecordElement::new(name, self, &data_type.clone().into())
345    }
346
347    /// iterate over the record elements of the record data type
348    pub fn record_elements(&self) -> impl Iterator<Item = ApplicationRecordElement> + Send + use<> {
349        self.element()
350            .get_sub_element(ElementName::Elements)
351            .into_iter()
352            .flat_map(|elements| elements.sub_elements())
353            .filter_map(|element| ApplicationRecordElement::try_from(element).ok())
354    }
355}
356
357//#########################################################
358
359/// An element in an application record data type
360#[derive(Debug, Clone, PartialEq, Eq, Hash)]
361pub struct ApplicationRecordElement(Element);
362abstraction_element!(ApplicationRecordElement, ApplicationRecordElement);
363impl IdentifiableAbstractionElement for ApplicationRecordElement {}
364
365impl ApplicationRecordElement {
366    fn new(
367        name: &str,
368        parent: &ApplicationRecordDataType,
369        data_type: &ApplicationDataType,
370    ) -> Result<Self, AutosarAbstractionError> {
371        let application_record_element = parent
372            .element()
373            .get_or_create_sub_element(ElementName::Elements)?
374            .create_named_sub_element(ElementName::ApplicationRecordElement, name)?;
375
376        let application_record_element = Self(application_record_element);
377        application_record_element.set_data_type(data_type)?;
378
379        Ok(application_record_element)
380    }
381
382    /// remove the application record element from the model
383    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
384        let opt_data_type = self.data_type();
385
386        AbstractionElement::remove(self, deep)?;
387
388        if deep
389            && let Some(data_type) = opt_data_type
390            && !is_used(data_type.element())
391        {
392            data_type.remove(deep)?;
393        }
394
395        Ok(())
396    }
397
398    /// set the data type of the record element
399    pub fn set_data_type<T: Into<ApplicationDataType> + AbstractionElement>(
400        &self,
401        data_type: &T,
402    ) -> Result<(), AutosarAbstractionError> {
403        let data_type: ApplicationDataType = data_type.clone().into();
404        self.element()
405            .get_or_create_sub_element(ElementName::TypeTref)?
406            .set_reference_target(data_type.element())?;
407        if let Some(category) = data_type.category() {
408            self.element()
409                .get_or_create_sub_element(ElementName::Category)?
410                .set_character_data(category)?;
411        } else {
412            // remove the category if the data type has no category
413            let _ = self.element().remove_sub_element_kind(ElementName::Category);
414        }
415
416        Ok(())
417    }
418
419    /// get the data type of the record element
420    #[must_use]
421    pub fn data_type(&self) -> Option<ApplicationDataType> {
422        self.element()
423            .get_sub_element(ElementName::TypeTref)?
424            .get_reference_target()
425            .ok()?
426            .try_into()
427            .ok()
428    }
429}
430
431//#########################################################
432
433/// An application primitive data type
434///
435/// Use [`ArPackage::create_application_primitive_data_type`] to create a new application primitive data type.
436#[derive(Debug, Clone, PartialEq, Eq, Hash)]
437pub struct ApplicationPrimitiveDataType(Element);
438abstraction_element!(ApplicationPrimitiveDataType, ApplicationPrimitiveDataType);
439impl IdentifiableAbstractionElement for ApplicationPrimitiveDataType {}
440impl AbstractAutosarDataType for ApplicationPrimitiveDataType {}
441
442impl ApplicationPrimitiveDataType {
443    /// create a new application primitive data type in the given package
444    pub(crate) fn new(
445        name: &str,
446        package: &ArPackage,
447        category: ApplicationPrimitiveCategory,
448        compu_method: Option<&CompuMethod>,
449        unit: Option<&Unit>,
450        data_constraint: Option<&DataConstr>,
451    ) -> Result<Self, AutosarAbstractionError> {
452        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
453        let application_primitive_data_type =
454            elements.create_named_sub_element(ElementName::ApplicationPrimitiveDataType, name)?;
455
456        let application_primitive_data_type = Self(application_primitive_data_type);
457
458        application_primitive_data_type.set_category(category)?;
459        application_primitive_data_type.set_compu_method(compu_method)?;
460        application_primitive_data_type.set_unit(unit)?;
461        application_primitive_data_type.set_data_constraint(data_constraint)?;
462
463        Ok(application_primitive_data_type)
464    }
465
466    /// remove the application primitive data type from the model
467    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
468        let opt_compu_method = self.compu_method();
469        let opt_unit = self.unit();
470        let opt_data_constraint = self.data_constraint();
471        let ref_parents = get_reference_parents(self.element())?;
472
473        AbstractionElement::remove(self, deep)?;
474
475        if deep {
476            if let Some(compu_method) = opt_compu_method
477                && !is_used(compu_method.element())
478            {
479                compu_method.remove(deep)?;
480            }
481            if let Some(unit) = opt_unit
482                && !is_used(unit.element())
483            {
484                unit.remove(deep)?;
485            }
486            if let Some(data_constraint) = opt_data_constraint
487                && !is_used(data_constraint.element())
488            {
489                data_constraint.remove(deep)?;
490            }
491        }
492
493        remove_helper(ref_parents, deep)
494    }
495
496    /// set the category of the primitive data type
497    pub fn set_category(&self, category: ApplicationPrimitiveCategory) -> Result<(), AutosarAbstractionError> {
498        self.element()
499            .get_or_create_sub_element(ElementName::Category)?
500            .set_character_data(category.to_string())?;
501
502        Ok(())
503    }
504
505    /// get the category of the primitive data type
506    #[must_use]
507    pub fn category(&self) -> Option<ApplicationPrimitiveCategory> {
508        self.element()
509            .get_sub_element(ElementName::Category)?
510            .character_data()?
511            .string_value()?
512            .parse()
513            .ok()
514    }
515
516    /// set the compu method of the primitive data type
517    pub fn set_compu_method(&self, compu_method: Option<&CompuMethod>) -> Result<(), AutosarAbstractionError> {
518        if let Some(compu_method) = compu_method {
519            self.element()
520                .get_or_create_sub_element(ElementName::SwDataDefProps)?
521                .get_or_create_sub_element(ElementName::SwDataDefPropsVariants)?
522                .get_or_create_sub_element(ElementName::SwDataDefPropsConditional)?
523                .get_or_create_sub_element(ElementName::CompuMethodRef)?
524                .set_reference_target(compu_method.element())?;
525        } else {
526            let _ = self
527                .element()
528                .get_sub_element(ElementName::SwDataDefProps)
529                .and_then(|sddp| sddp.get_sub_element(ElementName::SwDataDefPropsVariants))
530                .and_then(|sddpv| sddpv.get_sub_element(ElementName::SwDataDefPropsConditional))
531                .and_then(|sddpc| sddpc.remove_sub_element_kind(ElementName::CompuMethodRef).ok());
532        }
533
534        Ok(())
535    }
536
537    /// get the compu method of the primitive data type
538    #[must_use]
539    pub fn compu_method(&self) -> Option<CompuMethod> {
540        self.element()
541            .get_sub_element(ElementName::SwDataDefProps)?
542            .get_sub_element(ElementName::SwDataDefPropsVariants)?
543            .get_sub_element(ElementName::SwDataDefPropsConditional)?
544            .get_sub_element(ElementName::CompuMethodRef)?
545            .get_reference_target()
546            .ok()?
547            .try_into()
548            .ok()
549    }
550
551    /// set the unit of the primitive data type
552    pub fn set_unit(&self, unit: Option<&Unit>) -> Result<(), AutosarAbstractionError> {
553        if let Some(unit) = unit {
554            self.element()
555                .get_or_create_sub_element(ElementName::SwDataDefProps)?
556                .get_or_create_sub_element(ElementName::SwDataDefPropsVariants)?
557                .get_or_create_sub_element(ElementName::SwDataDefPropsConditional)?
558                .get_or_create_sub_element(ElementName::UnitRef)?
559                .set_reference_target(unit.element())?;
560        } else {
561            let _ = self
562                .element()
563                .get_sub_element(ElementName::SwDataDefProps)
564                .and_then(|sddp| sddp.get_sub_element(ElementName::SwDataDefPropsVariants))
565                .and_then(|sddpv| sddpv.get_sub_element(ElementName::SwDataDefPropsConditional))
566                .and_then(|sddpc| sddpc.remove_sub_element_kind(ElementName::UnitRef).ok());
567        }
568
569        Ok(())
570    }
571
572    /// get the unit of the primitive data type
573    #[must_use]
574    pub fn unit(&self) -> Option<Unit> {
575        self.element()
576            .get_sub_element(ElementName::SwDataDefProps)?
577            .get_sub_element(ElementName::SwDataDefPropsVariants)?
578            .get_sub_element(ElementName::SwDataDefPropsConditional)?
579            .get_sub_element(ElementName::UnitRef)?
580            .get_reference_target()
581            .ok()?
582            .try_into()
583            .ok()
584    }
585
586    /// set the data constraint of the primitive data type
587    pub fn set_data_constraint(&self, data_constraint: Option<&DataConstr>) -> Result<(), AutosarAbstractionError> {
588        if let Some(data_constraint) = data_constraint {
589            self.element()
590                .get_or_create_sub_element(ElementName::SwDataDefProps)?
591                .get_or_create_sub_element(ElementName::SwDataDefPropsVariants)?
592                .get_or_create_sub_element(ElementName::SwDataDefPropsConditional)?
593                .get_or_create_sub_element(ElementName::DataConstrRef)?
594                .set_reference_target(data_constraint.element())?;
595        } else {
596            let _ = self
597                .element()
598                .get_sub_element(ElementName::SwDataDefProps)
599                .and_then(|sddp| sddp.get_sub_element(ElementName::SwDataDefPropsVariants))
600                .and_then(|sddpv| sddpv.get_sub_element(ElementName::SwDataDefPropsConditional))
601                .and_then(|sddpc| sddpc.remove_sub_element_kind(ElementName::DataConstrRef).ok());
602        }
603
604        Ok(())
605    }
606
607    /// get the data constraint of the primitive data type
608    #[must_use]
609    pub fn data_constraint(&self) -> Option<DataConstr> {
610        self.element()
611            .get_sub_element(ElementName::SwDataDefProps)?
612            .get_sub_element(ElementName::SwDataDefPropsVariants)?
613            .get_sub_element(ElementName::SwDataDefPropsConditional)?
614            .get_sub_element(ElementName::DataConstrRef)?
615            .get_reference_target()
616            .ok()?
617            .try_into()
618            .ok()
619    }
620}
621
622//#########################################################
623
624/// The category of an application primitive data type
625#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
626pub enum ApplicationPrimitiveCategory {
627    /// Value
628    Value,
629    /// Value block
630    ValBlk,
631    /// String
632    String,
633    /// Boolean
634    Boolean,
635    /// Common axis
636    ComAxis,
637    /// Rescale axis
638    ResAxis,
639    /// Curve - 1D array with an axis
640    Curve,
641    /// Map - 2D array with two axes
642    Map,
643    /// Cuboid - 3D array with three axes
644    Cuboid,
645    /// Cube4 - 4D array with four axes
646    Cube4,
647    /// Cube5 - 5D array with five axes
648    Cube5,
649}
650
651impl std::fmt::Display for ApplicationPrimitiveCategory {
652    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
653        match self {
654            ApplicationPrimitiveCategory::Value => f.write_str("VALUE"),
655            ApplicationPrimitiveCategory::ValBlk => f.write_str("VAL_BLK"),
656            ApplicationPrimitiveCategory::String => f.write_str("STRING"),
657            ApplicationPrimitiveCategory::Boolean => f.write_str("BOOLEAN"),
658            ApplicationPrimitiveCategory::ComAxis => f.write_str("COM_AXIS"),
659            ApplicationPrimitiveCategory::ResAxis => f.write_str("RES_AXIS"),
660            ApplicationPrimitiveCategory::Curve => f.write_str("CURVE"),
661            ApplicationPrimitiveCategory::Map => f.write_str("MAP"),
662            ApplicationPrimitiveCategory::Cuboid => f.write_str("CUBOID"),
663            ApplicationPrimitiveCategory::Cube4 => f.write_str("CUBE_4"),
664            ApplicationPrimitiveCategory::Cube5 => f.write_str("CUBE_5"),
665        }
666    }
667}
668
669impl std::str::FromStr for ApplicationPrimitiveCategory {
670    type Err = AutosarAbstractionError;
671
672    fn from_str(s: &str) -> Result<Self, Self::Err> {
673        match s {
674            "VALUE" => Ok(ApplicationPrimitiveCategory::Value),
675            "VAL_BLK" => Ok(ApplicationPrimitiveCategory::ValBlk),
676            "STRING" => Ok(ApplicationPrimitiveCategory::String),
677            "BOOLEAN" => Ok(ApplicationPrimitiveCategory::Boolean),
678            "COM_AXIS" => Ok(ApplicationPrimitiveCategory::ComAxis),
679            "RES_AXIS" => Ok(ApplicationPrimitiveCategory::ResAxis),
680            "CURVE" => Ok(ApplicationPrimitiveCategory::Curve),
681            "MAP" => Ok(ApplicationPrimitiveCategory::Map),
682            "CUBOID" => Ok(ApplicationPrimitiveCategory::Cuboid),
683            "CUBE_4" => Ok(ApplicationPrimitiveCategory::Cube4),
684            "CUBE_5" => Ok(ApplicationPrimitiveCategory::Cube5),
685            _ => Err(AutosarAbstractionError::ValueConversionError {
686                value: s.to_string(),
687                dest: "ApplicationPrimitiveCategory".to_string(),
688            }),
689        }
690    }
691}
692
693//#########################################################
694
695/// A wrapper for all application data types
696#[derive(Debug, Clone, PartialEq, Eq, Hash)]
697pub enum ApplicationDataType {
698    /// An array data type
699    Array(ApplicationArrayDataType),
700    /// A record data type
701    Record(ApplicationRecordDataType),
702    /// A primitive data type
703    Primitive(ApplicationPrimitiveDataType),
704}
705
706impl AbstractionElement for ApplicationDataType {
707    fn element(&self) -> &Element {
708        match self {
709            ApplicationDataType::Array(e) => e.element(),
710            ApplicationDataType::Record(e) => e.element(),
711            ApplicationDataType::Primitive(e) => e.element(),
712        }
713    }
714}
715
716impl TryFrom<Element> for ApplicationDataType {
717    type Error = AutosarAbstractionError;
718
719    fn try_from(element: Element) -> Result<Self, Self::Error> {
720        match element.element_name() {
721            ElementName::ApplicationArrayDataType => Ok(ApplicationDataType::Array(element.try_into()?)),
722            ElementName::ApplicationRecordDataType => Ok(ApplicationDataType::Record(element.try_into()?)),
723            ElementName::ApplicationPrimitiveDataType => Ok(ApplicationDataType::Primitive(element.try_into()?)),
724            _ => Err(AutosarAbstractionError::ConversionError {
725                element,
726                dest: "ApplicationDataType".to_string(),
727            }),
728        }
729    }
730}
731
732impl IdentifiableAbstractionElement for ApplicationDataType {}
733
734impl From<ApplicationPrimitiveDataType> for ApplicationDataType {
735    fn from(val: ApplicationPrimitiveDataType) -> Self {
736        ApplicationDataType::Primitive(val)
737    }
738}
739
740impl From<ApplicationRecordDataType> for ApplicationDataType {
741    fn from(val: ApplicationRecordDataType) -> Self {
742        ApplicationDataType::Record(val)
743    }
744}
745
746impl From<ApplicationArrayDataType> for ApplicationDataType {
747    fn from(val: ApplicationArrayDataType) -> Self {
748        ApplicationDataType::Array(val)
749    }
750}
751
752impl ApplicationDataType {
753    /// get the category of the data type
754    #[must_use]
755    pub fn category(&self) -> Option<String> {
756        self.element()
757            .get_sub_element(ElementName::Category)?
758            .character_data()?
759            .string_value()
760    }
761
762    /// remove the application record data type from the model
763    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
764        match self {
765            ApplicationDataType::Array(e) => e.remove(deep),
766            ApplicationDataType::Record(e) => e.remove(deep),
767            ApplicationDataType::Primitive(e) => e.remove(deep),
768        }
769    }
770}
771
772//#########################################################
773
774fn remove_helper(ref_parents: Vec<(Element, Element)>, deep: bool) -> Result<(), AutosarAbstractionError> {
775    for (named_parent, parent) in ref_parents {
776        match named_parent.element_name() {
777            ElementName::Element => {
778                if let Ok(app_data_type_ref) = ApplicationArrayElement::try_from(named_parent) {
779                    app_data_type_ref.remove(deep)?;
780                }
781            }
782            ElementName::ApplicationRecordElement => {
783                if let Ok(app_data_type_ref) = ApplicationRecordElement::try_from(named_parent) {
784                    app_data_type_ref.remove(deep)?;
785                }
786            }
787            ElementName::DataTypeMappingSet => {
788                // don't remove the whole mapping set, only the mapping
789                if let Ok(data_type_map) = DataTypeMap::try_from(parent) {
790                    data_type_map.remove(deep)?;
791                }
792            }
793            ElementName::ParameterDataPrototype => {
794                if let Ok(param_prototype) = ParameterDataPrototype::try_from(named_parent) {
795                    param_prototype.remove(deep)?;
796                }
797            }
798            ElementName::VariableDataPrototype => {
799                if let Ok(var_data_prototype) = VariableDataPrototype::try_from(parent) {
800                    var_data_prototype.remove(deep)?;
801                }
802            }
803            ElementName::ArgumentDataPrototype => {
804                if let Ok(arg_data_prototype) = ArgumentDataPrototype::try_from(parent) {
805                    arg_data_prototype.remove(deep)?;
806                }
807            }
808            _ => {}
809        }
810    }
811
812    Ok(())
813}
814
815//#########################################################
816
817#[cfg(test)]
818mod tests {
819    use super::*;
820    use crate::{
821        AutosarModelAbstraction,
822        datatype::{BaseTypeEncoding, ImplementationDataTypeSettings},
823        software_component::ArgumentDirection,
824    };
825    use autosar_data::AutosarVersion;
826    use datatype::{CompuMethodContent, CompuMethodLinearContent};
827
828    #[test]
829    fn test_application_array_data_type() {
830        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
831        let package = model.get_or_create_package("/DataTypes").unwrap();
832        let element_type = ApplicationPrimitiveDataType::new(
833            "Element",
834            &package,
835            ApplicationPrimitiveCategory::Value,
836            None,
837            None,
838            None,
839        )
840        .unwrap();
841        let array_data_type =
842            ApplicationArrayDataType::new("Array", &package, &element_type, ApplicationArraySize::Fixed(10)).unwrap();
843        let array_type_2 =
844            ApplicationArrayDataType::new("Array2", &package, &element_type, ApplicationArraySize::Fixed(100)).unwrap();
845
846        assert_eq!(
847            array_data_type.array_element().unwrap().data_type().unwrap(),
848            ApplicationDataType::Primitive(element_type)
849        );
850        assert_eq!(array_data_type.size().unwrap(), ApplicationArraySize::Fixed(10));
851
852        array_data_type
853            .set_size(ApplicationArraySize::VariableLinear(100))
854            .unwrap();
855        assert_eq!(
856            array_data_type.size().unwrap(),
857            ApplicationArraySize::VariableLinear(100)
858        );
859
860        // the inner type must be an array type for the following size settings
861        let result = array_data_type.set_size(ApplicationArraySize::VariableSquare);
862        assert!(result.is_err());
863        let result = array_data_type.set_size(ApplicationArraySize::VariableRectangular(100));
864        assert!(result.is_err());
865        let result = array_data_type.set_size(ApplicationArraySize::VariableFullyFlexible(100));
866        assert!(result.is_err());
867
868        // reassign the array element type to an array type
869        array_data_type
870            .array_element()
871            .unwrap()
872            .set_data_type(&array_type_2)
873            .unwrap();
874        array_data_type.set_size(ApplicationArraySize::VariableSquare).unwrap();
875        assert_eq!(array_data_type.size().unwrap(), ApplicationArraySize::VariableSquare);
876        array_data_type
877            .set_size(ApplicationArraySize::VariableRectangular(100))
878            .unwrap();
879        assert_eq!(
880            array_data_type.size().unwrap(),
881            ApplicationArraySize::VariableRectangular(100)
882        );
883        array_data_type
884            .set_size(ApplicationArraySize::VariableFullyFlexible(100))
885            .unwrap();
886        assert_eq!(
887            array_data_type.size().unwrap(),
888            ApplicationArraySize::VariableFullyFlexible(100)
889        );
890
891        // reassign the array element type
892        let element_type_2 = ApplicationPrimitiveDataType::new(
893            "Element2",
894            &package,
895            ApplicationPrimitiveCategory::Value,
896            None,
897            None,
898            None,
899        )
900        .unwrap();
901        let array_element = array_data_type.array_element().unwrap();
902        array_element.set_data_type(&element_type_2).unwrap();
903        assert_eq!(
904            array_element.data_type().unwrap(),
905            ApplicationDataType::Primitive(element_type_2)
906        );
907    }
908
909    #[test]
910    fn test_application_record_data_type() {
911        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
912        let package = model.get_or_create_package("/DataTypes").unwrap();
913        let record_data_type = ApplicationRecordDataType::new("Record", &package).unwrap();
914        let element_type = ApplicationPrimitiveDataType::new(
915            "Element",
916            &package,
917            ApplicationPrimitiveCategory::Value,
918            None,
919            None,
920            None,
921        )
922        .unwrap();
923        let record_element = record_data_type
924            .create_record_element("Element", &element_type)
925            .unwrap();
926
927        assert_eq!(
928            record_element.data_type().unwrap(),
929            ApplicationDataType::Primitive(element_type)
930        );
931        assert_eq!(record_data_type.record_elements().next().unwrap(), record_element);
932    }
933
934    #[test]
935    fn test_application_primitive_data_type() {
936        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
937        let package = model.get_or_create_package("/DataTypes").unwrap();
938        let compu_method = CompuMethod::new(
939            "CompuMethod",
940            &package,
941            CompuMethodContent::Linear(CompuMethodLinearContent {
942                direction: datatype::CompuScaleDirection::IntToPhys,
943                offset: 0.0,
944                factor: 100.0,
945                divisor: 1.0,
946                lower_limit: None,
947                upper_limit: None,
948            }),
949        )
950        .unwrap();
951        let unit = Unit::new("Unit", &package, Some("Unit name")).unwrap();
952        let data_constraint = DataConstr::new("DataConstraint", &package).unwrap();
953        let primitive_data_type = ApplicationPrimitiveDataType::new(
954            "Primitive",
955            &package,
956            ApplicationPrimitiveCategory::Value,
957            Some(&compu_method),
958            Some(&unit),
959            Some(&data_constraint),
960        )
961        .unwrap();
962
963        assert_eq!(
964            primitive_data_type.category().unwrap(),
965            ApplicationPrimitiveCategory::Value
966        );
967        assert_eq!(primitive_data_type.compu_method().unwrap(), compu_method);
968        assert_eq!(primitive_data_type.unit().unwrap(), unit);
969        assert_eq!(primitive_data_type.data_constraint().unwrap(), data_constraint);
970
971        primitive_data_type
972            .set_category(ApplicationPrimitiveCategory::Boolean)
973            .unwrap();
974        assert_eq!(
975            primitive_data_type.category().unwrap(),
976            ApplicationPrimitiveCategory::Boolean
977        );
978        primitive_data_type.set_compu_method(None).unwrap();
979        assert!(primitive_data_type.compu_method().is_none());
980        primitive_data_type.set_unit(None).unwrap();
981        assert!(primitive_data_type.unit().is_none());
982        primitive_data_type.set_data_constraint(None).unwrap();
983        assert!(primitive_data_type.data_constraint().is_none());
984    }
985
986    #[test]
987    fn test_application_data_type() {
988        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
989        let package = model.get_or_create_package("/DataTypes").unwrap();
990        let element_type = ApplicationPrimitiveDataType::new(
991            "Element",
992            &package,
993            ApplicationPrimitiveCategory::Value,
994            None,
995            None,
996            None,
997        )
998        .unwrap();
999        let array_data_type =
1000            ApplicationArrayDataType::new("Array", &package, &element_type, ApplicationArraySize::Fixed(10)).unwrap();
1001        let record_data_type = ApplicationRecordDataType::new("Record", &package).unwrap();
1002        let primitive_data_type = ApplicationPrimitiveDataType::new(
1003            "Primitive",
1004            &package,
1005            ApplicationPrimitiveCategory::Value,
1006            None,
1007            None,
1008            None,
1009        )
1010        .unwrap();
1011
1012        let data_type: ApplicationDataType = array_data_type.clone().into();
1013        assert_eq!(data_type, ApplicationDataType::Array(array_data_type.clone()));
1014        assert_eq!(data_type.category().unwrap(), "ARRAY");
1015
1016        let data_type: ApplicationDataType = record_data_type.clone().into();
1017        assert_eq!(data_type, ApplicationDataType::Record(record_data_type.clone()));
1018        assert_eq!(data_type.category().unwrap(), "STRUCTURE");
1019
1020        let data_type: ApplicationDataType = primitive_data_type.clone().into();
1021        assert_eq!(data_type, ApplicationDataType::Primitive(primitive_data_type.clone()));
1022        assert_eq!(data_type.category().unwrap(), "VALUE");
1023
1024        let result = ApplicationDataType::try_from(package.element().clone());
1025        assert!(result.is_err());
1026    }
1027
1028    #[test]
1029    fn remove() {
1030        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1031        let package = model.get_or_create_package("/DataTypes").unwrap();
1032        let element_type = package
1033            .create_application_primitive_data_type(
1034                "AppPrimitive",
1035                ApplicationPrimitiveCategory::Value,
1036                None,
1037                None,
1038                None,
1039            )
1040            .unwrap();
1041        let array_data_type = package
1042            .create_application_array_data_type("AppArray", &element_type, ApplicationArraySize::Fixed(10))
1043            .unwrap();
1044
1045        // create a matching implementation data type
1046        let base_type = package
1047            .create_sw_base_type("uint8", 8, BaseTypeEncoding::TwosComplement, None, None, Some("uint8"))
1048            .unwrap();
1049        let impl_array = package
1050            .create_implementation_data_type(&ImplementationDataTypeSettings::Array {
1051                name: "ImplArray".to_string(),
1052                length: 10,
1053                element_type: Box::new(ImplementationDataTypeSettings::Value {
1054                    name: "ImplPrimitive".to_string(),
1055                    base_type,
1056                    compu_method: None,
1057                    data_constraint: None,
1058                }),
1059            })
1060            .unwrap();
1061
1062        // create a data type mapping that maps the implementation array to the application array
1063        let data_type_mapping_set = package.create_data_type_mapping_set("DataTypeMappingSet").unwrap();
1064        data_type_mapping_set
1065            .create_data_type_map(&impl_array, &array_data_type)
1066            .unwrap();
1067
1068        // create a SenderReceiverInterface that uses the application array data type
1069        let sr_interface = package.create_sender_receiver_interface("SRInterface").unwrap();
1070        let _vdp = sr_interface.create_data_element("VDP", &array_data_type).unwrap();
1071        // create a client-server interface that uses the application array data type
1072        let cs_interface = package.create_client_server_interface("CSInterface").unwrap();
1073        let cso = cs_interface.create_operation("ADP").unwrap();
1074        let _adp = cso
1075            .create_argument("ADP", &array_data_type, ArgumentDirection::In)
1076            .unwrap();
1077
1078        // create an application record data type that uses the application array data type
1079        let record_data_type = package.create_application_record_data_type("AppRecord").unwrap();
1080        let _record_element = record_data_type
1081            .create_record_element("RecordElement", &array_data_type)
1082            .unwrap();
1083
1084        // remove the application array data type deeply
1085        array_data_type.remove(true).unwrap();
1086
1087        // check that all related elements have been removed
1088        assert_eq!(data_type_mapping_set.data_type_maps().count(), 0);
1089        assert_eq!(sr_interface.data_elements().count(), 0);
1090        assert_eq!(cso.arguments().count(), 0);
1091        assert_eq!(record_data_type.record_elements().count(), 0);
1092    }
1093}