autosar_data_abstraction/datatype/
applicationtype.rs

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