autosar_data_abstraction/datatype/
mod.rs

1//! # Autosar Data Types
2//!
3//! This module contains the implementation of the AUTOSAR data types, as well as supporting elements like compu methods and data constraints.
4
5use crate::{
6    AbstractionElement, ArPackage, AutosarAbstractionError, IdentifiableAbstractionElement, abstraction_element,
7};
8use autosar_data::{Element, ElementName};
9
10mod applicationtype;
11mod basetype;
12mod compu_method;
13mod implementationtype;
14mod mapping;
15mod values;
16
17pub use applicationtype::*;
18pub use basetype::*;
19pub use compu_method::*;
20pub use implementationtype::*;
21pub use mapping::*;
22pub use values::*;
23
24//#########################################################
25
26/// `AbstractAutosarDataType` is a marker trait for all data types
27pub trait AbstractAutosarDataType: AbstractionElement {}
28
29//#########################################################
30
31/// `AutosarDataType` is the abstract base class for all data types in the AUTOSAR metamodel.
32///
33/// It encapsulates both application data types and implementation data types.
34#[derive(Debug, Clone, PartialEq, Eq, Hash)]
35pub enum AutosarDataType {
36    /// An application primitive data type
37    ApplicationPrimitiveDataType(ApplicationPrimitiveDataType),
38    /// An application array data type
39    ApplicationArrayDataType(ApplicationArrayDataType),
40    /// An application record data type
41    ApplicationRecordDataType(ApplicationRecordDataType),
42    /// An implementation data type
43    ImplementationDataType(ImplementationDataType),
44}
45
46impl AbstractionElement for AutosarDataType {
47    fn element(&self) -> &Element {
48        match self {
49            AutosarDataType::ApplicationPrimitiveDataType(data_type) => data_type.element(),
50            AutosarDataType::ApplicationArrayDataType(data_type) => data_type.element(),
51            AutosarDataType::ApplicationRecordDataType(data_type) => data_type.element(),
52            AutosarDataType::ImplementationDataType(data_type) => data_type.element(),
53        }
54    }
55}
56
57impl TryFrom<Element> for AutosarDataType {
58    type Error = AutosarAbstractionError;
59
60    fn try_from(element: Element) -> Result<Self, Self::Error> {
61        match element.element_name() {
62            ElementName::ApplicationPrimitiveDataType => Ok(Self::ApplicationPrimitiveDataType(
63                ApplicationPrimitiveDataType::try_from(element)?,
64            )),
65            ElementName::ApplicationArrayDataType => Ok(Self::ApplicationArrayDataType(
66                ApplicationArrayDataType::try_from(element)?,
67            )),
68            ElementName::ApplicationRecordDataType => Ok(Self::ApplicationRecordDataType(
69                ApplicationRecordDataType::try_from(element)?,
70            )),
71            ElementName::ImplementationDataType => {
72                Ok(Self::ImplementationDataType(ImplementationDataType::try_from(element)?))
73            }
74            _ => Err(AutosarAbstractionError::ConversionError {
75                element,
76                dest: "AutosarDataType".to_string(),
77            }),
78        }
79    }
80}
81
82impl IdentifiableAbstractionElement for AutosarDataType {}
83impl AbstractAutosarDataType for AutosarDataType {}
84
85//#########################################################
86
87/// `Unit` represents a unit of measurement.
88///
89/// Use [`ArPackage::create_unit`] to create a new unit.
90#[derive(Debug, Clone, PartialEq, Eq, Hash)]
91pub struct Unit(Element);
92abstraction_element!(Unit, Unit);
93impl IdentifiableAbstractionElement for Unit {}
94
95impl Unit {
96    /// Create a new unit
97    pub(crate) fn new(
98        name: &str,
99        package: &ArPackage,
100        display_name: Option<&str>,
101    ) -> Result<Self, AutosarAbstractionError> {
102        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
103        let unit_elem = elements.create_named_sub_element(ElementName::Unit, name)?;
104        let unit = Unit(unit_elem);
105
106        unit.set_display_name(display_name)?;
107
108        Ok(unit)
109    }
110
111    /// Set the display name of the unit
112    pub fn set_display_name(&self, display_name: Option<&str>) -> Result<(), AutosarAbstractionError> {
113        if let Some(display_name) = display_name {
114            self.element()
115                .get_or_create_sub_element(ElementName::DisplayName)?
116                .set_character_data(display_name)?;
117        } else {
118            let _ = self.element().remove_sub_element_kind(ElementName::DisplayName);
119        }
120
121        Ok(())
122    }
123
124    /// Get the display name of the unit
125    #[must_use]
126    pub fn display_name(&self) -> Option<String> {
127        self.element()
128            .get_sub_element(ElementName::DisplayName)?
129            .character_data()?
130            .string_value()
131    }
132}
133
134//#########################################################
135
136/// `DataConstr` represents a data constraint.
137#[derive(Debug, Clone, PartialEq, Eq, Hash)]
138pub struct DataConstr(Element);
139abstraction_element!(DataConstr, DataConstr);
140impl IdentifiableAbstractionElement for DataConstr {}
141
142impl DataConstr {
143    /// Create a new data constraint
144    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
145        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
146        let data_constr = elements.create_named_sub_element(ElementName::DataConstr, name)?;
147
148        Ok(Self(data_constr))
149    }
150
151    /// Create a data constraint rule
152    pub fn create_data_constr_rule(
153        &self,
154        rule_type: DataConstrType,
155        lower_limit: Option<f64>,
156        upper_limit: Option<f64>,
157    ) -> Result<DataConstrRule, AutosarAbstractionError> {
158        let data_constr_rules = self.element().get_or_create_sub_element(ElementName::DataConstrRules)?;
159        let rule = DataConstrRule::new(&data_constr_rules, rule_type, lower_limit, upper_limit)?;
160        Ok(rule)
161    }
162
163    /// Get all data constraint rules
164    pub fn data_constr_rules(&self) -> impl Iterator<Item = DataConstrRule> + Send + use<> {
165        self.element()
166            .get_sub_element(ElementName::DataConstrRules)
167            .into_iter()
168            .flat_map(|rules| rules.sub_elements())
169            .filter_map(|elem| DataConstrRule::try_from(elem).ok())
170    }
171}
172
173//#########################################################
174
175/// `DataConstrRule` represents a data constraint rule.
176#[derive(Debug, Clone, PartialEq, Eq, Hash)]
177pub struct DataConstrRule(Element);
178abstraction_element!(DataConstrRule, DataConstrRule);
179
180impl DataConstrRule {
181    pub(crate) fn new(
182        parent: &Element,
183        rule_type: DataConstrType,
184        lower_limit: Option<f64>,
185        upper_limit: Option<f64>,
186    ) -> Result<Self, AutosarAbstractionError> {
187        let rule = parent.create_sub_element(ElementName::DataConstrRule)?;
188        let constrs = match rule_type {
189            DataConstrType::Internal => rule.create_sub_element(ElementName::InternalConstrs)?,
190            DataConstrType::Physical => rule.create_sub_element(ElementName::PhysConstrs)?,
191        };
192
193        if let Some(lower_limit) = lower_limit {
194            constrs
195                .create_sub_element(ElementName::LowerLimit)?
196                .set_character_data(lower_limit)?;
197        }
198
199        if let Some(upper_limit) = upper_limit {
200            constrs
201                .create_sub_element(ElementName::UpperLimit)?
202                .set_character_data(upper_limit)?;
203        }
204
205        Ok(Self(rule))
206    }
207
208    /// get the constraint type
209    #[must_use]
210    pub fn rule_type(&self) -> DataConstrType {
211        if self.element().get_sub_element(ElementName::InternalConstrs).is_some() {
212            DataConstrType::Internal
213        } else {
214            DataConstrType::Physical
215        }
216    }
217
218    /// get the lower limit
219    #[must_use]
220    pub fn lower_limit(&self) -> Option<f64> {
221        self.element()
222            .get_sub_element(ElementName::InternalConstrs)
223            .or(self.element().get_sub_element(ElementName::PhysConstrs))?
224            .get_sub_element(ElementName::LowerLimit)?
225            .character_data()?
226            .parse_float()
227    }
228
229    /// get the upper limit
230    #[must_use]
231    pub fn upper_limit(&self) -> Option<f64> {
232        self.element()
233            .get_sub_element(ElementName::InternalConstrs)
234            .or(self.element().get_sub_element(ElementName::PhysConstrs))?
235            .get_sub_element(ElementName::UpperLimit)?
236            .character_data()?
237            .parse_float()
238    }
239}
240
241//#########################################################
242
243/// The type of a data constraint rule
244#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
245pub enum DataConstrType {
246    /// Internal value data constraint
247    Internal,
248    /// Physical value data constraint
249    Physical,
250}
251
252//#########################################################
253
254#[cfg(test)]
255mod test {
256    use super::*;
257    use crate::AutosarModelAbstraction;
258    use autosar_data::AutosarVersion;
259
260    #[test]
261    fn unit() {
262        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
263        let package = model.get_or_create_package("/Units").unwrap();
264
265        let unit = Unit::new("Unit", &package, Some("Unit Display")).unwrap();
266        assert_eq!(unit.display_name(), Some("Unit Display".to_string()));
267    }
268
269    #[test]
270    fn data_constr() {
271        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
272        let package = model.get_or_create_package("/DataConstraints").unwrap();
273
274        let data_constr = DataConstr::new("DataConstr", &package).unwrap();
275
276        let rule1 = data_constr
277            .create_data_constr_rule(DataConstrType::Internal, Some(1.0), Some(100.0))
278            .unwrap();
279        assert_eq!(rule1.rule_type(), DataConstrType::Internal);
280        assert_eq!(rule1.lower_limit(), Some(1.0));
281        assert_eq!(rule1.upper_limit(), Some(100.0));
282
283        let rule2 = data_constr
284            .create_data_constr_rule(DataConstrType::Physical, Some(2.0), Some(200.0))
285            .unwrap();
286        assert_eq!(rule2.rule_type(), DataConstrType::Physical);
287        assert_eq!(rule2.lower_limit(), Some(2.0));
288        assert_eq!(rule2.upper_limit(), Some(200.0));
289
290        let rules = data_constr.data_constr_rules().collect::<Vec<_>>();
291        assert_eq!(rules.len(), 2);
292    }
293
294    #[test]
295    fn autosar_data_type() {
296        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
297        let package = model.get_or_create_package("/DataTypes").unwrap();
298
299        let app_primitive = ApplicationPrimitiveDataType::new(
300            "Primitive",
301            &package,
302            ApplicationPrimitiveCategory::Value,
303            None,
304            None,
305            None,
306        )
307        .unwrap();
308        let app_array =
309            ApplicationArrayDataType::new("Array", &package, &app_primitive, ApplicationArraySize::Fixed(1)).unwrap();
310        let app_record = ApplicationRecordDataType::new("Record", &package).unwrap();
311        let base_type =
312            SwBaseType::new("uint8", &package, 8, BaseTypeEncoding::None, None, None, Some("uint8")).unwrap();
313        let impl_settings = ImplementationDataTypeSettings::Value {
314            name: "ImplValue".to_string(),
315            base_type: base_type.clone(),
316            compu_method: None,
317            data_constraint: None,
318        };
319        let impl_type = ImplementationDataType::new(&package, &impl_settings).unwrap();
320
321        let app_primitive2 = AutosarDataType::try_from(app_primitive.element().clone()).unwrap();
322        assert!(matches!(
323            app_primitive2,
324            AutosarDataType::ApplicationPrimitiveDataType(_)
325        ));
326        assert_eq!(app_primitive2.element(), app_primitive.element());
327
328        let app_array2 = AutosarDataType::try_from(app_array.element().clone()).unwrap();
329        assert!(matches!(app_array2, AutosarDataType::ApplicationArrayDataType(_)));
330        assert_eq!(app_array2.element(), app_array.element());
331
332        let app_record2 = AutosarDataType::try_from(app_record.element().clone()).unwrap();
333        assert!(matches!(app_record2, AutosarDataType::ApplicationRecordDataType(_)));
334        assert_eq!(app_record2.element(), app_record.element());
335
336        let impl_type2 = AutosarDataType::try_from(impl_type.element().clone()).unwrap();
337        assert!(matches!(impl_type2, AutosarDataType::ImplementationDataType(_)));
338        assert_eq!(impl_type2.element(), impl_type.element());
339    }
340}