autosar_data_abstraction/software_component/
mode.rs

1use std::str::FromStr;
2
3use crate::{
4    AbstractionElement, ArPackage, AutosarAbstractionError, Element, IdentifiableAbstractionElement,
5    abstraction_element,
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    /// Set the category of the mode declaration group
34    pub fn set_category(&self, category: Option<ModeDeclarationGroupCategory>) -> Result<(), AutosarAbstractionError> {
35        if let Some(category) = category {
36            self.element()
37                .get_or_create_sub_element(ElementName::Category)?
38                .set_character_data(category.to_string())?;
39        } else {
40            let _ = self.element().remove_sub_element_kind(ElementName::Category);
41        }
42        Ok(())
43    }
44
45    /// Get the category of the mode declaration group
46    #[must_use]
47    pub fn category(&self) -> Option<ModeDeclarationGroupCategory> {
48        let category = self
49            .element()
50            .get_sub_element(ElementName::Category)?
51            .character_data()?
52            .string_value()?;
53        ModeDeclarationGroupCategory::from_str(&category).ok()
54    }
55
56    /// Create a new mode declaration in the mode declaration group
57    pub fn create_mode_declaration(&self, name: &str) -> Result<ModeDeclaration, AutosarAbstractionError> {
58        let mode_declarations = self
59            .element()
60            .get_or_create_sub_element(ElementName::ModeDeclarations)?;
61        ModeDeclaration::new(name, &mode_declarations)
62    }
63
64    /// Iterate over all mode declarations in the mode declaration group
65    pub fn mode_declarations(&self) -> impl Iterator<Item = ModeDeclaration> + Send + 'static {
66        self.element()
67            .get_sub_element(ElementName::ModeDeclarations)
68            .into_iter()
69            .flat_map(|mode_declarations| mode_declarations.sub_elements())
70            .filter_map(|elem| ModeDeclaration::try_from(elem).ok())
71    }
72
73    /// Set the initial mode of the mode declaration group
74    ///
75    /// The initial mode is active before any mode is set.
76    /// This setting is required to be present and the referenced mode must be part of the mode declaration group.
77    pub fn set_initial_mode(&self, mode_declaration: &ModeDeclaration) -> Result<(), AutosarAbstractionError> {
78        if mode_declaration.element().named_parent()?.as_ref() != Some(self.element()) {
79            return Err(AutosarAbstractionError::InvalidParameter(
80                "Mode declaration is not part of the mode declaration group".to_string(),
81            ));
82        }
83        self.element()
84            .get_or_create_sub_element(ElementName::InitialModeRef)?
85            .set_reference_target(mode_declaration.element())?;
86        Ok(())
87    }
88
89    /// Get the initial mode of the mode declaration group
90    #[must_use]
91    pub fn initial_mode(&self) -> Option<ModeDeclaration> {
92        self.element()
93            .get_sub_element(ElementName::InitialModeRef)
94            .and_then(|elem| elem.get_reference_target().ok())
95            .and_then(|target| ModeDeclaration::try_from(target).ok())
96    }
97
98    /// set the onTransitionValue attribute of the mode declaration group
99    pub fn set_on_transition_value(&self, value: Option<u64>) -> Result<(), AutosarAbstractionError> {
100        if let Some(value) = value {
101            self.element()
102                .get_or_create_sub_element(ElementName::OnTransitionValue)?
103                .set_character_data(value)?;
104        } else {
105            let _ = self.element().remove_sub_element_kind(ElementName::OnTransitionValue);
106        }
107        Ok(())
108    }
109
110    /// Get the onTransitionValue attribute of the mode declaration group
111    #[must_use]
112    pub fn on_transition_value(&self) -> Option<u64> {
113        self.element()
114            .get_sub_element(ElementName::OnTransitionValue)?
115            .character_data()?
116            .parse_integer()
117    }
118}
119
120//##################################################################
121
122#[derive(Debug, Clone, PartialEq, Eq, Hash)]
123/// Category of mode declaration groupy, which defines the ordering of the modes in the group
124pub enum ModeDeclarationGroupCategory {
125    /// Ordering of the modes in the mode declaration group is alphabetic, and the modes may not set a value
126    AlphabeticOrder,
127    /// Ordering of modes in the mode declaration group is made explixit by the value, which must be set for each mode.
128    /// Additonally, the `on_transition_value` attribute must be set in this case.
129    ExplicitOrder,
130}
131
132impl std::fmt::Display for ModeDeclarationGroupCategory {
133    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134        match self {
135            ModeDeclarationGroupCategory::AlphabeticOrder => f.write_str("ALPHABETIC_ORDER"),
136            ModeDeclarationGroupCategory::ExplicitOrder => f.write_str("EXPLICIT_ORDER"),
137        }
138    }
139}
140
141impl std::str::FromStr for ModeDeclarationGroupCategory {
142    type Err = AutosarAbstractionError;
143
144    fn from_str(s: &str) -> Result<Self, Self::Err> {
145        match s {
146            "ALPHABETIC_ORDER" => Ok(ModeDeclarationGroupCategory::AlphabeticOrder),
147            "EXPLICIT_ORDER" => Ok(ModeDeclarationGroupCategory::ExplicitOrder),
148            _ => Err(AutosarAbstractionError::ValueConversionError {
149                value: s.to_string(),
150                dest: "ModeDeclarationGroupCategory".to_string(),
151            }),
152        }
153    }
154}
155
156//##################################################################
157
158/// A `ModeDeclaration` represents a mode declaration in a `ModeDeclarationGroup`
159#[derive(Debug, Clone, PartialEq, Eq, Hash)]
160pub struct ModeDeclaration(Element);
161abstraction_element!(ModeDeclaration, ModeDeclaration);
162impl IdentifiableAbstractionElement for ModeDeclaration {}
163
164impl ModeDeclaration {
165    /// Create a new `ModeDeclaration`
166    fn new(name: &str, parent_element: &Element) -> Result<Self, AutosarAbstractionError> {
167        let mode_declaration = parent_element.create_named_sub_element(ElementName::ModeDeclaration, name)?;
168        Ok(Self(mode_declaration))
169    }
170
171    /// Set the value that should be used to represent the mode in the RTE
172    pub fn set_value(&self, value: Option<u64>) -> Result<(), AutosarAbstractionError> {
173        if let Some(value) = value {
174            self.element()
175                .get_or_create_sub_element(ElementName::Value)?
176                .set_character_data(value)?;
177        } else {
178            let _ = self.element().remove_sub_element_kind(ElementName::Value);
179        }
180        Ok(())
181    }
182
183    /// Get the value that should be used to represent the mode in the RTE
184    #[must_use]
185    pub fn value(&self) -> Option<u64> {
186        self.element()
187            .get_sub_element(ElementName::Value)?
188            .character_data()?
189            .parse_integer()
190    }
191
192    /// Get the mode declaration group that this mode declaration belongs to
193    pub fn mode_declaration_group(&self) -> Result<ModeDeclarationGroup, AutosarAbstractionError> {
194        let Some(parent) = self.element().named_parent()? else {
195            return Err(AutosarAbstractionError::InvalidParameter(
196                "Mode declaration has no parent".to_string(),
197            ));
198        };
199        ModeDeclarationGroup::try_from(parent)
200    }
201}
202
203//##################################################################
204
205#[cfg(test)]
206mod test {
207    use super::*;
208    use crate::AutosarModelAbstraction;
209    use autosar_data::AutosarVersion;
210
211    #[test]
212    fn mode_declaration_group() {
213        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
214        let package = model.get_or_create_package("/Pkg").unwrap();
215        let mode_declaration_group = package.create_mode_declaration_group("test_group", None).unwrap();
216
217        assert_eq!(mode_declaration_group.category(), None);
218        assert_eq!(mode_declaration_group.name().unwrap(), "test_group");
219
220        mode_declaration_group
221            .set_category(Some(ModeDeclarationGroupCategory::ExplicitOrder))
222            .unwrap();
223        assert_eq!(
224            mode_declaration_group.category(),
225            Some(ModeDeclarationGroupCategory::ExplicitOrder)
226        );
227        mode_declaration_group
228            .set_category(Some(ModeDeclarationGroupCategory::AlphabeticOrder))
229            .unwrap();
230        assert_eq!(
231            mode_declaration_group.category(),
232            Some(ModeDeclarationGroupCategory::AlphabeticOrder)
233        );
234
235        assert_eq!(mode_declaration_group.on_transition_value(), None);
236        mode_declaration_group.set_on_transition_value(Some(42)).unwrap();
237        assert_eq!(mode_declaration_group.on_transition_value(), Some(42));
238        mode_declaration_group.set_on_transition_value(None).unwrap();
239        assert_eq!(mode_declaration_group.on_transition_value(), None);
240
241        let mode_declaration = mode_declaration_group.create_mode_declaration("test_mode").unwrap();
242        mode_declaration.set_value(Some(1)).unwrap();
243        assert_eq!(mode_declaration.value(), Some(1));
244
245        assert_eq!(mode_declaration_group.mode_declarations().count(), 1);
246
247        mode_declaration_group.set_initial_mode(&mode_declaration).unwrap();
248        assert_eq!(mode_declaration_group.initial_mode().unwrap(), mode_declaration);
249
250        let mode_declaration_group_2 = package.create_mode_declaration_group("test_group_2", None).unwrap();
251        mode_declaration_group_2
252            .set_initial_mode(&mode_declaration)
253            .unwrap_err(); // should fail, because mode_declaration is not part of the group
254    }
255}