autosar_data_abstraction/software_component/internal_behavior/
mod.rs

1use crate::{
2    AbstractionElement, AutosarAbstractionError, Element, IdentifiableAbstractionElement, abstraction_element,
3    datatype::DataTypeMappingSet,
4    software_component::{
5        ClientServerOperation, ModeDeclaration, ModeGroup, PPortPrototype, PortPrototype, RPortPrototype,
6        SwComponentType, VariableDataPrototype,
7    },
8};
9use autosar_data::ElementName;
10
11mod rte_event;
12
13pub use rte_event::*;
14
15//##################################################################
16
17/// The `SwcInternalBehavior` of a software component type describes the
18/// details that are needed to generate the RTE.
19#[derive(Debug, Clone, PartialEq, Eq, Hash)]
20pub struct SwcInternalBehavior(Element);
21abstraction_element!(SwcInternalBehavior, SwcInternalBehavior);
22impl IdentifiableAbstractionElement for SwcInternalBehavior {}
23
24impl SwcInternalBehavior {
25    pub(crate) fn new(name: &str, parent: &Element) -> Result<Self, AutosarAbstractionError> {
26        let swc_internal_behavior = parent.create_named_sub_element(ElementName::SwcInternalBehavior, name)?;
27
28        Ok(Self(swc_internal_behavior))
29    }
30
31    /// Get the software component type that contains the `SwcInternalBehavior`
32    #[must_use]
33    pub fn sw_component_type(&self) -> Option<SwComponentType> {
34        let parent = self.element().named_parent().ok()??;
35        SwComponentType::try_from(parent).ok()
36    }
37
38    /// Create a new `RunnableEntity` in the `SwcInternalBehavior`
39    pub fn create_runnable_entity(&self, name: &str) -> Result<RunnableEntity, AutosarAbstractionError> {
40        let runnalbles_elem = self.element().get_or_create_sub_element(ElementName::Runnables)?;
41        RunnableEntity::new(name, &runnalbles_elem)
42    }
43
44    /// Get an iterator over all `RunnableEntities` in the `SwcInternalBehavior`
45    pub fn runnable_entities(&self) -> impl Iterator<Item = RunnableEntity> + Send + 'static {
46        self.element()
47            .get_sub_element(ElementName::Runnables)
48            .into_iter()
49            .flat_map(|runnables| runnables.sub_elements())
50            .filter_map(|elem| RunnableEntity::try_from(elem).ok())
51    }
52
53    /// Add a reference to a `DataTypeMappingSet` to the `SwcInternalBehavior`
54    pub fn add_data_type_mapping_set(
55        &self,
56        data_type_mapping_set: &DataTypeMappingSet,
57    ) -> Result<(), AutosarAbstractionError> {
58        self.element()
59            .get_or_create_sub_element(ElementName::DataTypeMappingRefs)?
60            .create_sub_element(ElementName::DataTypeMappingRef)?
61            .set_reference_target(data_type_mapping_set.element())?;
62        Ok(())
63    }
64
65    /// create an iterator over all `DataTypeMappingSet` references in the `SwcInternalBehavior`
66    pub fn data_type_mapping_sets(&self) -> impl Iterator<Item = DataTypeMappingSet> + Send + 'static {
67        self.element()
68            .get_sub_element(ElementName::DataTypeMappingRefs)
69            .into_iter()
70            .flat_map(|refs| {
71                refs.sub_elements()
72                    .filter_map(|elem| elem.get_reference_target().ok())
73                    .filter_map(|elem| DataTypeMappingSet::try_from(elem).ok())
74            })
75    }
76
77    /// Create a new `InitEvent` in the `SwcInternalBehavior`
78    pub fn create_init_event(
79        &self,
80        name: &str,
81        runnable: &RunnableEntity,
82    ) -> Result<InitEvent, AutosarAbstractionError> {
83        let events = self.element().get_or_create_sub_element(ElementName::Events)?;
84        InitEvent::new(name, &events, runnable)
85    }
86
87    /// Create a new `OperationInvokedEvent` in the `SwcInternalBehavior` when a server operation is invoked
88    pub fn create_operation_invoked_event(
89        &self,
90        name: &str,
91        runnable: &RunnableEntity,
92        client_server_operation: &ClientServerOperation,
93        context_p_port: &PPortPrototype,
94    ) -> Result<OperationInvokedEvent, AutosarAbstractionError> {
95        let events = self.element().get_or_create_sub_element(ElementName::Events)?;
96        OperationInvokedEvent::new(name, &events, runnable, client_server_operation, context_p_port)
97    }
98
99    /// Create a timing event that triggers a runnable in the `SwcInternalBehavior` based on a timer
100    pub fn create_timing_event(
101        &self,
102        name: &str,
103        runnable: &RunnableEntity,
104        period: f64,
105    ) -> Result<TimingEvent, AutosarAbstractionError> {
106        let events = self.element().get_or_create_sub_element(ElementName::Events)?;
107        TimingEvent::new(name, &events, runnable, period)
108    }
109
110    /// create a background event that triggers a runnable in the `SwcInternalBehavior` for background processing
111    pub fn create_background_event(
112        &self,
113        name: &str,
114        runnable: &RunnableEntity,
115    ) -> Result<BackgroundEvent, AutosarAbstractionError> {
116        let events = self.element().get_or_create_sub_element(ElementName::Events)?;
117        BackgroundEvent::new(name, &events, runnable)
118    }
119
120    /// create a data received event that triggers a runnable in the `SwcInternalBehavior` when data is received
121    pub fn create_data_received_event<T: Into<PortPrototype> + Clone>(
122        &self,
123        name: &str,
124        runnable: &RunnableEntity,
125        variable_data_prototype: &VariableDataPrototype,
126        context_port: &T,
127    ) -> Result<DataReceivedEvent, AutosarAbstractionError> {
128        let events = self.element().get_or_create_sub_element(ElementName::Events)?;
129        DataReceivedEvent::new(name, &events, runnable, variable_data_prototype, context_port)
130    }
131
132    /// create an os task execution event that triggers a runnable in the `SwcInternalBehavior` every time the task is executed
133    pub fn create_os_task_execution_event(
134        &self,
135        name: &str,
136        runnable: &RunnableEntity,
137    ) -> Result<OsTaskExecutionEvent, AutosarAbstractionError> {
138        let events = self.element().get_or_create_sub_element(ElementName::Events)?;
139        OsTaskExecutionEvent::new(name, &events, runnable)
140    }
141
142    /// create a mode switch event that triggers a runnable in the `SwcInternalBehavior` when the mode is switched
143    pub fn create_mode_switch_event<T: Into<PortPrototype> + Clone>(
144        &self,
145        name: &str,
146        runnable: &RunnableEntity,
147        activation: ModeActivationKind,
148        context_port: &T,
149        mode_declaration: &ModeDeclaration,
150        second_mode_declaration: Option<&ModeDeclaration>,
151    ) -> Result<SwcModeSwitchEvent, AutosarAbstractionError> {
152        let events = self.element().get_or_create_sub_element(ElementName::Events)?;
153        SwcModeSwitchEvent::new(
154            name,
155            &events,
156            runnable,
157            activation,
158            context_port,
159            mode_declaration,
160            second_mode_declaration,
161        )
162    }
163
164    /// create an iterator over all events in the `SwcInternalBehavior`
165    pub fn events(&self) -> impl Iterator<Item = RTEEvent> + Send + 'static {
166        self.element()
167            .get_sub_element(ElementName::Events)
168            .into_iter()
169            .flat_map(|events| events.sub_elements())
170            .filter_map(|elem| RTEEvent::try_from(elem).ok())
171    }
172}
173
174//##################################################################
175
176/// A `RunnableEntity` is a function that can be executed by the RTE
177#[derive(Debug, Clone, PartialEq, Eq, Hash)]
178pub struct RunnableEntity(Element);
179abstraction_element!(RunnableEntity, RunnableEntity);
180impl IdentifiableAbstractionElement for RunnableEntity {}
181
182impl RunnableEntity {
183    pub(crate) fn new(name: &str, parent: &Element) -> Result<Self, AutosarAbstractionError> {
184        let runnable_entity = parent.create_named_sub_element(ElementName::RunnableEntity, name)?;
185
186        Ok(Self(runnable_entity))
187    }
188
189    /// Get the `SwcInternalBehavior` that contains the `RunnableEntity`
190    #[must_use]
191    pub fn swc_internal_behavior(&self) -> Option<SwcInternalBehavior> {
192        let parent = self.element().named_parent().ok()??;
193        SwcInternalBehavior::try_from(parent).ok()
194    }
195
196    /// Iterate over all events that can trigger the `RunnableEntity`
197    #[must_use]
198    pub fn events(&self) -> Vec<RTEEvent> {
199        let model_result = self.element().model();
200        let path_result = self.element().path();
201        if let (Ok(model), Ok(path)) = (model_result, path_result) {
202            model
203                .get_references_to(&path)
204                .iter()
205                .filter_map(|e| {
206                    e.upgrade()
207                        .and_then(|ref_elem| ref_elem.named_parent().ok().flatten())
208                        .and_then(|elem| RTEEvent::try_from(elem).ok())
209                })
210                .collect()
211        } else {
212            vec![]
213        }
214    }
215
216    /// add implicit read access to a data element of a sender-receiver `PortPrototype`
217    ///
218    /// this results in `Rte_IRead_<port>_<data_element>` being generated
219    pub fn create_data_read_access<T: Into<PortPrototype> + Clone>(
220        &self,
221        name: &str,
222        data_element: &VariableDataPrototype,
223        context_port: &T,
224    ) -> Result<VariableAccess, AutosarAbstractionError> {
225        let data_accesses = self.element().get_or_create_sub_element(ElementName::DataReadAccesss)?;
226        VariableAccess::new(name, &data_accesses, data_element, &context_port.clone().into())
227    }
228
229    /// iterate over all data read accesses
230    pub fn data_read_accesses(&self) -> impl Iterator<Item = VariableAccess> + Send + 'static {
231        self.element()
232            .get_sub_element(ElementName::DataReadAccesss)
233            .into_iter()
234            .flat_map(|data_accesses| data_accesses.sub_elements())
235            .filter_map(|elem| VariableAccess::try_from(elem).ok())
236    }
237
238    /// add implicit write access to a data element of a sender-receiver `PortPrototype`
239    ///
240    /// this results in `Rte_IWrite_<port>_<data_element>` being generated
241    pub fn create_data_write_access<T: Into<PortPrototype> + Clone>(
242        &self,
243        name: &str,
244        data_element: &VariableDataPrototype,
245        context_port: &T,
246    ) -> Result<VariableAccess, AutosarAbstractionError> {
247        let data_accesses = self
248            .element()
249            .get_or_create_sub_element(ElementName::DataWriteAccesss)?;
250        VariableAccess::new(name, &data_accesses, data_element, &context_port.clone().into())
251    }
252
253    /// iterate over all data write accesses
254    pub fn data_write_accesses(&self) -> impl Iterator<Item = VariableAccess> + Send + 'static {
255        self.element()
256            .get_sub_element(ElementName::DataWriteAccesss)
257            .into_iter()
258            .flat_map(|data_accesses| data_accesses.sub_elements())
259            .filter_map(|elem| VariableAccess::try_from(elem).ok())
260    }
261
262    /// add a data send point to a data element of a sender-receiver `PortPrototype`
263    pub fn create_data_send_point<T: Into<PortPrototype> + Clone>(
264        &self,
265        name: &str,
266        data_element: &VariableDataPrototype,
267        context_port: &T,
268    ) -> Result<VariableAccess, AutosarAbstractionError> {
269        let data_accesses = self.element().get_or_create_sub_element(ElementName::DataSendPoints)?;
270        VariableAccess::new(name, &data_accesses, data_element, &context_port.clone().into())
271    }
272
273    /// iterate over all data send points
274    pub fn data_send_points(&self) -> impl Iterator<Item = VariableAccess> + Send + 'static {
275        self.element()
276            .get_sub_element(ElementName::DataSendPoints)
277            .into_iter()
278            .flat_map(|data_accesses| data_accesses.sub_elements())
279            .filter_map(|elem| VariableAccess::try_from(elem).ok())
280    }
281
282    /// add explicit read access by argument to a data element of a sender-receiver `PortPrototype`
283    ///
284    /// this results in `Rte_Read_<port>_<data_element>(DataType* data)` being generated
285    pub fn create_data_receive_point_by_argument<T: Into<PortPrototype> + Clone>(
286        &self,
287        name: &str,
288        data_element: &VariableDataPrototype,
289        context_port: &T,
290    ) -> Result<VariableAccess, AutosarAbstractionError> {
291        let data_accesses = self
292            .element()
293            .get_or_create_sub_element(ElementName::DataReceivePointByArguments)?;
294        VariableAccess::new(name, &data_accesses, data_element, &context_port.clone().into())
295    }
296
297    /// iterate over all data receive points by argument
298    pub fn data_receive_points_by_argument(&self) -> impl Iterator<Item = VariableAccess> + Send + 'static {
299        self.element()
300            .get_sub_element(ElementName::DataReceivePointByArguments)
301            .into_iter()
302            .flat_map(|data_accesses| data_accesses.sub_elements())
303            .filter_map(|elem| VariableAccess::try_from(elem).ok())
304    }
305
306    /// add explicit read access by value to a data element of a sender-receiver `PortPrototype`
307    pub fn create_data_receive_point_by_value<T: Into<PortPrototype> + Clone>(
308        &self,
309        name: &str,
310        data_element: &VariableDataPrototype,
311        context_port: &T,
312    ) -> Result<VariableAccess, AutosarAbstractionError> {
313        let data_accesses = self
314            .element()
315            .get_or_create_sub_element(ElementName::DataReceivePointByValues)?;
316        VariableAccess::new(name, &data_accesses, data_element, &context_port.clone().into())
317    }
318
319    /// iterate over all data receive points by value
320    pub fn data_receive_points_by_value(&self) -> impl Iterator<Item = VariableAccess> + Send + 'static {
321        self.element()
322            .get_sub_element(ElementName::DataReceivePointByValues)
323            .into_iter()
324            .flat_map(|data_accesses| data_accesses.sub_elements())
325            .filter_map(|elem| VariableAccess::try_from(elem).ok())
326    }
327
328    /// create a synchronous server call point that allows the runnable to call a server operation
329    pub fn create_synchronous_server_call_point(
330        &self,
331        name: &str,
332        client_server_operation: &ClientServerOperation,
333        context_r_port: &RPortPrototype,
334    ) -> Result<SynchronousServerCallPoint, AutosarAbstractionError> {
335        let server_call_points = self
336            .element()
337            .get_or_create_sub_element(ElementName::ServerCallPoints)?;
338        SynchronousServerCallPoint::new(name, &server_call_points, client_server_operation, context_r_port)
339    }
340
341    /// iterate over all synchronous server call points
342    pub fn synchronous_server_call_points(&self) -> impl Iterator<Item = SynchronousServerCallPoint> + Send + 'static {
343        self.element()
344            .get_sub_element(ElementName::ServerCallPoints)
345            .into_iter()
346            .flat_map(|server_call_points| server_call_points.sub_elements())
347            .filter_map(|elem| SynchronousServerCallPoint::try_from(elem).ok())
348    }
349
350    /// create a mode access point that allows the runnable to access the current mode of a ModeDeclarationGroup
351    pub fn create_mode_access_point<T: Into<PortPrototype> + Clone>(
352        &self,
353        name: &str,
354        mode_group: &ModeGroup,
355        context_port: &T,
356    ) -> Result<ModeAccessPoint, AutosarAbstractionError> {
357        let mode_access_points = self
358            .element()
359            .get_or_create_sub_element(ElementName::ModeAccessPoints)?;
360        ModeAccessPoint::new(name, &mode_access_points, mode_group, &context_port.clone().into())
361    }
362
363    /// iterate over all mode access points
364    pub fn mode_access_points(&self) -> impl Iterator<Item = ModeAccessPoint> + Send + 'static {
365        self.element()
366            .get_sub_element(ElementName::ModeAccessPoints)
367            .into_iter()
368            .flat_map(|mode_access_points| mode_access_points.sub_elements())
369            .filter_map(|elem| ModeAccessPoint::try_from(elem).ok())
370    }
371
372    /// create a mode switch point that allows the runnable to switch modes in a ModeDeclarationGroup
373    pub fn create_mode_switch_point<T: Into<PortPrototype> + Clone>(
374        &self,
375        name: &str,
376        mode_group: &ModeGroup,
377        context_port: &T,
378    ) -> Result<ModeSwitchPoint, AutosarAbstractionError> {
379        let mode_switch_points = self
380            .element()
381            .get_or_create_sub_element(ElementName::ModeSwitchPoints)?;
382        ModeSwitchPoint::new(name, &mode_switch_points, mode_group, context_port)
383    }
384
385    /// iterate over all mode switch points
386    pub fn mode_switch_points(&self) -> impl Iterator<Item = ModeSwitchPoint> + Send + 'static {
387        self.element()
388            .get_sub_element(ElementName::ModeSwitchPoints)
389            .into_iter()
390            .flat_map(|mode_switch_points| mode_switch_points.sub_elements())
391            .filter_map(|elem| ModeSwitchPoint::try_from(elem).ok())
392    }
393}
394
395//##################################################################
396
397/// A `VariableAccess` allows a `RunnableEntity` to access a variable in various contexts
398#[derive(Debug, Clone, PartialEq, Eq, Hash)]
399pub struct VariableAccess(Element);
400abstraction_element!(VariableAccess, VariableAccess);
401impl IdentifiableAbstractionElement for VariableAccess {}
402
403impl VariableAccess {
404    pub(crate) fn new(
405        name: &str,
406        parent: &Element,
407        data_element: &VariableDataPrototype,
408        context_port: &PortPrototype,
409    ) -> Result<Self, AutosarAbstractionError> {
410        let variable_access = parent.create_named_sub_element(ElementName::VariableAccess, name)?;
411        let variable_access = Self(variable_access);
412        variable_access.set_accessed_variable(data_element, context_port)?;
413
414        Ok(variable_access)
415    }
416
417    /// Set the accessed variable
418    pub fn set_accessed_variable(
419        &self,
420        data_element: &VariableDataPrototype,
421        context_port: &PortPrototype,
422    ) -> Result<(), AutosarAbstractionError> {
423        // remove the old accessed variable
424        let _ = self.element().remove_sub_element_kind(ElementName::AccessedVariable);
425        let accessed_variable = self.element().create_sub_element(ElementName::AccessedVariable)?;
426        let autosar_variable_iref = accessed_variable.create_sub_element(ElementName::AutosarVariableIref)?;
427
428        autosar_variable_iref
429            .create_sub_element(ElementName::TargetDataPrototypeRef)?
430            .set_reference_target(data_element.element())?;
431        autosar_variable_iref
432            .create_sub_element(ElementName::PortPrototypeRef)?
433            .set_reference_target(context_port.element())?;
434        Ok(())
435    }
436
437    /// Get the accessed variable
438    #[must_use]
439    pub fn accessed_variable(&self) -> Option<(VariableDataPrototype, PortPrototype)> {
440        let accessed_variable = self.element().get_sub_element(ElementName::AccessedVariable)?;
441        let autosar_variable_iref = accessed_variable.get_sub_element(ElementName::AutosarVariableIref)?;
442        let data_prototype_ref = autosar_variable_iref.get_sub_element(ElementName::TargetDataPrototypeRef)?;
443        let port_prototype_ref = autosar_variable_iref.get_sub_element(ElementName::PortPrototypeRef)?;
444
445        let data_prototype = VariableDataPrototype::try_from(data_prototype_ref.get_reference_target().ok()?).ok()?;
446        let port_prototype = PortPrototype::try_from(port_prototype_ref.get_reference_target().ok()?).ok()?;
447
448        Some((data_prototype, port_prototype))
449    }
450
451    /// Get the `RunnableEntity` that contains the `VariableAccess`
452    #[must_use]
453    pub fn runnable_entity(&self) -> Option<RunnableEntity> {
454        let parent = self.element().named_parent().ok()??;
455        RunnableEntity::try_from(parent).ok()
456    }
457}
458
459//##################################################################
460
461/// A `SynchronousServerCallPoint` allows a `RunnableEntity` to call a server operation synchronously
462#[derive(Debug, Clone, PartialEq, Eq, Hash)]
463pub struct SynchronousServerCallPoint(Element);
464abstraction_element!(SynchronousServerCallPoint, SynchronousServerCallPoint);
465impl IdentifiableAbstractionElement for SynchronousServerCallPoint {}
466
467impl SynchronousServerCallPoint {
468    pub(crate) fn new(
469        name: &str,
470        parent: &Element,
471        client_server_operation: &ClientServerOperation,
472        context_r_port: &RPortPrototype,
473    ) -> Result<Self, AutosarAbstractionError> {
474        let synchronous_server_call_point =
475            parent.create_named_sub_element(ElementName::SynchronousServerCallPoint, name)?;
476        let synchronous_server_call_point = Self(synchronous_server_call_point);
477        synchronous_server_call_point.set_client_server_operation(client_server_operation, context_r_port)?;
478
479        Ok(synchronous_server_call_point)
480    }
481
482    /// Set the client server operation
483    pub fn set_client_server_operation(
484        &self,
485        client_server_operation: &ClientServerOperation,
486        context_r_port: &RPortPrototype,
487    ) -> Result<(), AutosarAbstractionError> {
488        // remove the old client server operation
489        let _ = self.element().remove_sub_element_kind(ElementName::OperationIref);
490        let operation_iref = self.element().create_sub_element(ElementName::OperationIref)?;
491
492        operation_iref
493            .create_sub_element(ElementName::TargetRequiredOperationRef)?
494            .set_reference_target(client_server_operation.element())?;
495        operation_iref
496            .create_sub_element(ElementName::ContextRPortRef)?
497            .set_reference_target(context_r_port.element())?;
498        Ok(())
499    }
500
501    /// Get the client server operation
502    #[must_use]
503    pub fn client_server_operation(&self) -> Option<(ClientServerOperation, RPortPrototype)> {
504        let operation_iref = self.element().get_sub_element(ElementName::OperationIref)?;
505        let required_operation_ref = operation_iref.get_sub_element(ElementName::TargetRequiredOperationRef)?;
506        let context_r_port_ref = operation_iref.get_sub_element(ElementName::ContextRPortRef)?;
507
508        let client_server_operation =
509            ClientServerOperation::try_from(required_operation_ref.get_reference_target().ok()?).ok()?;
510        let context_r_port = RPortPrototype::try_from(context_r_port_ref.get_reference_target().ok()?).ok()?;
511
512        Some((client_server_operation, context_r_port))
513    }
514
515    /// Get the `RunnableEntity` that contains the `SynchronousServerCallPoint`
516    #[must_use]
517    pub fn runnable_entity(&self) -> Option<RunnableEntity> {
518        let parent = self.element().named_parent().ok()??;
519        RunnableEntity::try_from(parent).ok()
520    }
521}
522
523//##################################################################
524
525/// A `ModeAccessPoint`provides the ability to access the current mode of a ModeDeclarationGroup
526#[derive(Debug, Clone, PartialEq, Eq, Hash)]
527pub struct ModeAccessPoint(Element);
528abstraction_element!(ModeAccessPoint, ModeAccessPoint);
529
530// not identifiable, but it has an Ident element instead
531impl IdentifiableAbstractionElement for ModeAccessPoint {
532    fn name(&self) -> Option<String> {
533        self.element()
534            .get_sub_element(ElementName::Ident)
535            .and_then(|elem| elem.item_name())
536    }
537
538    /// set the name of the mode access point
539    fn set_name(&self, name: &str) -> Result<(), AutosarAbstractionError> {
540        // rename an existing Ident element or create a new one
541        if let Some(ident_elem) = self.element().get_sub_element(ElementName::Ident) {
542            ident_elem.set_item_name(name)?;
543        } else {
544            self.element().create_named_sub_element(ElementName::Ident, name)?;
545        }
546        Ok(())
547    }
548}
549
550impl ModeAccessPoint {
551    pub(crate) fn new<T: Into<PortPrototype> + Clone>(
552        name: &str,
553        parent: &Element,
554        mode_group: &ModeGroup,
555        context_port: &T,
556    ) -> Result<Self, AutosarAbstractionError> {
557        let mode_access_point = parent.create_sub_element(ElementName::ModeAccessPoint)?;
558        let mode_access_point = Self(mode_access_point);
559        mode_access_point.set_name(name)?;
560        mode_access_point.set_mode_group(mode_group, context_port)?;
561
562        Ok(mode_access_point)
563    }
564
565    /// Set the mode group and context port for the mode access point
566    pub fn set_mode_group<T: Into<PortPrototype> + Clone>(
567        &self,
568        mode_group: &ModeGroup,
569        context_port: &T,
570    ) -> Result<(), AutosarAbstractionError> {
571        let context_port = context_port.clone().into();
572        // remove the old mode group iref
573        let _ = self.element().remove_sub_element_kind(ElementName::ModeGroupIref);
574        let mode_group_iref = self.element().create_sub_element(ElementName::ModeGroupIref)?;
575
576        let context_port_elem = context_port.element();
577        match context_port {
578            PortPrototype::R(_) | PortPrototype::PR(_) => {
579                let r_ref_container =
580                    mode_group_iref.create_sub_element(ElementName::RModeGroupInAtomicSwcInstanceRef)?;
581                r_ref_container
582                    .create_sub_element(ElementName::ContextRPortRef)?
583                    .set_reference_target(context_port_elem)?;
584                r_ref_container
585                    .create_sub_element(ElementName::TargetModeGroupRef)?
586                    .set_reference_target(mode_group.element())?;
587            }
588            PortPrototype::P(_) => {
589                let p_ref_container =
590                    mode_group_iref.create_sub_element(ElementName::PModeGroupInAtomicSwcInstanceRef)?;
591                p_ref_container
592                    .create_sub_element(ElementName::ContextPPortRef)?
593                    .set_reference_target(context_port_elem)?;
594                p_ref_container
595                    .create_sub_element(ElementName::TargetModeGroupRef)?
596                    .set_reference_target(mode_group.element())?;
597            }
598        }
599
600        Ok(())
601    }
602
603    /// Get the mode group and context port for the mode access point
604    #[must_use]
605    pub fn mode_group(&self) -> Option<(ModeGroup, PortPrototype)> {
606        let mode_group_iref = self.element().get_sub_element(ElementName::ModeGroupIref)?;
607
608        // Determine the context port reference based on the mode group reference type
609        if let Some(r_ref_container) = mode_group_iref.get_sub_element(ElementName::RModeGroupInAtomicSwcInstanceRef) {
610            let context_r_port = r_ref_container
611                .get_sub_element(ElementName::ContextRPortRef)?
612                .get_reference_target()
613                .ok()?;
614            let mode_group = r_ref_container
615                .get_sub_element(ElementName::TargetModeGroupRef)?
616                .get_reference_target()
617                .ok()?;
618            Some((
619                ModeGroup::try_from(mode_group).ok()?,
620                PortPrototype::try_from(context_r_port).ok()?,
621            ))
622        } else if let Some(p_ref_container) =
623            mode_group_iref.get_sub_element(ElementName::PModeGroupInAtomicSwcInstanceRef)
624        {
625            let context_p_port = p_ref_container
626                .get_sub_element(ElementName::ContextPPortRef)?
627                .get_reference_target()
628                .ok()?;
629            let mode_group = p_ref_container
630                .get_sub_element(ElementName::TargetModeGroupRef)?
631                .get_reference_target()
632                .ok()?;
633            Some((
634                ModeGroup::try_from(mode_group).ok()?,
635                PortPrototype::try_from(context_p_port).ok()?,
636            ))
637        } else {
638            None
639        }
640    }
641
642    /// Get the `RunnableEntity` that contains the `ModeAccessPoint`
643    #[must_use]
644    pub fn runnable_entity(&self) -> Option<RunnableEntity> {
645        let parent = self.element().named_parent().ok()??;
646        RunnableEntity::try_from(parent).ok()
647    }
648}
649
650//##################################################################
651
652/// A `ModeSwitchPoint` allows a `RunnableEntity` to switch modes in a ModeDeclarationGroup
653#[derive(Debug, Clone, PartialEq, Eq, Hash)]
654pub struct ModeSwitchPoint(Element);
655abstraction_element!(ModeSwitchPoint, ModeSwitchPoint);
656impl IdentifiableAbstractionElement for ModeSwitchPoint {}
657
658impl ModeSwitchPoint {
659    pub(crate) fn new<T: Into<PortPrototype> + Clone>(
660        name: &str,
661        parent: &Element,
662        mode_group: &ModeGroup,
663        context_port: &T,
664    ) -> Result<Self, AutosarAbstractionError> {
665        let mode_switch_point = parent.create_named_sub_element(ElementName::ModeSwitchPoint, name)?;
666        let mode_switch_point = Self(mode_switch_point);
667        mode_switch_point.set_mode_group(mode_group, context_port)?;
668
669        Ok(mode_switch_point)
670    }
671
672    /// Set the mode group and context port for the mode switch point
673    pub fn set_mode_group<T: Into<PortPrototype> + Clone>(
674        &self,
675        mode_group: &ModeGroup,
676        context_port: &T,
677    ) -> Result<(), AutosarAbstractionError> {
678        let context_port = context_port.clone().into();
679        if matches!(context_port, PortPrototype::R(_)) {
680            return Err(AutosarAbstractionError::InvalidParameter(
681                "ModeSwitchPoint context_port cannot be an R port".to_string(),
682            ));
683        }
684
685        // remove the old mode group iref
686        let _ = self.element().remove_sub_element_kind(ElementName::ModeGroupIref);
687        let mode_group_iref = self.element().create_sub_element(ElementName::ModeGroupIref)?;
688
689        mode_group_iref
690            .create_sub_element(ElementName::TargetModeGroupRef)?
691            .set_reference_target(mode_group.element())?;
692        mode_group_iref
693            .create_sub_element(ElementName::ContextPPortRef)?
694            .set_reference_target(context_port.element())?;
695
696        Ok(())
697    }
698
699    /// Get the mode group and context port for the mode switch point
700    #[must_use]
701    pub fn mode_group(&self) -> Option<(ModeGroup, PortPrototype)> {
702        let mode_group_iref = self.element().get_sub_element(ElementName::ModeGroupIref)?;
703        let mode_group = mode_group_iref
704            .get_sub_element(ElementName::TargetModeGroupRef)?
705            .get_reference_target()
706            .ok()?;
707        let context_port = mode_group_iref
708            .get_sub_element(ElementName::ContextPPortRef)?
709            .get_reference_target()
710            .ok()?;
711
712        let mode_declaration = ModeGroup::try_from(mode_group).ok()?;
713        let context_port = PortPrototype::try_from(context_port).ok()?;
714
715        Some((mode_declaration, context_port))
716    }
717
718    /// Get the `RunnableEntity` that contains the `ModeSwitchPoint`
719    #[must_use]
720    pub fn runnable_entity(&self) -> Option<RunnableEntity> {
721        let parent = self.element().named_parent().ok()??;
722        RunnableEntity::try_from(parent).ok()
723    }
724}
725
726//##################################################################
727
728#[cfg(test)]
729mod test {
730    use super::*;
731    use crate::{
732        AbstractionElement, AutosarModelAbstraction,
733        datatype::ApplicationPrimitiveCategory,
734        software_component::{AbstractRTEEvent, AbstractSwComponentType, AtomicSwComponentType},
735    };
736    use autosar_data::{AutosarVersion, EnumItem};
737
738    #[test]
739    fn swc_internal_behavior() {
740        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
741        let package = model.get_or_create_package("/package").unwrap();
742
743        // create a client-server interface
744        let client_server_interface = package.create_client_server_interface("ClientServerInterface").unwrap();
745        let operation = client_server_interface.create_operation("TestOperation").unwrap();
746
747        // create a software component type with an internal behavior
748        let app_swc = package
749            .create_application_sw_component_type("AppSwComponentType")
750            .unwrap();
751        let p_port = app_swc.create_p_port("p_port", &client_server_interface).unwrap();
752        let swc_internal_behavior = app_swc
753            .create_swc_internal_behavior("AppSwComponentType_InternalBehavior")
754            .unwrap();
755        assert_eq!(app_swc.swc_internal_behaviors().count(), 1);
756        assert_eq!(swc_internal_behavior.sw_component_type().unwrap(), app_swc.into());
757
758        // create two runnable entities
759        let runnable1 = swc_internal_behavior.create_runnable_entity("Runnable1").unwrap();
760        assert_eq!(runnable1.swc_internal_behavior().unwrap(), swc_internal_behavior);
761        let runnable2 = swc_internal_behavior.create_runnable_entity("Runnable2").unwrap();
762        assert_eq!(swc_internal_behavior.runnable_entities().count(), 2);
763
764        // create an init event, which triggers runnable1
765        let init_event = swc_internal_behavior
766            .create_init_event("InitEvent", &runnable1)
767            .unwrap();
768        assert_eq!(init_event.runnable_entity().unwrap(), runnable1);
769
770        // create an operation invoked event, which triggers runnable1
771        let op_invoked_event = swc_internal_behavior
772            .create_operation_invoked_event("OpInvokedEvent", &runnable1, &operation, &p_port)
773            .unwrap();
774        let (op_invoked_event_operation, context_p_port) = op_invoked_event.client_server_operation().unwrap();
775        assert_eq!(op_invoked_event_operation, operation);
776        assert_eq!(context_p_port, p_port);
777        assert_eq!(op_invoked_event.runnable_entity().unwrap(), runnable1);
778
779        // create a background event, which triggers runnable1
780        let background_event = swc_internal_behavior
781            .create_background_event("BackgroundEvent", &runnable1)
782            .unwrap();
783        assert_eq!(background_event.runnable_entity().unwrap(), runnable1);
784
785        // create an os task execution event, which triggers runnable1
786        let os_task_execution_event = swc_internal_behavior
787            .create_os_task_execution_event("OsTaskExecutionEvent", &runnable1)
788            .unwrap();
789        assert_eq!(os_task_execution_event.runnable_entity().unwrap(), runnable1);
790
791        // create a timing event, which triggers runnable2
792        let timing_event = swc_internal_behavior
793            .create_timing_event("TimingEvent", &runnable2, 0.1)
794            .unwrap();
795        assert_eq!(timing_event.period().unwrap(), 0.1);
796        assert_eq!(timing_event.runnable_entity().unwrap(), runnable2);
797        assert_eq!(timing_event.swc_internal_behavior().unwrap(), swc_internal_behavior);
798
799        // there should be 3 events in the swc_internal_behavior
800        assert_eq!(swc_internal_behavior.events().count(), 5);
801        // iterate over all events and check if they are the same as the ones we created
802        let mut events_iter = swc_internal_behavior.events();
803        assert_eq!(events_iter.next().unwrap().element(), init_event.element());
804        assert_eq!(events_iter.next().unwrap().element(), op_invoked_event.element());
805        assert_eq!(events_iter.next().unwrap().element(), background_event.element());
806        assert_eq!(events_iter.next().unwrap().element(), os_task_execution_event.element());
807        assert_eq!(events_iter.next().unwrap().element(), timing_event.element());
808
809        // runnable1 should be triggered by 4 events
810        assert_eq!(runnable1.events().len(), 4);
811        // runnable2 should be triggered by 1 event
812        assert_eq!(runnable2.events().len(), 1);
813
814        // add a data type mapping set to the swc_internal_behavior
815        let data_type_mapping_set = package.create_data_type_mapping_set("MappingSet").unwrap();
816        swc_internal_behavior
817            .add_data_type_mapping_set(&data_type_mapping_set)
818            .unwrap();
819        assert_eq!(swc_internal_behavior.data_type_mapping_sets().count(), 1);
820    }
821
822    #[test]
823    fn mode_switch_event() {
824        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
825        let package = model.get_or_create_package("/package").unwrap();
826
827        // create a software component type with an internal behavior
828        let app_swc = package
829            .create_application_sw_component_type("AppSwComponentType")
830            .unwrap();
831        let swc_internal_behavior = app_swc
832            .create_swc_internal_behavior("AppSwComponentType_InternalBehavior")
833            .unwrap();
834        assert_eq!(app_swc.swc_internal_behaviors().count(), 1);
835        assert_eq!(
836            swc_internal_behavior.sw_component_type().unwrap(),
837            app_swc.clone().into()
838        );
839
840        // create a mode declaration group and a mode switch interface
841        let mode_declaration_group = package
842            .create_mode_declaration_group("ModeDeclarationGroup", None)
843            .unwrap();
844        let mode_declaration_1 = mode_declaration_group
845            .create_mode_declaration("ModeDeclaration1")
846            .unwrap();
847        let mode_declaration_2 = mode_declaration_group
848            .create_mode_declaration("ModeDeclaration2")
849            .unwrap();
850        let mode_switch_interface = package.create_mode_switch_interface("ModeSwitchInterface").unwrap();
851        let r_port = app_swc.create_r_port("r_port", &mode_switch_interface).unwrap();
852
853        let mode_declaration_group2 = package
854            .create_mode_declaration_group("ModeDeclarationGroup2", None)
855            .unwrap();
856        let mode_declaration_g2 = mode_declaration_group2
857            .create_mode_declaration("ModeDeclaratio_g2")
858            .unwrap();
859
860        //  create a second port for the error path test which does not have a mode switch interface
861        let client_server_interface = package.create_client_server_interface("ClientServerInterface").unwrap();
862        let bad_port = app_swc.create_r_port("bad_port", &client_server_interface).unwrap();
863
864        // create a runnable entity
865        let runnable = swc_internal_behavior.create_runnable_entity("Runnable1").unwrap();
866        assert_eq!(runnable.swc_internal_behavior().unwrap(), swc_internal_behavior);
867
868        // error case: create a mode switch event with a port that does not have a mode switch interface
869        let result = swc_internal_behavior.create_mode_switch_event(
870            "ModeSwitchEvent",
871            &runnable,
872            ModeActivationKind::OnEntry,
873            &bad_port,
874            &mode_declaration_g2,
875            None,
876        );
877        assert!(result.is_err());
878
879        // error case: the mode switch interface does not contain a mode group
880        let result = swc_internal_behavior.create_mode_switch_event(
881            "ModeSwitchEvent",
882            &runnable,
883            ModeActivationKind::OnEntry,
884            &r_port,
885            &mode_declaration_1,
886            Some(&mode_declaration_2),
887        );
888        assert!(result.is_err());
889
890        // create the mode group in the mode switch interface
891        mode_switch_interface
892            .create_mode_group("mode_group", &mode_declaration_group)
893            .unwrap();
894
895        // error case: create a mode switch event with a mode_declaration that is not part of the mode declaration group
896        let result = swc_internal_behavior.create_mode_switch_event(
897            "ModeSwitchEvent",
898            &runnable,
899            ModeActivationKind::OnEntry,
900            &r_port,
901            &mode_declaration_g2,
902            None,
903        );
904        assert!(result.is_err());
905
906        // correct: create a mode switch event with a mode_declaration that is part of the mode declaration group
907        let mode_switch_event = swc_internal_behavior
908            .create_mode_switch_event(
909                "ModeSwitchEvent",
910                &runnable,
911                ModeActivationKind::OnEntry,
912                &r_port,
913                &mode_declaration_1,
914                Some(&mode_declaration_2),
915            )
916            .unwrap();
917        assert_eq!(mode_switch_event.runnable_entity().unwrap(), runnable);
918
919        assert_eq!(runnable.events().len(), 1);
920
921        let (mode_decls, context_port) = mode_switch_event.mode_declarations().unwrap();
922        assert_eq!(context_port, r_port.into());
923        assert_eq!(mode_decls.len(), 2);
924        assert_eq!(mode_decls[0], mode_declaration_1);
925        assert_eq!(mode_decls[1], mode_declaration_2);
926
927        // check the mode activation kind
928        mode_switch_event
929            .set_mode_activation_kind(ModeActivationKind::OnEntry)
930            .unwrap();
931        assert_eq!(
932            mode_switch_event.mode_activation_kind().unwrap(),
933            ModeActivationKind::OnEntry
934        );
935        mode_switch_event
936            .set_mode_activation_kind(ModeActivationKind::OnExit)
937            .unwrap();
938        assert_eq!(
939            mode_switch_event.mode_activation_kind().unwrap(),
940            ModeActivationKind::OnExit
941        );
942        mode_switch_event
943            .set_mode_activation_kind(ModeActivationKind::OnTransition)
944            .unwrap();
945        assert_eq!(
946            mode_switch_event.mode_activation_kind().unwrap(),
947            ModeActivationKind::OnTransition
948        );
949
950        // mode activation kind error case
951        let activation_kind = ModeActivationKind::try_from(EnumItem::Opaque);
952        assert!(activation_kind.is_err());
953    }
954
955    #[test]
956    fn data_received_event() {
957        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
958        let package = model.get_or_create_package("/package").unwrap();
959
960        // create a sender receiver interface with a variable
961        let sender_receiver_interface = package
962            .create_sender_receiver_interface("SenderReceiverInterface")
963            .unwrap();
964        let app_data_type = package
965            .create_application_primitive_data_type("uint32", ApplicationPrimitiveCategory::Value, None, None, None)
966            .unwrap();
967        let variable_data_prototype = sender_receiver_interface
968            .create_data_element("data", &app_data_type)
969            .unwrap();
970
971        // create a software component type with an internal behavior
972        let app_swc = package
973            .create_application_sw_component_type("AppSwComponentType")
974            .unwrap();
975        let r_port = app_swc.create_r_port("r_port", &sender_receiver_interface).unwrap();
976        let swc_internal_behavior = app_swc
977            .create_swc_internal_behavior("AppSwComponentType_InternalBehavior")
978            .unwrap();
979        assert_eq!(app_swc.swc_internal_behaviors().count(), 1);
980        assert_eq!(
981            swc_internal_behavior.sw_component_type().unwrap(),
982            app_swc.clone().into()
983        );
984
985        // create a p-port using the sender-receiver interface
986        let p_port = app_swc.create_p_port("p_port", &sender_receiver_interface).unwrap();
987
988        // create a port using a client-server interface
989        let client_server_interface = package.create_client_server_interface("ClientServerInterface").unwrap();
990        let cs_port = app_swc.create_r_port("cs_port", &client_server_interface).unwrap();
991
992        // create a runnable entity
993        let runnable = swc_internal_behavior.create_runnable_entity("Runnable1").unwrap();
994        assert_eq!(runnable.swc_internal_behavior().unwrap(), swc_internal_behavior);
995
996        // error case: create a data received event with a port that does not have a sender-receiver interface
997        let result = swc_internal_behavior.create_data_received_event(
998            "DataReceivedEvent",
999            &runnable,
1000            &variable_data_prototype,
1001            &cs_port,
1002        );
1003        assert!(result.is_err());
1004
1005        // error case: can't create a data received event with a p-port
1006        let result = swc_internal_behavior.create_data_received_event(
1007            "DataReceivedEvent",
1008            &runnable,
1009            &variable_data_prototype,
1010            &p_port,
1011        );
1012        assert!(result.is_err());
1013
1014        // create a data received event, which triggers runnable
1015        let data_received_event = swc_internal_behavior
1016            .create_data_received_event("DataReceivedEvent", &runnable, &variable_data_prototype, &r_port)
1017            .unwrap();
1018        assert_eq!(data_received_event.runnable_entity().unwrap(), runnable);
1019
1020        let (data_element, context_port) = data_received_event.variable_data_prototype().unwrap();
1021        assert_eq!(data_element, variable_data_prototype);
1022        assert_eq!(context_port, r_port.into());
1023        assert_eq!(data_received_event.runnable_entity().unwrap(), runnable);
1024    }
1025
1026    #[test]
1027    fn variable_access() {
1028        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1029        let package = model.get_or_create_package("/package").unwrap();
1030
1031        // create a sender receiver interface with a variable
1032        let sender_receiver_interface = package
1033            .create_sender_receiver_interface("SenderReceiverInterface")
1034            .unwrap();
1035        let app_data_type = package
1036            .create_application_primitive_data_type("uint32", ApplicationPrimitiveCategory::Value, None, None, None)
1037            .unwrap();
1038        let variable_data_prototype = sender_receiver_interface
1039            .create_data_element("data", &app_data_type)
1040            .unwrap();
1041
1042        // create a software component type with an internal behavior
1043        let app_swc = package
1044            .create_application_sw_component_type("AppSwComponentType")
1045            .unwrap();
1046        let r_port = app_swc.create_r_port("r_port", &sender_receiver_interface).unwrap();
1047        let p_port = app_swc.create_p_port("p_port", &sender_receiver_interface).unwrap();
1048        let swc_internal_behavior = app_swc
1049            .create_swc_internal_behavior("AppSwComponentType_InternalBehavior")
1050            .unwrap();
1051        assert_eq!(app_swc.swc_internal_behaviors().count(), 1);
1052        assert_eq!(
1053            swc_internal_behavior.sw_component_type().unwrap(),
1054            app_swc.clone().into()
1055        );
1056
1057        // create a runnable entity
1058        let runnable = swc_internal_behavior.create_runnable_entity("Runnable").unwrap();
1059        assert_eq!(runnable.swc_internal_behavior().unwrap(), swc_internal_behavior);
1060
1061        // create a variable access for read access
1062        let variable_access = runnable
1063            .create_data_read_access("DataReadAccess", &variable_data_prototype, &r_port)
1064            .unwrap();
1065        assert_eq!(variable_access.runnable_entity().unwrap(), runnable);
1066        assert_eq!(variable_access.accessed_variable().unwrap().0, variable_data_prototype);
1067        assert_eq!(runnable.data_read_accesses().count(), 1);
1068
1069        // create a variable access for write access
1070        let variable_access = runnable
1071            .create_data_write_access("DataWriteAccess", &variable_data_prototype, &p_port)
1072            .unwrap();
1073        assert_eq!(variable_access.runnable_entity().unwrap(), runnable);
1074        assert_eq!(variable_access.accessed_variable().unwrap().0, variable_data_prototype);
1075        assert_eq!(runnable.data_write_accesses().count(), 1);
1076
1077        // create a variable access for send point
1078        let variable_access = runnable
1079            .create_data_send_point("DataSendPoint", &variable_data_prototype, &p_port)
1080            .unwrap();
1081        assert_eq!(variable_access.runnable_entity().unwrap(), runnable);
1082        assert_eq!(variable_access.accessed_variable().unwrap().0, variable_data_prototype);
1083        assert_eq!(runnable.data_send_points().count(), 1);
1084
1085        // create a variable access for receive point by argument
1086        let variable_access = runnable
1087            .create_data_receive_point_by_argument("DataReceivePointByArgument", &variable_data_prototype, &r_port)
1088            .unwrap();
1089        assert_eq!(variable_access.runnable_entity().unwrap(), runnable);
1090        assert_eq!(variable_access.accessed_variable().unwrap().0, variable_data_prototype);
1091        assert_eq!(runnable.data_receive_points_by_argument().count(), 1);
1092
1093        // create a variable access for receive point by value
1094        let variable_access = runnable
1095            .create_data_receive_point_by_value("DataReceivePointByValue", &variable_data_prototype, &r_port)
1096            .unwrap();
1097        assert_eq!(variable_access.runnable_entity().unwrap(), runnable);
1098        assert_eq!(variable_access.accessed_variable().unwrap().0, variable_data_prototype);
1099        assert_eq!(runnable.data_receive_points_by_value().count(), 1);
1100    }
1101
1102    #[test]
1103    fn synchronous_server_call_point() {
1104        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1105        let package = model.get_or_create_package("/package").unwrap();
1106
1107        // create a client-server interface
1108        let client_server_interface = package.create_client_server_interface("ClientServerInterface").unwrap();
1109        let operation = client_server_interface.create_operation("TestOperation").unwrap();
1110
1111        // create a software component type with an internal behavior
1112        let app_swc = package
1113            .create_application_sw_component_type("AppSwComponentType")
1114            .unwrap();
1115        let r_port = app_swc.create_r_port("r_port", &client_server_interface).unwrap();
1116        let swc_internal_behavior = app_swc
1117            .create_swc_internal_behavior("AppSwComponentType_InternalBehavior")
1118            .unwrap();
1119        assert_eq!(app_swc.swc_internal_behaviors().count(), 1);
1120        assert_eq!(
1121            swc_internal_behavior.sw_component_type().unwrap(),
1122            app_swc.clone().into()
1123        );
1124
1125        // create a runnable entity
1126        let runnable = swc_internal_behavior.create_runnable_entity("Runnable1").unwrap();
1127        assert_eq!(runnable.swc_internal_behavior().unwrap(), swc_internal_behavior);
1128
1129        // create a synchronous server call point
1130        let synchronous_server_call_point = runnable
1131            .create_synchronous_server_call_point("SynchronousServerCallPoint", &operation, &r_port)
1132            .unwrap();
1133        assert_eq!(synchronous_server_call_point.runnable_entity().unwrap(), runnable);
1134        assert_eq!(
1135            synchronous_server_call_point.client_server_operation().unwrap().0,
1136            operation
1137        );
1138        assert_eq!(runnable.synchronous_server_call_points().count(), 1);
1139    }
1140
1141    #[test]
1142    fn mode_access_point() {
1143        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1144        let package = model.get_or_create_package("/package").unwrap();
1145
1146        // create a mode declaration group
1147        let mode_declaration_group = package
1148            .create_mode_declaration_group("ModeDeclarationGroup", None)
1149            .unwrap();
1150        // create a mode switch interface
1151        let mode_switch_interface = package.create_mode_switch_interface("ModeSwitchInterface").unwrap();
1152        // create a mode group in the mode switch interface
1153        let mode_group = mode_switch_interface
1154            .create_mode_group("mode_group", &mode_declaration_group)
1155            .unwrap();
1156
1157        // create a software component type with an internal behavior
1158        let app_swc = package
1159            .create_application_sw_component_type("AppSwComponentType")
1160            .unwrap();
1161        let r_port = app_swc.create_r_port("r_port", &mode_switch_interface).unwrap();
1162        let p_port = app_swc.create_p_port("p_port", &mode_switch_interface).unwrap();
1163        let swc_internal_behavior = app_swc
1164            .create_swc_internal_behavior("AppSwComponentType_InternalBehavior")
1165            .unwrap();
1166        assert_eq!(app_swc.swc_internal_behaviors().count(), 1);
1167        assert_eq!(
1168            swc_internal_behavior.sw_component_type().unwrap(),
1169            app_swc.clone().into()
1170        );
1171
1172        // create a runnable entity
1173        let runnable = swc_internal_behavior.create_runnable_entity("Runnable1").unwrap();
1174        assert_eq!(runnable.swc_internal_behavior().unwrap(), swc_internal_behavior);
1175
1176        // create a mode access point
1177        let mode_access_point_r = runnable
1178            .create_mode_access_point("ModeAccessPoint", &mode_group, &r_port)
1179            .unwrap();
1180        assert_eq!(mode_access_point_r.name(), Some("ModeAccessPoint".to_string()));
1181        let mode_access_point_p = runnable
1182            .create_mode_access_point("ModeAccessPointP", &mode_group, &p_port)
1183            .unwrap();
1184        assert_eq!(mode_access_point_p.name(), Some("ModeAccessPointP".to_string()));
1185        assert_eq!(mode_access_point_r.runnable_entity().unwrap(), runnable);
1186        assert_eq!(mode_access_point_p.runnable_entity().unwrap(), runnable);
1187        assert_eq!(mode_access_point_r.mode_group().unwrap().0, mode_group);
1188        assert_eq!(mode_access_point_p.mode_group().unwrap().0, mode_group);
1189        assert_eq!(mode_access_point_r.mode_group().unwrap().1, r_port.into());
1190        assert_eq!(mode_access_point_p.mode_group().unwrap().1, p_port.into());
1191        assert_eq!(runnable.mode_access_points().count(), 2);
1192    }
1193
1194    #[test]
1195    fn test_mode_switch_point() {
1196        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1197        let package = model.get_or_create_package("/package").unwrap();
1198
1199        // create a mode declaration group
1200        let mode_declaration_group = package
1201            .create_mode_declaration_group("ModeDeclarationGroup", None)
1202            .unwrap();
1203        // create a mode switch interface
1204        let mode_switch_interface = package.create_mode_switch_interface("ModeSwitchInterface").unwrap();
1205        // create a mode group in the mode switch interface
1206        let mode_group = mode_switch_interface
1207            .create_mode_group("mode_group", &mode_declaration_group)
1208            .unwrap();
1209
1210        // create a software component type with an internal behavior
1211        let app_swc = package
1212            .create_application_sw_component_type("AppSwComponentType")
1213            .unwrap();
1214        let p_port = app_swc.create_p_port("p_port", &mode_switch_interface).unwrap();
1215        let swc_internal_behavior = app_swc
1216            .create_swc_internal_behavior("AppSwComponentType_InternalBehavior")
1217            .unwrap();
1218        assert_eq!(app_swc.swc_internal_behaviors().count(), 1);
1219        assert_eq!(
1220            swc_internal_behavior.sw_component_type().unwrap(),
1221            app_swc.clone().into()
1222        );
1223
1224        // create a runnable entity
1225        let runnable = swc_internal_behavior.create_runnable_entity("Runnable1").unwrap();
1226        assert_eq!(runnable.swc_internal_behavior().unwrap(), swc_internal_behavior);
1227
1228        // create a mode switch point
1229        let mode_switch_point = runnable
1230            .create_mode_switch_point("ModeSwitchPoint", &mode_group, &p_port)
1231            .unwrap();
1232        assert_eq!(mode_switch_point.runnable_entity().unwrap(), runnable);
1233        assert_eq!(mode_switch_point.mode_group().unwrap().0, mode_group);
1234        assert_eq!(mode_switch_point.mode_group().unwrap().1, p_port.into());
1235        assert_eq!(runnable.mode_switch_points().count(), 1);
1236    }
1237}