autosar_data_abstraction/software_component/
mode.rs

1use std::str::FromStr;
2
3use crate::{
4    AbstractionElement, ArPackage, AutosarAbstractionError, Element, IdentifiableAbstractionElement,
5    abstraction_element, get_reference_parents, software_component::SwcModeSwitchEvent,
6};
7use autosar_data::ElementName;
8
9//##################################################################
10
11/// A `ModeDeclarationGroup` is a collection of mode declarations.
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13pub struct ModeDeclarationGroup(Element);
14abstraction_element!(ModeDeclarationGroup, ModeDeclarationGroup);
15impl IdentifiableAbstractionElement for ModeDeclarationGroup {}
16
17impl ModeDeclarationGroup {
18    /// Create a new `ModeDeclarationGroup`
19    pub(crate) fn new(
20        name: &str,
21        package: &ArPackage,
22        category: Option<ModeDeclarationGroupCategory>,
23    ) -> Result<Self, AutosarAbstractionError> {
24        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
25        let mode_declaration_group_elem = elements.create_named_sub_element(ElementName::ModeDeclarationGroup, name)?;
26        let mode_declaration_group = Self(mode_declaration_group_elem);
27
28        mode_declaration_group.set_category(category)?;
29
30        Ok(mode_declaration_group)
31    }
32
33    /// Remove this `ModeDeclarationGroup` from the model
34    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
35        for mode_declaration in self.mode_declarations() {
36            mode_declaration.remove(deep)?;
37        }
38        AbstractionElement::remove(self, deep)
39    }
40
41    /// Set the category of the mode declaration group
42    pub fn set_category(&self, category: Option<ModeDeclarationGroupCategory>) -> Result<(), AutosarAbstractionError> {
43        if let Some(category) = category {
44            self.element()
45                .get_or_create_sub_element(ElementName::Category)?
46                .set_character_data(category.to_string())?;
47        } else {
48            let _ = self.element().remove_sub_element_kind(ElementName::Category);
49        }
50        Ok(())
51    }
52
53    /// Get the category of the mode declaration group
54    #[must_use]
55    pub fn category(&self) -> Option<ModeDeclarationGroupCategory> {
56        let category = self
57            .element()
58            .get_sub_element(ElementName::Category)?
59            .character_data()?
60            .string_value()?;
61        ModeDeclarationGroupCategory::from_str(&category).ok()
62    }
63
64    /// Create a new mode declaration in the mode declaration group
65    pub fn create_mode_declaration(&self, name: &str) -> Result<ModeDeclaration, AutosarAbstractionError> {
66        let mode_declarations = self
67            .element()
68            .get_or_create_sub_element(ElementName::ModeDeclarations)?;
69        ModeDeclaration::new(name, &mode_declarations)
70    }
71
72    /// Iterate over all mode declarations in the mode declaration group
73    pub fn mode_declarations(&self) -> impl Iterator<Item = ModeDeclaration> + Send + use<> {
74        self.element()
75            .get_sub_element(ElementName::ModeDeclarations)
76            .into_iter()
77            .flat_map(|mode_declarations| mode_declarations.sub_elements())
78            .filter_map(|elem| ModeDeclaration::try_from(elem).ok())
79    }
80
81    /// Set the initial mode of the mode declaration group
82    ///
83    /// The initial mode is active before any mode is set.
84    /// This setting is required to be present and the referenced mode must be part of the mode declaration group.
85    pub fn set_initial_mode(&self, mode_declaration: &ModeDeclaration) -> Result<(), AutosarAbstractionError> {
86        if mode_declaration.element().named_parent()?.as_ref() != Some(self.element()) {
87            return Err(AutosarAbstractionError::InvalidParameter(
88                "Mode declaration is not part of the mode declaration group".to_string(),
89            ));
90        }
91        self.element()
92            .get_or_create_sub_element(ElementName::InitialModeRef)?
93            .set_reference_target(mode_declaration.element())?;
94        Ok(())
95    }
96
97    /// Get the initial mode of the mode declaration group
98    #[must_use]
99    pub fn initial_mode(&self) -> Option<ModeDeclaration> {
100        self.element()
101            .get_sub_element(ElementName::InitialModeRef)
102            .and_then(|elem| elem.get_reference_target().ok())
103            .and_then(|target| ModeDeclaration::try_from(target).ok())
104    }
105
106    /// set the onTransitionValue attribute of the mode declaration group
107    pub fn set_on_transition_value(&self, value: Option<u64>) -> Result<(), AutosarAbstractionError> {
108        if let Some(value) = value {
109            self.element()
110                .get_or_create_sub_element(ElementName::OnTransitionValue)?
111                .set_character_data(value)?;
112        } else {
113            let _ = self.element().remove_sub_element_kind(ElementName::OnTransitionValue);
114        }
115        Ok(())
116    }
117
118    /// Get the onTransitionValue attribute of the mode declaration group
119    #[must_use]
120    pub fn on_transition_value(&self) -> Option<u64> {
121        self.element()
122            .get_sub_element(ElementName::OnTransitionValue)?
123            .character_data()?
124            .parse_integer()
125    }
126}
127
128//##################################################################
129
130#[derive(Debug, Clone, PartialEq, Eq, Hash)]
131/// Category of mode declaration groupy, which defines the ordering of the modes in the group
132pub enum ModeDeclarationGroupCategory {
133    /// Ordering of the modes in the mode declaration group is alphabetic, and the modes may not set a value
134    AlphabeticOrder,
135    /// Ordering of modes in the mode declaration group is made explixit by the value, which must be set for each mode.
136    /// Additonally, the `on_transition_value` attribute must be set in this case.
137    ExplicitOrder,
138}
139
140impl std::fmt::Display for ModeDeclarationGroupCategory {
141    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142        match self {
143            ModeDeclarationGroupCategory::AlphabeticOrder => f.write_str("ALPHABETIC_ORDER"),
144            ModeDeclarationGroupCategory::ExplicitOrder => f.write_str("EXPLICIT_ORDER"),
145        }
146    }
147}
148
149impl std::str::FromStr for ModeDeclarationGroupCategory {
150    type Err = AutosarAbstractionError;
151
152    fn from_str(s: &str) -> Result<Self, Self::Err> {
153        match s {
154            "ALPHABETIC_ORDER" => Ok(ModeDeclarationGroupCategory::AlphabeticOrder),
155            "EXPLICIT_ORDER" => Ok(ModeDeclarationGroupCategory::ExplicitOrder),
156            _ => Err(AutosarAbstractionError::ValueConversionError {
157                value: s.to_string(),
158                dest: "ModeDeclarationGroupCategory".to_string(),
159            }),
160        }
161    }
162}
163
164//##################################################################
165
166/// A `ModeDeclaration` represents a mode declaration in a `ModeDeclarationGroup`
167#[derive(Debug, Clone, PartialEq, Eq, Hash)]
168pub struct ModeDeclaration(Element);
169abstraction_element!(ModeDeclaration, ModeDeclaration);
170impl IdentifiableAbstractionElement for ModeDeclaration {}
171
172impl ModeDeclaration {
173    /// Create a new `ModeDeclaration`
174    fn new(name: &str, parent_element: &Element) -> Result<Self, AutosarAbstractionError> {
175        let mode_declaration = parent_element.create_named_sub_element(ElementName::ModeDeclaration, name)?;
176        Ok(Self(mode_declaration))
177    }
178
179    /// Remove this `ModeDeclaration` from the model
180    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
181        let ref_parents = get_reference_parents(self.element())?;
182
183        AbstractionElement::remove(self, deep)?;
184
185        for (named_parent, _parent) in ref_parents {
186            if named_parent.element_name() == ElementName::SwcModeSwitchEvent
187                && let Ok(swc_mode_switch_event) = SwcModeSwitchEvent::try_from(named_parent)
188            {
189                swc_mode_switch_event.remove(deep)?;
190            }
191        }
192
193        Ok(())
194    }
195
196    /// Set the value that should be used to represent the mode in the RTE
197    pub fn set_value(&self, value: Option<u64>) -> Result<(), AutosarAbstractionError> {
198        if let Some(value) = value {
199            self.element()
200                .get_or_create_sub_element(ElementName::Value)?
201                .set_character_data(value)?;
202        } else {
203            let _ = self.element().remove_sub_element_kind(ElementName::Value);
204        }
205        Ok(())
206    }
207
208    /// Get the value that should be used to represent the mode in the RTE
209    #[must_use]
210    pub fn value(&self) -> Option<u64> {
211        self.element()
212            .get_sub_element(ElementName::Value)?
213            .character_data()?
214            .parse_integer()
215    }
216
217    /// Get the mode declaration group that this mode declaration belongs to
218    pub fn mode_declaration_group(&self) -> Result<ModeDeclarationGroup, AutosarAbstractionError> {
219        let Some(parent) = self.element().named_parent()? else {
220            return Err(AutosarAbstractionError::InvalidParameter(
221                "Mode declaration has no parent".to_string(),
222            ));
223        };
224        ModeDeclarationGroup::try_from(parent)
225    }
226}
227
228//##################################################################
229
230#[cfg(test)]
231mod test {
232    use super::*;
233    use crate::{
234        AutosarModelAbstraction,
235        software_component::{AbstractSwComponentType, AtomicSwComponentType, ModeActivationKind},
236    };
237    use autosar_data::AutosarVersion;
238
239    #[test]
240    fn mode_declaration_group() {
241        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
242        let package = model.get_or_create_package("/Pkg").unwrap();
243        let mode_declaration_group = package.create_mode_declaration_group("test_group", None).unwrap();
244
245        assert_eq!(mode_declaration_group.category(), None);
246        assert_eq!(mode_declaration_group.name().unwrap(), "test_group");
247
248        mode_declaration_group
249            .set_category(Some(ModeDeclarationGroupCategory::ExplicitOrder))
250            .unwrap();
251        assert_eq!(
252            mode_declaration_group.category(),
253            Some(ModeDeclarationGroupCategory::ExplicitOrder)
254        );
255        mode_declaration_group
256            .set_category(Some(ModeDeclarationGroupCategory::AlphabeticOrder))
257            .unwrap();
258        assert_eq!(
259            mode_declaration_group.category(),
260            Some(ModeDeclarationGroupCategory::AlphabeticOrder)
261        );
262
263        assert_eq!(mode_declaration_group.on_transition_value(), None);
264        mode_declaration_group.set_on_transition_value(Some(42)).unwrap();
265        assert_eq!(mode_declaration_group.on_transition_value(), Some(42));
266        mode_declaration_group.set_on_transition_value(None).unwrap();
267        assert_eq!(mode_declaration_group.on_transition_value(), None);
268
269        let mode_declaration = mode_declaration_group.create_mode_declaration("test_mode").unwrap();
270        mode_declaration.set_value(Some(1)).unwrap();
271        assert_eq!(mode_declaration.value(), Some(1));
272
273        assert_eq!(mode_declaration_group.mode_declarations().count(), 1);
274
275        mode_declaration_group.set_initial_mode(&mode_declaration).unwrap();
276        assert_eq!(mode_declaration_group.initial_mode().unwrap(), mode_declaration);
277
278        let mode_declaration_group_2 = package.create_mode_declaration_group("test_group_2", None).unwrap();
279        mode_declaration_group_2
280            .set_initial_mode(&mode_declaration)
281            .unwrap_err(); // should fail, because mode_declaration is not part of the group
282    }
283
284    #[test]
285    fn remove_mode_declaration() {
286        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
287        let package = model.get_or_create_package("/Pkg").unwrap();
288
289        // create a mode group
290        let mode_declaration_group = package.create_mode_declaration_group("test_group", None).unwrap();
291        let mode_declaration = mode_declaration_group.create_mode_declaration("test_mode").unwrap();
292
293        // create a mode switch interface referencing the mode declaration group
294        let mode_switch_interface = package.create_mode_switch_interface("TestModeSwitchInterface").unwrap();
295        let _mode_if_group = mode_switch_interface
296            .create_mode_group("ModeDeclarationGroup", &mode_declaration_group)
297            .unwrap();
298
299        // create a SWC type with a mode port
300        let swc_type = package.create_application_sw_component_type("TestSwcType").unwrap();
301        let port = swc_type.create_r_port("RPort", &mode_switch_interface).unwrap();
302
303        // create SWC internal behavior with a mode switch event referencing the mode declaration
304        let ib = swc_type.create_swc_internal_behavior("InternalBehavior").unwrap();
305        let runnable = ib.create_runnable_entity("RunnableEntity").unwrap();
306        let _swc_mode_switch_event = ib
307            .create_mode_switch_event(
308                "ModeSwitchEvent",
309                &runnable,
310                ModeActivationKind::OnEntry,
311                &port,
312                &mode_declaration,
313                None,
314            )
315            .unwrap();
316
317        assert_eq!(mode_declaration_group.mode_declarations().count(), 1);
318
319        mode_declaration.remove(true).unwrap();
320
321        // after removal, the mode declaration group should have no mode declarations
322        assert_eq!(mode_declaration_group.mode_declarations().count(), 0);
323        // the mode switch event should also be removed, as it became invalid when the mode declaration was removed
324        assert_eq!(ib.events().count(), 0);
325    }
326}