autosar_data_abstraction/datatype/
implementationtype.rs

1use crate::{
2    AbstractionElement, ArPackage, AutosarAbstractionError, Element, EnumItem, 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;
9use datatype::{AbstractAutosarDataType, CompuMethod, DataConstr, SwBaseType};
10use std::fmt::Display;
11
12/// Interface for implementation data types, which provides default implementations for common operations
13pub trait AbstractImplementationDataType: IdentifiableAbstractionElement {
14    /// get the category of this implementation data type
15    fn category(&self) -> Option<ImplementationDataCategory> {
16        self.element()
17            .get_sub_element(ElementName::Category)?
18            .character_data()?
19            .string_value()?
20            .as_str()
21            .try_into()
22            .ok()
23    }
24
25    /// create an iterator over the sub-elements of this implementation data type
26    fn sub_elements(&self) -> impl Iterator<Item = ImplementationDataTypeElement> + Send + use<Self> {
27        self.element()
28            .get_sub_element(ElementName::SubElements)
29            .into_iter()
30            .flat_map(|elem| elem.sub_elements())
31            .filter_map(|elem| ImplementationDataTypeElement::try_from(elem).ok())
32    }
33
34    /// get the `SwBaseType` of this implementation data type [category: VALUE]
35    fn base_type(&self) -> Option<SwBaseType> {
36        let category = self.category()?;
37        if category != ImplementationDataCategory::Value {
38            return None;
39        }
40        self.element()
41            .get_sub_element(ElementName::SwDataDefProps)?
42            .get_sub_element(ElementName::SwDataDefPropsVariants)?
43            .get_sub_element(ElementName::SwDataDefPropsConditional)?
44            .get_sub_element(ElementName::BaseTypeRef)?
45            .get_reference_target()
46            .ok()?
47            .try_into()
48            .ok()
49    }
50
51    /// get the `CompuMethod` of this implementation data type [category: VALUE, `TYPE_REFERENCE`]
52    fn compu_method(&self) -> Option<CompuMethod> {
53        let category = self.category()?;
54        if category != ImplementationDataCategory::Value && category != ImplementationDataCategory::TypeReference {
55            return None;
56        }
57        self.element()
58            .get_sub_element(ElementName::SwDataDefProps)?
59            .get_sub_element(ElementName::SwDataDefPropsVariants)?
60            .get_sub_element(ElementName::SwDataDefPropsConditional)?
61            .get_sub_element(ElementName::CompuMethodRef)
62            .and_then(|cmref| cmref.get_reference_target().ok())
63            .and_then(|refelem| refelem.try_into().ok())
64    }
65
66    /// get the `DataConstr` of this implementation data type [category: VALUE, `TYPE_REFERENCE`]
67    fn data_constraint(&self) -> Option<DataConstr> {
68        let category = self.category()?;
69        if category != ImplementationDataCategory::Value && category != ImplementationDataCategory::TypeReference {
70            return None;
71        }
72        self.element()
73            .get_sub_element(ElementName::SwDataDefProps)?
74            .get_sub_element(ElementName::SwDataDefPropsVariants)?
75            .get_sub_element(ElementName::SwDataDefPropsConditional)?
76            .get_sub_element(ElementName::DataConstrRef)
77            .and_then(|dcref| dcref.get_reference_target().ok())
78            .and_then(|refelem| refelem.try_into().ok())
79    }
80
81    /// get the referenced implementation data type [category: `TYPE_REFERENCE`]
82    fn referenced_type(&self) -> Option<ImplementationDataType> {
83        let category = self.category()?;
84        if category != ImplementationDataCategory::TypeReference {
85            return None;
86        }
87        self.element()
88            .get_sub_element(ElementName::SwDataDefProps)?
89            .get_sub_element(ElementName::SwDataDefPropsVariants)?
90            .get_sub_element(ElementName::SwDataDefPropsConditional)?
91            .get_sub_element(ElementName::ImplementationDataTypeRef)?
92            .get_reference_target()
93            .ok()?
94            .try_into()
95            .ok()
96    }
97
98    /// get the array size of this implementation data type [category: ARRAY]
99    fn array_size(&self) -> Option<u32> {
100        let category = self.category()?;
101        if category != ImplementationDataCategory::Array {
102            return None;
103        }
104        self.sub_elements()
105            .next()?
106            .element()
107            .get_sub_element(ElementName::ArraySize)?
108            .character_data()?
109            .parse_integer()
110    }
111
112    /// get the data pointer target of this implementation data type [[category: `DATA_REFERENCE`]]
113    fn data_pointer_target(&self) -> Option<DataPointerTarget> {
114        let category = self.category()?;
115        if category != ImplementationDataCategory::DataReference {
116            return None;
117        }
118        let sw_pointer_target_props = self
119            .element()
120            .get_sub_element(ElementName::SwDataDefProps)?
121            .get_sub_element(ElementName::SwDataDefPropsVariants)?
122            .get_sub_element(ElementName::SwDataDefPropsConditional)?
123            .get_sub_element(ElementName::SwPointerTargetProps)?
124            .get_sub_element(ElementName::SwDataDefProps)?
125            .get_sub_element(ElementName::SwDataDefPropsVariants)?
126            .get_sub_element(ElementName::SwDataDefPropsConditional)?;
127        if let Some(base_type) = sw_pointer_target_props
128            .get_sub_element(ElementName::BaseTypeRef)
129            .and_then(|elem| elem.get_reference_target().ok())
130        {
131            Some(DataPointerTarget::BaseType(base_type.try_into().ok()?))
132        } else if let Some(impl_data_type) = sw_pointer_target_props
133            .get_sub_element(ElementName::ImplementationDataTypeRef)
134            .and_then(|elem| elem.get_reference_target().ok())
135        {
136            Some(DataPointerTarget::ImplementationDataType(
137                impl_data_type.try_into().ok()?,
138            ))
139        } else {
140            None
141        }
142    }
143
144    /// apply the settings to this implementation data type
145    ///
146    /// Calling this method completely replaces the existing settings of the implementation data type,
147    /// deleting existing sub-elements and creating new ones according to the settings
148    fn apply_settings(&self, settings: &ImplementationDataTypeSettings) -> Result<(), AutosarAbstractionError> {
149        self.set_name(settings.name())?;
150        apply_impl_data_settings(self.element(), settings)
151    }
152
153    /// get the settings of this implementation data type
154    fn settings(&self) -> Option<ImplementationDataTypeSettings> {
155        let category = self.category()?;
156        match category {
157            ImplementationDataCategory::Value => Some(ImplementationDataTypeSettings::Value {
158                name: self.name()?,
159                base_type: self.base_type()?,
160                compu_method: self.compu_method(),
161                data_constraint: self.data_constraint(),
162            }),
163            ImplementationDataCategory::Array => {
164                let element_settings = self.sub_elements().next()?.settings()?;
165                Some(ImplementationDataTypeSettings::Array {
166                    name: self.name()?,
167                    length: self.array_size()?,
168                    element_type: Box::new(element_settings),
169                })
170            }
171            ImplementationDataCategory::Structure => {
172                let elements = self
173                    .sub_elements()
174                    .map(|elem| elem.settings())
175                    .collect::<Option<Vec<_>>>()?;
176                Some(ImplementationDataTypeSettings::Structure {
177                    name: self.name()?,
178                    elements,
179                })
180            }
181            ImplementationDataCategory::Union => {
182                let elements = self
183                    .sub_elements()
184                    .map(|elem| elem.settings())
185                    .collect::<Option<Vec<_>>>()?;
186                Some(ImplementationDataTypeSettings::Union {
187                    name: self.name()?,
188                    elements,
189                })
190            }
191            ImplementationDataCategory::DataReference => {
192                let sw_pointer_target_props = self
193                    .element()
194                    .get_sub_element(ElementName::SwDataDefProps)?
195                    .get_sub_element(ElementName::SwDataDefPropsVariants)?
196                    .get_sub_element(ElementName::SwDataDefPropsConditional)?
197                    .get_sub_element(ElementName::SwPointerTargetProps)?
198                    .get_sub_element(ElementName::SwDataDefProps)?
199                    .get_sub_element(ElementName::SwDataDefPropsVariants)?
200                    .get_sub_element(ElementName::SwDataDefPropsConditional)?;
201                let target = if let Some(base_type) = sw_pointer_target_props
202                    .get_sub_element(ElementName::BaseTypeRef)
203                    .and_then(|elem| elem.get_reference_target().ok())
204                {
205                    DataPointerTarget::BaseType(base_type.try_into().ok()?)
206                } else if let Some(impl_data_type) = sw_pointer_target_props
207                    .get_sub_element(ElementName::ImplementationDataTypeRef)
208                    .and_then(|elem| elem.get_reference_target().ok())
209                {
210                    DataPointerTarget::ImplementationDataType(impl_data_type.try_into().ok()?)
211                } else {
212                    return None;
213                };
214                Some(ImplementationDataTypeSettings::DataReference {
215                    name: self.name()?,
216                    target,
217                })
218            }
219            ImplementationDataCategory::FunctionReference => {
220                Some(ImplementationDataTypeSettings::FunctionReference { name: self.name()? })
221            }
222            ImplementationDataCategory::TypeReference => Some(ImplementationDataTypeSettings::TypeReference {
223                name: self.name()?,
224                reftype: self.referenced_type()?,
225                compu_method: self.compu_method(),
226                data_constraint: self.data_constraint(),
227            }),
228        }
229    }
230}
231
232//#########################################################
233
234/// An implementation data type; specifics are determined by the category
235///
236/// Use [`ArPackage::create_implementation_data_type`] to create a new implementation data type
237#[derive(Debug, Clone, PartialEq, Eq, Hash)]
238pub struct ImplementationDataType(Element);
239abstraction_element!(ImplementationDataType, ImplementationDataType);
240impl IdentifiableAbstractionElement for ImplementationDataType {}
241impl AbstractAutosarDataType for ImplementationDataType {}
242impl AbstractImplementationDataType for ImplementationDataType {}
243
244impl ImplementationDataType {
245    /// create a new implementation data type from an `ImplementationDataTypeSettings` structure
246    pub(crate) fn new(
247        package: &ArPackage,
248        settings: &ImplementationDataTypeSettings,
249    ) -> Result<Self, AutosarAbstractionError> {
250        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
251        let implementation_data_type =
252            elements.create_named_sub_element(ElementName::ImplementationDataType, settings.name())?;
253        let implementation_data_type = Self(implementation_data_type);
254        implementation_data_type.apply_settings(settings)?;
255
256        Ok(implementation_data_type)
257    }
258
259    /// remove this implementation data type from the model
260    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
261        let opt_compu_method = self.compu_method();
262        let opt_data_constraint = self.data_constraint();
263        let opt_base_type = self.base_type();
264        let opt_referenced_type = self.referenced_type();
265
266        for element in self.sub_elements() {
267            element.remove(deep)?;
268        }
269
270        let ref_parents = get_reference_parents(self.element())?;
271
272        AbstractionElement::remove(self, deep)?;
273
274        for (named_parent, parent) in ref_parents {
275            match named_parent.element_name() {
276                ElementName::ImplementationDataType => {
277                    if let Ok(impl_data_type) = ImplementationDataType::try_from(named_parent) {
278                        impl_data_type.remove(deep)?;
279                    }
280                }
281                ElementName::ImplementationDataTypeElement => {
282                    if let Ok(impl_data_type_element) = ImplementationDataTypeElement::try_from(named_parent) {
283                        impl_data_type_element.remove(deep)?;
284                    }
285                }
286                ElementName::DataTypeMappingSet => {
287                    if let Ok(datatype_map) = DataTypeMap::try_from(parent) {
288                        datatype_map.remove(deep)?;
289                    }
290                }
291                ElementName::ParameterDataPrototype => {
292                    if let Ok(param_prototype) = ParameterDataPrototype::try_from(named_parent) {
293                        param_prototype.remove(deep)?;
294                    }
295                }
296                ElementName::VariableDataPrototype => {
297                    if let Ok(var_prototype) = VariableDataPrototype::try_from(named_parent) {
298                        var_prototype.remove(deep)?;
299                    }
300                }
301                ElementName::ArgumentDataPrototype => {
302                    if let Ok(arg_prototype) = ArgumentDataPrototype::try_from(named_parent) {
303                        arg_prototype.remove(deep)?;
304                    }
305                }
306                _ => {}
307            }
308        }
309
310        if deep {
311            if let Some(compu_method) = opt_compu_method
312                && !is_used(compu_method.element())
313            {
314                compu_method.remove(deep)?;
315            }
316            if let Some(data_constraint) = opt_data_constraint
317                && !is_used(data_constraint.element())
318            {
319                data_constraint.remove(deep)?;
320            }
321            if let Some(base_type) = opt_base_type
322                && !is_used(base_type.element())
323            {
324                base_type.remove(deep)?;
325            }
326            if let Some(referenced_type) = opt_referenced_type
327                && !is_used(referenced_type.element())
328            {
329                referenced_type.remove(deep)?;
330            }
331        }
332        Ok(())
333    }
334}
335
336//#########################################################
337
338/// An element of an implementation data type
339#[derive(Debug, Clone, PartialEq, Eq, Hash)]
340pub struct ImplementationDataTypeElement(Element);
341abstraction_element!(ImplementationDataTypeElement, ImplementationDataTypeElement);
342impl IdentifiableAbstractionElement for ImplementationDataTypeElement {}
343impl AbstractImplementationDataType for ImplementationDataTypeElement {}
344
345impl ImplementationDataTypeElement {
346    pub(crate) fn new(
347        parent: &Element,
348        settings: &ImplementationDataTypeSettings,
349    ) -> Result<Self, AutosarAbstractionError> {
350        let implementation_data_type_element =
351            parent.create_named_sub_element(ElementName::ImplementationDataTypeElement, settings.name())?;
352        let implementation_data_type_element = Self(implementation_data_type_element);
353        implementation_data_type_element.apply_settings(settings)?;
354
355        Ok(implementation_data_type_element)
356    }
357
358    /// remove this implementation data type element from the model
359    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
360        let opt_compu_method = self.compu_method();
361        let opt_data_constraint = self.data_constraint();
362        let opt_base_type = self.base_type();
363        let opt_referenced_type = self.referenced_type();
364
365        for element in self.sub_elements() {
366            element.remove(deep)?;
367        }
368
369        AbstractionElement::remove(self, deep)?;
370
371        if deep {
372            if let Some(compu_method) = opt_compu_method
373                && !is_used(compu_method.element())
374            {
375                compu_method.remove(deep)?;
376            }
377            if let Some(data_constraint) = opt_data_constraint
378                && !is_used(data_constraint.element())
379            {
380                data_constraint.remove(deep)?;
381            }
382            if let Some(base_type) = opt_base_type
383                && !is_used(base_type.element())
384            {
385                base_type.remove(deep)?;
386            }
387            if let Some(referenced_type) = opt_referenced_type
388                && !is_used(referenced_type.element())
389            {
390                referenced_type.remove(deep)?;
391            }
392        }
393
394        Ok(())
395    }
396}
397
398//#########################################################
399
400fn apply_impl_data_settings(
401    element: &Element,
402    settings: &ImplementationDataTypeSettings,
403) -> Result<(), AutosarAbstractionError> {
404    // remove the existing sub-elements of the implementation data type
405    let _ = element.remove_sub_element_kind(ElementName::Category);
406    let _ = element.remove_sub_element_kind(ElementName::SubElements);
407    let _ = element.remove_sub_element_kind(ElementName::SwDataDefProps);
408    // DynamicArraySizeProfile is part of the definition of variable-sized arrays, which are not supported (yet?)
409    let _ = element.remove_sub_element_kind(ElementName::DynamicArraySizeProfile);
410
411    match settings {
412        ImplementationDataTypeSettings::Value {
413            base_type,
414            compu_method,
415            data_constraint,
416            ..
417        } => {
418            element
419                .create_sub_element(ElementName::Category)?
420                .set_character_data("VALUE")?;
421            let sw_data_def_props = element
422                .create_sub_element(ElementName::SwDataDefProps)?
423                .create_sub_element(ElementName::SwDataDefPropsVariants)?
424                .create_sub_element(ElementName::SwDataDefPropsConditional)?;
425            sw_data_def_props
426                .create_sub_element(ElementName::BaseTypeRef)?
427                .set_reference_target(base_type.element())?;
428            if let Some(compu_method) = compu_method {
429                sw_data_def_props
430                    .create_sub_element(ElementName::CompuMethodRef)?
431                    .set_reference_target(compu_method.element())?;
432            }
433            if let Some(data_constraint) = data_constraint {
434                sw_data_def_props
435                    .create_sub_element(ElementName::DataConstrRef)?
436                    .set_reference_target(data_constraint.element())?;
437            }
438        }
439        ImplementationDataTypeSettings::Array {
440            length, element_type, ..
441        } => {
442            element
443                .create_sub_element(ElementName::Category)?
444                .set_character_data("ARRAY")?;
445            let sub_elements = element.get_or_create_sub_element(ElementName::SubElements)?;
446            let array_element = ImplementationDataTypeElement::new(&sub_elements, element_type)?;
447            array_element
448                .element()
449                .create_sub_element(ElementName::ArraySize)?
450                .set_character_data(u64::from(*length))?;
451            array_element
452                .element()
453                .create_sub_element(ElementName::ArraySizeSemantics)?
454                .set_character_data(EnumItem::FixedSize)?;
455        }
456        ImplementationDataTypeSettings::Structure { elements, .. } => {
457            element
458                .create_sub_element(ElementName::Category)?
459                .set_character_data("STRUCTURE")?;
460            let sub_elements = element.get_or_create_sub_element(ElementName::SubElements)?;
461            for sub_element in elements {
462                ImplementationDataTypeElement::new(&sub_elements, sub_element)?;
463            }
464        }
465        ImplementationDataTypeSettings::Union { elements, .. } => {
466            element
467                .create_sub_element(ElementName::Category)?
468                .set_character_data("UNION")?;
469            let sub_elements = element.get_or_create_sub_element(ElementName::SubElements)?;
470            for sub_element in elements {
471                ImplementationDataTypeElement::new(&sub_elements, sub_element)?;
472            }
473        }
474        ImplementationDataTypeSettings::DataReference { target, .. } => {
475            element
476                .create_sub_element(ElementName::Category)?
477                .set_character_data("DATA_REFERENCE")?;
478            let pointer_props = element
479                .create_sub_element(ElementName::SwDataDefProps)?
480                .create_sub_element(ElementName::SwDataDefPropsVariants)?
481                .create_sub_element(ElementName::SwDataDefPropsConditional)?
482                .create_sub_element(ElementName::SwPointerTargetProps)?;
483            let contained_props = pointer_props
484                .create_sub_element(ElementName::SwDataDefProps)?
485                .create_sub_element(ElementName::SwDataDefPropsVariants)?
486                .create_sub_element(ElementName::SwDataDefPropsConditional)?;
487            match target {
488                DataPointerTarget::BaseType(base_type) => {
489                    contained_props
490                        .create_sub_element(ElementName::BaseTypeRef)?
491                        .set_reference_target(base_type.element())?;
492                    pointer_props
493                        .create_sub_element(ElementName::TargetCategory)
494                        .and_then(|elem| elem.set_character_data("VALUE"))?;
495                }
496                DataPointerTarget::ImplementationDataType(impl_data_type) => {
497                    contained_props
498                        .create_sub_element(ElementName::ImplementationDataTypeRef)?
499                        .set_reference_target(impl_data_type.element())?;
500                    let target_category = impl_data_type
501                        .category()
502                        .as_ref()
503                        .map(|item| item.to_string())
504                        .unwrap_or("VALUE".to_string());
505                    pointer_props
506                        .create_sub_element(ElementName::TargetCategory)?
507                        .set_character_data(target_category)?;
508                }
509            }
510        }
511        ImplementationDataTypeSettings::FunctionReference { .. } => {
512            element
513                .create_sub_element(ElementName::Category)?
514                .set_character_data("FUNCTION_REFERENCE")?;
515        }
516        ImplementationDataTypeSettings::TypeReference {
517            reftype,
518            compu_method,
519            data_constraint,
520            ..
521        } => {
522            element
523                .create_sub_element(ElementName::Category)?
524                .set_character_data("TYPE_REFERENCE")?;
525            let sw_data_def_props = element
526                .create_sub_element(ElementName::SwDataDefProps)?
527                .create_sub_element(ElementName::SwDataDefPropsVariants)?
528                .create_sub_element(ElementName::SwDataDefPropsConditional)?;
529            sw_data_def_props
530                .create_sub_element(ElementName::ImplementationDataTypeRef)?
531                .set_reference_target(reftype.element())?;
532            if let Some(compu_method) = compu_method {
533                sw_data_def_props
534                    .create_sub_element(ElementName::CompuMethodRef)?
535                    .set_reference_target(compu_method.element())?;
536            }
537            if let Some(data_constraint) = data_constraint {
538                sw_data_def_props
539                    .create_sub_element(ElementName::DataConstrRef)?
540                    .set_reference_target(data_constraint.element())?;
541            }
542        }
543    }
544
545    Ok(())
546}
547
548//#########################################################
549
550/// The category of an implementation data type
551#[derive(Debug, Clone, PartialEq, Eq, Hash)]
552pub enum ImplementationDataCategory {
553    /// A simple value
554    Value,
555    /// a pointer to data
556    DataReference,
557    /// a pointer to a function
558    FunctionReference,
559    /// this type is a reference to another type
560    TypeReference,
561    /// a structure of elements
562    Structure,
563    /// a union of elements
564    Union,
565    /// an array
566    Array,
567}
568
569impl Display for ImplementationDataCategory {
570    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
571        match self {
572            ImplementationDataCategory::Value => f.write_str("VALUE"),
573            ImplementationDataCategory::DataReference => f.write_str("DATA_REFERENCE"),
574            ImplementationDataCategory::FunctionReference => f.write_str("FUNCTION_REFERENCE"),
575            ImplementationDataCategory::TypeReference => f.write_str("TYPE_REFERENCE"),
576            ImplementationDataCategory::Structure => f.write_str("STRUCTURE"),
577            ImplementationDataCategory::Union => f.write_str("UNION"),
578            ImplementationDataCategory::Array => f.write_str("ARRAY"),
579        }
580    }
581}
582
583impl TryFrom<&str> for ImplementationDataCategory {
584    type Error = AutosarAbstractionError;
585
586    fn try_from(value: &str) -> Result<Self, Self::Error> {
587        match value {
588            "VALUE" => Ok(ImplementationDataCategory::Value),
589            "DATA_REFERENCE" => Ok(ImplementationDataCategory::DataReference),
590            "FUNCTION_REFERENCE" => Ok(ImplementationDataCategory::FunctionReference),
591            "TYPE_REFERENCE" => Ok(ImplementationDataCategory::TypeReference),
592            "STRUCTURE" => Ok(ImplementationDataCategory::Structure),
593            "UNION" => Ok(ImplementationDataCategory::Union),
594            "ARRAY" => Ok(ImplementationDataCategory::Array),
595            _ => Err(AutosarAbstractionError::ValueConversionError {
596                value: value.to_string(),
597                dest: "ImplementationDataCategory".to_string(),
598            }),
599        }
600    }
601}
602
603//#########################################################
604
605/// Settings for an implementation data type
606///
607/// This structure is used to create new implementation data types
608#[derive(Debug, Clone, PartialEq, Eq, Hash)]
609pub enum ImplementationDataTypeSettings {
610    /// A simple value
611    Value {
612        /// the name of the data type
613        name: String,
614        /// the base type of the data type
615        base_type: SwBaseType,
616        /// the `CompuMethod` of the data type
617        compu_method: Option<CompuMethod>,
618        /// the data constraints of the data type
619        data_constraint: Option<DataConstr>,
620    },
621    /// An array of elements
622    Array {
623        /// the name of the data type
624        name: String,
625        /// the length of the array
626        length: u32,
627        /// settings to construct the element type of the array
628        element_type: Box<ImplementationDataTypeSettings>,
629    },
630    /// A structure of elements
631    Structure {
632        /// the name of the structure
633        name: String,
634        /// settings for the elements of the structure
635        elements: Vec<ImplementationDataTypeSettings>,
636    },
637    /// A union of elements
638    Union {
639        /// the name of the union
640        name: String,
641        /// settings for the elements of the union
642        elements: Vec<ImplementationDataTypeSettings>,
643    },
644    /// A pointer to data
645    DataReference {
646        /// the name of the data type
647        name: String,
648        /// the target of the data pointer; either an `SwBaseType` or an `ImplementationDataType`
649        target: DataPointerTarget,
650    },
651    /// A pointer to a function
652    FunctionReference {
653        /// the name of the data type
654        name: String,
655        // TODO: Add reference to the referenced function type
656    },
657    /// A reference to another implementation data type
658    TypeReference {
659        /// the name of the data type
660        name: String,
661        /// the referenced data type
662        reftype: ImplementationDataType,
663        /// the `CompuMethod` of the data type
664        compu_method: Option<CompuMethod>,
665        /// the data constraints of the data type
666        data_constraint: Option<DataConstr>,
667    },
668}
669
670impl ImplementationDataTypeSettings {
671    /// get the name of the implementation data type
672    #[must_use]
673    pub fn name(&self) -> &str {
674        match self {
675            ImplementationDataTypeSettings::Value { name, .. } => name,
676            ImplementationDataTypeSettings::Array { name, .. } => name,
677            ImplementationDataTypeSettings::Structure { name, .. } => name,
678            ImplementationDataTypeSettings::Union { name, .. } => name,
679            ImplementationDataTypeSettings::DataReference { name, .. } => name,
680            ImplementationDataTypeSettings::FunctionReference { name, .. } => name,
681            ImplementationDataTypeSettings::TypeReference { name, .. } => name,
682        }
683    }
684}
685
686//#########################################################
687
688/// The target of an `ImplementationDataType` with category `DataReference`
689#[derive(Debug, Clone, PartialEq, Eq, Hash)]
690pub enum DataPointerTarget {
691    /// A base type
692    BaseType(SwBaseType),
693    /// An implementation data type
694    ImplementationDataType(ImplementationDataType),
695}
696
697//#########################################################
698
699#[cfg(test)]
700mod tests {
701    use super::*;
702    use crate::{
703        AutosarModelAbstraction,
704        datatype::{ApplicationArraySize, ApplicationPrimitiveCategory},
705        software_component::ArgumentDirection,
706    };
707    use autosar_data::AutosarVersion;
708    use datatype::{BaseTypeEncoding, CompuMethodLinearContent, CompuScaleDirection};
709
710    #[test]
711    fn test_impl_data_type() {
712        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
713        let package = model.get_or_create_package("/DataTypes").unwrap();
714        let base_type =
715            SwBaseType::new("uint8", &package, 8, BaseTypeEncoding::None, None, None, Some("uint8")).unwrap();
716        let compu_method = CompuMethod::new(
717            "linear",
718            &package,
719            datatype::CompuMethodContent::Linear(CompuMethodLinearContent {
720                direction: CompuScaleDirection::IntToPhys,
721                offset: 42.0,
722                factor: 1.0,
723                divisor: 1.0,
724                lower_limit: None,
725                upper_limit: None,
726            }),
727        )
728        .unwrap();
729        let data_constraint = DataConstr::new("constraint", &package).unwrap();
730        let other_impl_data_type = ImplementationDataType::new(
731            &package,
732            &ImplementationDataTypeSettings::Value {
733                name: "OtherImplDataType".to_string(),
734                base_type: base_type.clone(),
735                compu_method: Some(compu_method.clone()),
736                data_constraint: None,
737            },
738        )
739        .unwrap();
740        let settings = ImplementationDataTypeSettings::Structure {
741            name: "Structure".to_string(),
742            elements: vec![
743                ImplementationDataTypeSettings::Union {
744                    name: "union".to_string(),
745                    elements: vec![ImplementationDataTypeSettings::Value {
746                        name: "MyImplDataType1".to_string(),
747                        base_type: base_type.clone(),
748                        compu_method: Some(compu_method.clone()),
749                        data_constraint: Some(data_constraint.clone()),
750                    }],
751                },
752                ImplementationDataTypeSettings::Value {
753                    name: "MyImplDataType1".to_string(),
754                    base_type: base_type.clone(),
755                    compu_method: Some(compu_method.clone()),
756                    data_constraint: Some(data_constraint.clone()),
757                },
758                ImplementationDataTypeSettings::Array {
759                    name: "MyArray".to_string(),
760                    length: 10,
761                    element_type: Box::new(ImplementationDataTypeSettings::Value {
762                        name: "MyImplDataType2".to_string(),
763                        base_type: base_type.clone(),
764                        compu_method: Some(compu_method.clone()),
765                        data_constraint: None,
766                    }),
767                },
768                ImplementationDataTypeSettings::TypeReference {
769                    name: "ReferenceType".to_string(),
770                    reftype: other_impl_data_type.clone(),
771                    compu_method: Some(compu_method.clone()),
772                    data_constraint: Some(data_constraint.clone()),
773                },
774                ImplementationDataTypeSettings::DataReference {
775                    name: "DataReferenceToBase".to_string(),
776                    target: DataPointerTarget::BaseType(base_type.clone()),
777                },
778                ImplementationDataTypeSettings::DataReference {
779                    name: "DataReferenceToImpl".to_string(),
780                    target: DataPointerTarget::ImplementationDataType(other_impl_data_type.clone()),
781                },
782            ],
783        };
784        let impl_data_type = ImplementationDataType::new(&package, &settings).unwrap();
785
786        assert_eq!(impl_data_type.category(), Some(ImplementationDataCategory::Structure));
787
788        let sub_elements = impl_data_type.sub_elements().collect::<Vec<_>>();
789        assert_eq!(sub_elements.len(), 6);
790        assert_eq!(sub_elements[0].category(), Some(ImplementationDataCategory::Union));
791        assert_eq!(sub_elements[1].category(), Some(ImplementationDataCategory::Value));
792        assert_eq!(sub_elements[2].category(), Some(ImplementationDataCategory::Array));
793        assert_eq!(
794            sub_elements[3].category(),
795            Some(ImplementationDataCategory::TypeReference)
796        );
797        assert_eq!(
798            sub_elements[4].category(),
799            Some(ImplementationDataCategory::DataReference)
800        );
801        assert_eq!(
802            sub_elements[4].data_pointer_target(),
803            Some(DataPointerTarget::BaseType(base_type.clone()))
804        );
805        assert_eq!(
806            sub_elements[5].category(),
807            Some(ImplementationDataCategory::DataReference)
808        );
809        assert_eq!(
810            sub_elements[5].data_pointer_target(),
811            Some(DataPointerTarget::ImplementationDataType(other_impl_data_type.clone()))
812        );
813
814        let settings_read = impl_data_type.settings().unwrap();
815        assert_eq!(settings, settings_read);
816
817        // overwrite the current settings with new ones
818        let settings2 = ImplementationDataTypeSettings::Value {
819            name: "NewImplDataType".to_string(),
820            base_type,
821            compu_method: None,
822            data_constraint: None,
823        };
824        impl_data_type.apply_settings(&settings2).unwrap();
825        let settings_read = impl_data_type.settings().unwrap();
826        assert_eq!(settings2, settings_read);
827    }
828
829    #[test]
830    fn implementation_data_category() {
831        assert_eq!(ImplementationDataCategory::Value.to_string(), "VALUE");
832        assert_eq!(ImplementationDataCategory::DataReference.to_string(), "DATA_REFERENCE");
833        assert_eq!(
834            ImplementationDataCategory::FunctionReference.to_string(),
835            "FUNCTION_REFERENCE"
836        );
837        assert_eq!(ImplementationDataCategory::TypeReference.to_string(), "TYPE_REFERENCE");
838        assert_eq!(ImplementationDataCategory::Structure.to_string(), "STRUCTURE");
839        assert_eq!(ImplementationDataCategory::Union.to_string(), "UNION");
840        assert_eq!(ImplementationDataCategory::Array.to_string(), "ARRAY");
841
842        assert_eq!(
843            ImplementationDataCategory::try_from("VALUE").unwrap(),
844            ImplementationDataCategory::Value
845        );
846        assert_eq!(
847            ImplementationDataCategory::try_from("DATA_REFERENCE").unwrap(),
848            ImplementationDataCategory::DataReference
849        );
850        assert_eq!(
851            ImplementationDataCategory::try_from("FUNCTION_REFERENCE").unwrap(),
852            ImplementationDataCategory::FunctionReference
853        );
854        assert_eq!(
855            ImplementationDataCategory::try_from("TYPE_REFERENCE").unwrap(),
856            ImplementationDataCategory::TypeReference
857        );
858        assert_eq!(
859            ImplementationDataCategory::try_from("STRUCTURE").unwrap(),
860            ImplementationDataCategory::Structure
861        );
862        assert_eq!(
863            ImplementationDataCategory::try_from("UNION").unwrap(),
864            ImplementationDataCategory::Union
865        );
866        assert_eq!(
867            ImplementationDataCategory::try_from("ARRAY").unwrap(),
868            ImplementationDataCategory::Array
869        );
870
871        assert!(ImplementationDataCategory::try_from("invalid").is_err());
872    }
873
874    #[test]
875    fn remove() {
876        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
877        let package = model.get_or_create_package("/DataTypes").unwrap();
878        let element_type = package
879            .create_application_primitive_data_type(
880                "AppPrimitive",
881                ApplicationPrimitiveCategory::Value,
882                None,
883                None,
884                None,
885            )
886            .unwrap();
887        let array_data_type = package
888            .create_application_array_data_type("AppArray", &element_type, ApplicationArraySize::Fixed(10))
889            .unwrap();
890
891        // create a matching implementation data type
892        let base_type = package
893            .create_sw_base_type("uint8", 8, BaseTypeEncoding::TwosComplement, None, None, Some("uint8"))
894            .unwrap();
895        let impl_array = package
896            .create_implementation_data_type(&ImplementationDataTypeSettings::Array {
897                name: "ImplArray".to_string(),
898                length: 10,
899                element_type: Box::new(ImplementationDataTypeSettings::Value {
900                    name: "ImplPrimitive".to_string(),
901                    base_type,
902                    compu_method: None,
903                    data_constraint: None,
904                }),
905            })
906            .unwrap();
907
908        // create a data type mapping that maps the implementation array to the application array
909        let data_type_mapping_set = package.create_data_type_mapping_set("DataTypeMappingSet").unwrap();
910        data_type_mapping_set
911            .create_data_type_map(&impl_array, &array_data_type)
912            .unwrap();
913
914        // create a SenderReceiverInterface that uses the implementation array data type
915        let sr_interface = package.create_sender_receiver_interface("SRInterface").unwrap();
916        let _vdp = sr_interface.create_data_element("VDP", &impl_array).unwrap();
917        // create a client-server interface that uses the implementation array data type
918        let cs_interface = package.create_client_server_interface("CSInterface").unwrap();
919        let cso = cs_interface.create_operation("ADP").unwrap();
920        let _adp = cso.create_argument("ADP", &impl_array, ArgumentDirection::In).unwrap();
921
922        // create an implementation data type that references the implementation array data type
923        let impl_ref_type = package
924            .create_implementation_data_type(&ImplementationDataTypeSettings::TypeReference {
925                name: "ImplRecord".to_string(),
926                reftype: impl_array.clone(),
927                compu_method: None,
928                data_constraint: None,
929            })
930            .unwrap();
931
932        // remove the application array data type deeply
933        impl_array.remove(true).unwrap();
934
935        // check that all related elements have been removed
936        assert_eq!(data_type_mapping_set.data_type_maps().count(), 0);
937        assert_eq!(sr_interface.data_elements().count(), 0);
938        assert_eq!(cso.arguments().count(), 0);
939        assert!(impl_ref_type.element().path().is_err());
940    }
941}