autosar_data_abstraction/datatype/
implementationtype.rs

1use crate::{
2    AbstractionElement, ArPackage, AutosarAbstractionError, Element, EnumItem, IdentifiableAbstractionElement,
3    abstraction_element, datatype,
4};
5use autosar_data::ElementName;
6use datatype::{AbstractAutosarDataType, CompuMethod, DataConstr, SwBaseType};
7use std::fmt::Display;
8
9/// Interface for implementation data types, which provides default implementations for common operations
10pub trait AbstractImplementationDataType: IdentifiableAbstractionElement {
11    /// get the category of this implementation data type
12    fn category(&self) -> Option<ImplementationDataCategory> {
13        self.element()
14            .get_sub_element(ElementName::Category)?
15            .character_data()?
16            .string_value()?
17            .as_str()
18            .try_into()
19            .ok()
20    }
21
22    /// create an iterator over the sub-elements of this implementation data type
23    fn sub_elements(&self) -> impl Iterator<Item = ImplementationDataTypeElement> + Send + 'static {
24        self.element()
25            .get_sub_element(ElementName::SubElements)
26            .into_iter()
27            .flat_map(|elem| elem.sub_elements())
28            .filter_map(|elem| ImplementationDataTypeElement::try_from(elem).ok())
29    }
30
31    /// get the `SwBaseType` of this implementation data type [category: VALUE]
32    fn base_type(&self) -> Option<SwBaseType> {
33        let category = self.category()?;
34        if category != ImplementationDataCategory::Value {
35            return None;
36        }
37        self.element()
38            .get_sub_element(ElementName::SwDataDefProps)?
39            .get_sub_element(ElementName::SwDataDefPropsVariants)?
40            .get_sub_element(ElementName::SwDataDefPropsConditional)?
41            .get_sub_element(ElementName::BaseTypeRef)?
42            .get_reference_target()
43            .ok()?
44            .try_into()
45            .ok()
46    }
47
48    /// get the `CompuMethod` of this implementation data type [category: VALUE, `TYPE_REFERENCE`]
49    fn compu_method(&self) -> Option<CompuMethod> {
50        let category = self.category()?;
51        if category != ImplementationDataCategory::Value && category != ImplementationDataCategory::TypeReference {
52            return None;
53        }
54        self.element()
55            .get_sub_element(ElementName::SwDataDefProps)?
56            .get_sub_element(ElementName::SwDataDefPropsVariants)?
57            .get_sub_element(ElementName::SwDataDefPropsConditional)?
58            .get_sub_element(ElementName::CompuMethodRef)
59            .and_then(|cmref| cmref.get_reference_target().ok())
60            .and_then(|refelem| refelem.try_into().ok())
61    }
62
63    /// get the `DataConstr` of this implementation data type [category: VALUE, `TYPE_REFERENCE`]
64    fn data_constraint(&self) -> Option<DataConstr> {
65        let category = self.category()?;
66        if category != ImplementationDataCategory::Value && category != ImplementationDataCategory::TypeReference {
67            return None;
68        }
69        self.element()
70            .get_sub_element(ElementName::SwDataDefProps)?
71            .get_sub_element(ElementName::SwDataDefPropsVariants)?
72            .get_sub_element(ElementName::SwDataDefPropsConditional)?
73            .get_sub_element(ElementName::DataConstrRef)
74            .and_then(|dcref| dcref.get_reference_target().ok())
75            .and_then(|refelem| refelem.try_into().ok())
76    }
77
78    /// get the referenced implementation data type [category: `TYPE_REFERENCE`]
79    fn referenced_type(&self) -> Option<ImplementationDataType> {
80        let category = self.category()?;
81        if category != ImplementationDataCategory::TypeReference {
82            return None;
83        }
84        self.element()
85            .get_sub_element(ElementName::SwDataDefProps)?
86            .get_sub_element(ElementName::SwDataDefPropsVariants)?
87            .get_sub_element(ElementName::SwDataDefPropsConditional)?
88            .get_sub_element(ElementName::ImplementationDataTypeRef)?
89            .get_reference_target()
90            .ok()?
91            .try_into()
92            .ok()
93    }
94
95    /// get the array size of this implementation data type [category: ARRAY]
96    fn array_size(&self) -> Option<u32> {
97        let category = self.category()?;
98        if category != ImplementationDataCategory::Array {
99            return None;
100        }
101        self.sub_elements()
102            .next()?
103            .element()
104            .get_sub_element(ElementName::ArraySize)?
105            .character_data()?
106            .parse_integer()
107    }
108
109    /// get the data pointer target of this implementation data type [category: DATA_REFERENCE]
110    fn data_pointer_target(&self) -> Option<DataPointerTarget> {
111        let category = self.category()?;
112        if category != ImplementationDataCategory::DataReference {
113            return None;
114        }
115        let sw_pointer_target_props = self
116            .element()
117            .get_sub_element(ElementName::SwDataDefProps)?
118            .get_sub_element(ElementName::SwDataDefPropsVariants)?
119            .get_sub_element(ElementName::SwDataDefPropsConditional)?
120            .get_sub_element(ElementName::SwPointerTargetProps)?
121            .get_sub_element(ElementName::SwDataDefProps)?
122            .get_sub_element(ElementName::SwDataDefPropsVariants)?
123            .get_sub_element(ElementName::SwDataDefPropsConditional)?;
124        if let Some(base_type) = sw_pointer_target_props
125            .get_sub_element(ElementName::BaseTypeRef)
126            .and_then(|elem| elem.get_reference_target().ok())
127        {
128            Some(DataPointerTarget::BaseType(base_type.try_into().ok()?))
129        } else if let Some(impl_data_type) = sw_pointer_target_props
130            .get_sub_element(ElementName::ImplementationDataTypeRef)
131            .and_then(|elem| elem.get_reference_target().ok())
132        {
133            Some(DataPointerTarget::ImplementationDataType(
134                impl_data_type.try_into().ok()?,
135            ))
136        } else {
137            None
138        }
139    }
140
141    /// apply the settings to this implementation data type
142    ///
143    /// Calling this method completely replaces the existing settings of the implementation data type,
144    /// deleting existing sub-elements and creating new ones according to the settings
145    fn apply_settings(&self, settings: &ImplementationDataTypeSettings) -> Result<(), AutosarAbstractionError> {
146        self.set_name(settings.name())?;
147        apply_impl_data_settings(self.element(), settings)
148    }
149
150    /// get the settings of this implementation data type
151    fn settings(&self) -> Option<ImplementationDataTypeSettings> {
152        let category = self.category()?;
153        match category {
154            ImplementationDataCategory::Value => Some(ImplementationDataTypeSettings::Value {
155                name: self.name()?,
156                base_type: self.base_type()?,
157                compu_method: self.compu_method(),
158                data_constraint: self.data_constraint(),
159            }),
160            ImplementationDataCategory::Array => {
161                let element_settings = self.sub_elements().next()?.settings()?;
162                Some(ImplementationDataTypeSettings::Array {
163                    name: self.name()?,
164                    length: self.array_size()?,
165                    element_type: Box::new(element_settings),
166                })
167            }
168            ImplementationDataCategory::Structure => {
169                let elements = self
170                    .sub_elements()
171                    .map(|elem| elem.settings())
172                    .collect::<Option<Vec<_>>>()?;
173                Some(ImplementationDataTypeSettings::Structure {
174                    name: self.name()?,
175                    elements,
176                })
177            }
178            ImplementationDataCategory::Union => {
179                let elements = self
180                    .sub_elements()
181                    .map(|elem| elem.settings())
182                    .collect::<Option<Vec<_>>>()?;
183                Some(ImplementationDataTypeSettings::Union {
184                    name: self.name()?,
185                    elements,
186                })
187            }
188            ImplementationDataCategory::DataReference => {
189                let sw_pointer_target_props = self
190                    .element()
191                    .get_sub_element(ElementName::SwDataDefProps)?
192                    .get_sub_element(ElementName::SwDataDefPropsVariants)?
193                    .get_sub_element(ElementName::SwDataDefPropsConditional)?
194                    .get_sub_element(ElementName::SwPointerTargetProps)?
195                    .get_sub_element(ElementName::SwDataDefProps)?
196                    .get_sub_element(ElementName::SwDataDefPropsVariants)?
197                    .get_sub_element(ElementName::SwDataDefPropsConditional)?;
198                let target = if let Some(base_type) = sw_pointer_target_props
199                    .get_sub_element(ElementName::BaseTypeRef)
200                    .and_then(|elem| elem.get_reference_target().ok())
201                {
202                    DataPointerTarget::BaseType(base_type.try_into().ok()?)
203                } else if let Some(impl_data_type) = sw_pointer_target_props
204                    .get_sub_element(ElementName::ImplementationDataTypeRef)
205                    .and_then(|elem| elem.get_reference_target().ok())
206                {
207                    DataPointerTarget::ImplementationDataType(impl_data_type.try_into().ok()?)
208                } else {
209                    return None;
210                };
211                Some(ImplementationDataTypeSettings::DataReference {
212                    name: self.name()?,
213                    target,
214                })
215            }
216            ImplementationDataCategory::FunctionReference => {
217                Some(ImplementationDataTypeSettings::FunctionReference { name: self.name()? })
218            }
219            ImplementationDataCategory::TypeReference => Some(ImplementationDataTypeSettings::TypeReference {
220                name: self.name()?,
221                reftype: self.referenced_type()?,
222                compu_method: self.compu_method(),
223                data_constraint: self.data_constraint(),
224            }),
225        }
226    }
227}
228
229//#########################################################
230
231/// An implementation data type; specifics are determined by the category
232///
233/// Use [`ArPackage::create_implementation_data_type`] to create a new implementation data type
234#[derive(Debug, Clone, PartialEq, Eq, Hash)]
235pub struct ImplementationDataType(Element);
236abstraction_element!(ImplementationDataType, ImplementationDataType);
237impl IdentifiableAbstractionElement for ImplementationDataType {}
238impl AbstractAutosarDataType for ImplementationDataType {}
239impl AbstractImplementationDataType for ImplementationDataType {}
240
241impl ImplementationDataType {
242    /// create a new implementation data type from an `ImplementationDataTypeSettings` structure
243    pub(crate) fn new(
244        package: &ArPackage,
245        settings: &ImplementationDataTypeSettings,
246    ) -> Result<Self, AutosarAbstractionError> {
247        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
248        let implementation_data_type =
249            elements.create_named_sub_element(ElementName::ImplementationDataType, settings.name())?;
250        let implementation_data_type = Self(implementation_data_type);
251        implementation_data_type.apply_settings(settings)?;
252
253        Ok(implementation_data_type)
254    }
255}
256
257//#########################################################
258
259/// An element of an implementation data type
260#[derive(Debug, Clone, PartialEq, Eq, Hash)]
261pub struct ImplementationDataTypeElement(Element);
262abstraction_element!(ImplementationDataTypeElement, ImplementationDataTypeElement);
263impl IdentifiableAbstractionElement for ImplementationDataTypeElement {}
264impl AbstractImplementationDataType for ImplementationDataTypeElement {}
265
266impl ImplementationDataTypeElement {
267    pub(crate) fn new(
268        parent: &Element,
269        settings: &ImplementationDataTypeSettings,
270    ) -> Result<Self, AutosarAbstractionError> {
271        let implementation_data_type_element =
272            parent.create_named_sub_element(ElementName::ImplementationDataTypeElement, settings.name())?;
273        let implementation_data_type_element = Self(implementation_data_type_element);
274        implementation_data_type_element.apply_settings(settings)?;
275
276        Ok(implementation_data_type_element)
277    }
278}
279
280//#########################################################
281
282fn apply_impl_data_settings(
283    element: &Element,
284    settings: &ImplementationDataTypeSettings,
285) -> Result<(), AutosarAbstractionError> {
286    // remove the existing sub-elements of the implementation data type
287    let _ = element.remove_sub_element_kind(ElementName::Category);
288    let _ = element.remove_sub_element_kind(ElementName::SubElements);
289    let _ = element.remove_sub_element_kind(ElementName::SwDataDefProps);
290    // DynamicArraySizeProfile is part of the definition of variable-sized arrays, which are not supported (yet?)
291    let _ = element.remove_sub_element_kind(ElementName::DynamicArraySizeProfile);
292
293    match settings {
294        ImplementationDataTypeSettings::Value {
295            base_type,
296            compu_method,
297            data_constraint,
298            ..
299        } => {
300            element
301                .create_sub_element(ElementName::Category)?
302                .set_character_data("VALUE")?;
303            let sw_data_def_props = element
304                .create_sub_element(ElementName::SwDataDefProps)?
305                .create_sub_element(ElementName::SwDataDefPropsVariants)?
306                .create_sub_element(ElementName::SwDataDefPropsConditional)?;
307            sw_data_def_props
308                .create_sub_element(ElementName::BaseTypeRef)?
309                .set_reference_target(base_type.element())?;
310            if let Some(compu_method) = compu_method {
311                sw_data_def_props
312                    .create_sub_element(ElementName::CompuMethodRef)?
313                    .set_reference_target(compu_method.element())?;
314            }
315            if let Some(data_constraint) = data_constraint {
316                sw_data_def_props
317                    .create_sub_element(ElementName::DataConstrRef)?
318                    .set_reference_target(data_constraint.element())?;
319            }
320        }
321        ImplementationDataTypeSettings::Array {
322            length, element_type, ..
323        } => {
324            element
325                .create_sub_element(ElementName::Category)?
326                .set_character_data("ARRAY")?;
327            let sub_elements = element.get_or_create_sub_element(ElementName::SubElements)?;
328            let array_element = ImplementationDataTypeElement::new(&sub_elements, element_type)?;
329            array_element
330                .element()
331                .create_sub_element(ElementName::ArraySize)?
332                .set_character_data(u64::from(*length))?;
333            array_element
334                .element()
335                .create_sub_element(ElementName::ArraySizeSemantics)?
336                .set_character_data(EnumItem::FixedSize)?;
337        }
338        ImplementationDataTypeSettings::Structure { elements, .. } => {
339            element
340                .create_sub_element(ElementName::Category)?
341                .set_character_data("STRUCTURE")?;
342            let sub_elements = element.get_or_create_sub_element(ElementName::SubElements)?;
343            for sub_element in elements {
344                ImplementationDataTypeElement::new(&sub_elements, sub_element)?;
345            }
346        }
347        ImplementationDataTypeSettings::Union { elements, .. } => {
348            element
349                .create_sub_element(ElementName::Category)?
350                .set_character_data("UNION")?;
351            let sub_elements = element.get_or_create_sub_element(ElementName::SubElements)?;
352            for sub_element in elements {
353                ImplementationDataTypeElement::new(&sub_elements, sub_element)?;
354            }
355        }
356        ImplementationDataTypeSettings::DataReference { target, .. } => {
357            element
358                .create_sub_element(ElementName::Category)?
359                .set_character_data("DATA_REFERENCE")?;
360            let pointer_props = element
361                .create_sub_element(ElementName::SwDataDefProps)?
362                .create_sub_element(ElementName::SwDataDefPropsVariants)?
363                .create_sub_element(ElementName::SwDataDefPropsConditional)?
364                .create_sub_element(ElementName::SwPointerTargetProps)?;
365            let contained_props = pointer_props
366                .create_sub_element(ElementName::SwDataDefProps)?
367                .create_sub_element(ElementName::SwDataDefPropsVariants)?
368                .create_sub_element(ElementName::SwDataDefPropsConditional)?;
369            match target {
370                DataPointerTarget::BaseType(base_type) => {
371                    contained_props
372                        .create_sub_element(ElementName::BaseTypeRef)?
373                        .set_reference_target(base_type.element())?;
374                    pointer_props
375                        .create_sub_element(ElementName::TargetCategory)
376                        .and_then(|elem| elem.set_character_data("VALUE"))?;
377                }
378                DataPointerTarget::ImplementationDataType(impl_data_type) => {
379                    contained_props
380                        .create_sub_element(ElementName::ImplementationDataTypeRef)?
381                        .set_reference_target(impl_data_type.element())?;
382                    let target_category = impl_data_type
383                        .category()
384                        .as_ref()
385                        .map(|item| item.to_string())
386                        .unwrap_or("VALUE".to_string());
387                    pointer_props
388                        .create_sub_element(ElementName::TargetCategory)?
389                        .set_character_data(target_category)?;
390                }
391            }
392        }
393        ImplementationDataTypeSettings::FunctionReference { .. } => {
394            element
395                .create_sub_element(ElementName::Category)?
396                .set_character_data("FUNCTION_REFERENCE")?;
397        }
398        ImplementationDataTypeSettings::TypeReference {
399            reftype,
400            compu_method,
401            data_constraint,
402            ..
403        } => {
404            element
405                .create_sub_element(ElementName::Category)?
406                .set_character_data("TYPE_REFERENCE")?;
407            let sw_data_def_props = element
408                .create_sub_element(ElementName::SwDataDefProps)?
409                .create_sub_element(ElementName::SwDataDefPropsVariants)?
410                .create_sub_element(ElementName::SwDataDefPropsConditional)?;
411            sw_data_def_props
412                .create_sub_element(ElementName::ImplementationDataTypeRef)?
413                .set_reference_target(reftype.element())?;
414            if let Some(compu_method) = compu_method {
415                sw_data_def_props
416                    .create_sub_element(ElementName::CompuMethodRef)?
417                    .set_reference_target(compu_method.element())?;
418            }
419            if let Some(data_constraint) = data_constraint {
420                sw_data_def_props
421                    .create_sub_element(ElementName::DataConstrRef)?
422                    .set_reference_target(data_constraint.element())?;
423            }
424        }
425    }
426
427    Ok(())
428}
429
430//#########################################################
431
432/// The category of an implementation data type
433#[derive(Debug, Clone, PartialEq, Eq, Hash)]
434pub enum ImplementationDataCategory {
435    /// A simple value
436    Value,
437    /// a pointer to data
438    DataReference,
439    /// a pointer to a function
440    FunctionReference,
441    /// this type is a reference to another type
442    TypeReference,
443    /// a structure of elements
444    Structure,
445    /// a union of elements
446    Union,
447    /// an array
448    Array,
449}
450
451impl Display for ImplementationDataCategory {
452    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
453        match self {
454            ImplementationDataCategory::Value => f.write_str("VALUE"),
455            ImplementationDataCategory::DataReference => f.write_str("DATA_REFERENCE"),
456            ImplementationDataCategory::FunctionReference => f.write_str("FUNCTION_REFERENCE"),
457            ImplementationDataCategory::TypeReference => f.write_str("TYPE_REFERENCE"),
458            ImplementationDataCategory::Structure => f.write_str("STRUCTURE"),
459            ImplementationDataCategory::Union => f.write_str("UNION"),
460            ImplementationDataCategory::Array => f.write_str("ARRAY"),
461        }
462    }
463}
464
465impl TryFrom<&str> for ImplementationDataCategory {
466    type Error = AutosarAbstractionError;
467
468    fn try_from(value: &str) -> Result<Self, Self::Error> {
469        match value {
470            "VALUE" => Ok(ImplementationDataCategory::Value),
471            "DATA_REFERENCE" => Ok(ImplementationDataCategory::DataReference),
472            "FUNCTION_REFERENCE" => Ok(ImplementationDataCategory::FunctionReference),
473            "TYPE_REFERENCE" => Ok(ImplementationDataCategory::TypeReference),
474            "STRUCTURE" => Ok(ImplementationDataCategory::Structure),
475            "UNION" => Ok(ImplementationDataCategory::Union),
476            "ARRAY" => Ok(ImplementationDataCategory::Array),
477            _ => Err(AutosarAbstractionError::ValueConversionError {
478                value: value.to_string(),
479                dest: "ImplementationDataCategory".to_string(),
480            }),
481        }
482    }
483}
484
485//#########################################################
486
487/// Settings for an implementation data type
488///
489/// This structure is used to create new implementation data types
490#[derive(Debug, Clone, PartialEq, Eq, Hash)]
491pub enum ImplementationDataTypeSettings {
492    /// A simple value
493    Value {
494        /// the name of the data type
495        name: String,
496        /// the base type of the data type
497        base_type: SwBaseType,
498        /// the `CompuMethod` of the data type
499        compu_method: Option<CompuMethod>,
500        /// the data constraints of the data type
501        data_constraint: Option<DataConstr>,
502    },
503    /// An array of elements
504    Array {
505        /// the name of the data type
506        name: String,
507        /// the length of the array
508        length: u32,
509        /// settings to construct the element type of the array
510        element_type: Box<ImplementationDataTypeSettings>,
511    },
512    /// A structure of elements
513    Structure {
514        /// the name of the structure
515        name: String,
516        /// settings for the elements of the structure
517        elements: Vec<ImplementationDataTypeSettings>,
518    },
519    /// A union of elements
520    Union {
521        /// the name of the union
522        name: String,
523        /// settings for the elements of the union
524        elements: Vec<ImplementationDataTypeSettings>,
525    },
526    /// A pointer to data
527    DataReference {
528        /// the name of the data type
529        name: String,
530        /// the target of the data pointer; either an SwBaseType or an ImplementationDataType
531        target: DataPointerTarget,
532    },
533    /// A pointer to a function
534    FunctionReference {
535        /// the name of the data type
536        name: String,
537        // TODO: Add reference to the referenced function type
538    },
539    /// A reference to another implementation data type
540    TypeReference {
541        /// the name of the data type
542        name: String,
543        /// the referenced data type
544        reftype: ImplementationDataType,
545        /// the `CompuMethod` of the data type
546        compu_method: Option<CompuMethod>,
547        /// the data constraints of the data type
548        data_constraint: Option<DataConstr>,
549    },
550}
551
552impl ImplementationDataTypeSettings {
553    /// get the name of the implementation data type
554    #[must_use]
555    pub fn name(&self) -> &str {
556        match self {
557            ImplementationDataTypeSettings::Value { name, .. } => name,
558            ImplementationDataTypeSettings::Array { name, .. } => name,
559            ImplementationDataTypeSettings::Structure { name, .. } => name,
560            ImplementationDataTypeSettings::Union { name, .. } => name,
561            ImplementationDataTypeSettings::DataReference { name, .. } => name,
562            ImplementationDataTypeSettings::FunctionReference { name, .. } => name,
563            ImplementationDataTypeSettings::TypeReference { name, .. } => name,
564        }
565    }
566}
567
568//#########################################################
569
570/// The target of an ImplementationDataType with category DataReference
571#[derive(Debug, Clone, PartialEq, Eq, Hash)]
572pub enum DataPointerTarget {
573    /// A base type
574    BaseType(SwBaseType),
575    /// An implementation data type
576    ImplementationDataType(ImplementationDataType),
577}
578
579//#########################################################
580
581#[cfg(test)]
582mod tests {
583    use super::*;
584    use crate::AutosarModelAbstraction;
585    use autosar_data::AutosarVersion;
586    use datatype::{BaseTypeEncoding, CompuMethodLinearContent, CompuScaleDirection};
587
588    #[test]
589    fn test_impl_data_type() {
590        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
591        let package = model.get_or_create_package("/DataTypes").unwrap();
592        let base_type =
593            SwBaseType::new("uint8", &package, 8, BaseTypeEncoding::None, None, None, Some("uint8")).unwrap();
594        let compu_method = CompuMethod::new(
595            "linear",
596            &package,
597            datatype::CompuMethodContent::Linear(CompuMethodLinearContent {
598                direction: CompuScaleDirection::IntToPhys,
599                offset: 42.0,
600                factor: 1.0,
601                divisor: 1.0,
602                lower_limit: None,
603                upper_limit: None,
604            }),
605        )
606        .unwrap();
607        let data_constraint = DataConstr::new("constraint", &package).unwrap();
608        let other_impl_data_type = ImplementationDataType::new(
609            &package,
610            &ImplementationDataTypeSettings::Value {
611                name: "OtherImplDataType".to_string(),
612                base_type: base_type.clone(),
613                compu_method: Some(compu_method.clone()),
614                data_constraint: None,
615            },
616        )
617        .unwrap();
618        let settings = ImplementationDataTypeSettings::Structure {
619            name: "Structure".to_string(),
620            elements: vec![
621                ImplementationDataTypeSettings::Union {
622                    name: "union".to_string(),
623                    elements: vec![ImplementationDataTypeSettings::Value {
624                        name: "MyImplDataType1".to_string(),
625                        base_type: base_type.clone(),
626                        compu_method: Some(compu_method.clone()),
627                        data_constraint: Some(data_constraint.clone()),
628                    }],
629                },
630                ImplementationDataTypeSettings::Value {
631                    name: "MyImplDataType1".to_string(),
632                    base_type: base_type.clone(),
633                    compu_method: Some(compu_method.clone()),
634                    data_constraint: Some(data_constraint.clone()),
635                },
636                ImplementationDataTypeSettings::Array {
637                    name: "MyArray".to_string(),
638                    length: 10,
639                    element_type: Box::new(ImplementationDataTypeSettings::Value {
640                        name: "MyImplDataType2".to_string(),
641                        base_type: base_type.clone(),
642                        compu_method: Some(compu_method.clone()),
643                        data_constraint: None,
644                    }),
645                },
646                ImplementationDataTypeSettings::TypeReference {
647                    name: "ReferenceType".to_string(),
648                    reftype: other_impl_data_type.clone(),
649                    compu_method: Some(compu_method.clone()),
650                    data_constraint: Some(data_constraint.clone()),
651                },
652                ImplementationDataTypeSettings::DataReference {
653                    name: "DataReferenceToBase".to_string(),
654                    target: DataPointerTarget::BaseType(base_type.clone()),
655                },
656                ImplementationDataTypeSettings::DataReference {
657                    name: "DataReferenceToImpl".to_string(),
658                    target: DataPointerTarget::ImplementationDataType(other_impl_data_type.clone()),
659                },
660            ],
661        };
662        let impl_data_type = ImplementationDataType::new(&package, &settings).unwrap();
663
664        assert_eq!(impl_data_type.category(), Some(ImplementationDataCategory::Structure));
665
666        let sub_elements = impl_data_type.sub_elements().collect::<Vec<_>>();
667        assert_eq!(sub_elements.len(), 6);
668        assert_eq!(sub_elements[0].category(), Some(ImplementationDataCategory::Union));
669        assert_eq!(sub_elements[1].category(), Some(ImplementationDataCategory::Value));
670        assert_eq!(sub_elements[2].category(), Some(ImplementationDataCategory::Array));
671        assert_eq!(
672            sub_elements[3].category(),
673            Some(ImplementationDataCategory::TypeReference)
674        );
675        assert_eq!(
676            sub_elements[4].category(),
677            Some(ImplementationDataCategory::DataReference)
678        );
679        assert_eq!(
680            sub_elements[4].data_pointer_target(),
681            Some(DataPointerTarget::BaseType(base_type.clone()))
682        );
683        assert_eq!(
684            sub_elements[5].category(),
685            Some(ImplementationDataCategory::DataReference)
686        );
687        assert_eq!(
688            sub_elements[5].data_pointer_target(),
689            Some(DataPointerTarget::ImplementationDataType(other_impl_data_type.clone()))
690        );
691
692        let settings_read = impl_data_type.settings().unwrap();
693        assert_eq!(settings, settings_read);
694
695        // overwrite the current settings with new ones
696        let settings2 = ImplementationDataTypeSettings::Value {
697            name: "NewImplDataType".to_string(),
698            base_type,
699            compu_method: None,
700            data_constraint: None,
701        };
702        impl_data_type.apply_settings(&settings2).unwrap();
703        let settings_read = impl_data_type.settings().unwrap();
704        assert_eq!(settings2, settings_read);
705    }
706
707    #[test]
708    fn implementation_data_category() {
709        assert_eq!(ImplementationDataCategory::Value.to_string(), "VALUE");
710        assert_eq!(ImplementationDataCategory::DataReference.to_string(), "DATA_REFERENCE");
711        assert_eq!(
712            ImplementationDataCategory::FunctionReference.to_string(),
713            "FUNCTION_REFERENCE"
714        );
715        assert_eq!(ImplementationDataCategory::TypeReference.to_string(), "TYPE_REFERENCE");
716        assert_eq!(ImplementationDataCategory::Structure.to_string(), "STRUCTURE");
717        assert_eq!(ImplementationDataCategory::Union.to_string(), "UNION");
718        assert_eq!(ImplementationDataCategory::Array.to_string(), "ARRAY");
719
720        assert_eq!(
721            ImplementationDataCategory::try_from("VALUE").unwrap(),
722            ImplementationDataCategory::Value
723        );
724        assert_eq!(
725            ImplementationDataCategory::try_from("DATA_REFERENCE").unwrap(),
726            ImplementationDataCategory::DataReference
727        );
728        assert_eq!(
729            ImplementationDataCategory::try_from("FUNCTION_REFERENCE").unwrap(),
730            ImplementationDataCategory::FunctionReference
731        );
732        assert_eq!(
733            ImplementationDataCategory::try_from("TYPE_REFERENCE").unwrap(),
734            ImplementationDataCategory::TypeReference
735        );
736        assert_eq!(
737            ImplementationDataCategory::try_from("STRUCTURE").unwrap(),
738            ImplementationDataCategory::Structure
739        );
740        assert_eq!(
741            ImplementationDataCategory::try_from("UNION").unwrap(),
742            ImplementationDataCategory::Union
743        );
744        assert_eq!(
745            ImplementationDataCategory::try_from("ARRAY").unwrap(),
746            ImplementationDataCategory::Array
747        );
748
749        assert!(ImplementationDataCategory::try_from("invalid").is_err());
750    }
751}