autosar_data_abstraction/software_component/
mod.rs

1//! Software component types and compositions
2//!
3//! This module contains the definition of software component types and instances.
4//! It also contains the definition of the composition hierarchy, and the connectors between components.
5
6use crate::{
7    AbstractionElement, ArPackage, AutosarAbstractionError, Element, IdentifiableAbstractionElement, SwcToEcuMapping,
8    abstraction_element, get_reference_parents,
9};
10use autosar_data::ElementName;
11
12mod connector;
13mod interface;
14mod internal_behavior;
15mod mode;
16mod port;
17
18pub use connector::*;
19pub use interface::*;
20pub use internal_behavior::*;
21pub use mode::*;
22pub use port::*;
23
24//##################################################################
25
26/// The `AbstractSwComponentType` is the common interface for all types of software components
27pub trait AbstractSwComponentType: IdentifiableAbstractionElement {
28    /// iterator over the instances of the component type
29    fn instances(&self) -> Vec<ComponentPrototype> {
30        let model_result = self.element().model();
31        let path_result = self.element().path();
32        if let (Ok(model), Ok(path)) = (model_result, path_result) {
33            model
34                .get_references_to(&path)
35                .iter()
36                .filter_map(|e| {
37                    e.upgrade()
38                        .and_then(|ref_elem| ref_elem.named_parent().ok().flatten())
39                        .and_then(|elem| ComponentPrototype::try_from(elem).ok())
40                })
41                .collect()
42        } else {
43            vec![]
44        }
45    }
46
47    /// list all compositions containing instances of the component type
48    fn parent_compositions(&self) -> Vec<CompositionSwComponentType> {
49        self.instances()
50            .iter()
51            .filter_map(|swcp| swcp.element().named_parent().ok().flatten())
52            .filter_map(|elem| CompositionSwComponentType::try_from(elem).ok())
53            .collect()
54    }
55
56    /// create a new required port with the given name and port interface
57    fn create_r_port<T: AbstractPortInterface>(
58        &self,
59        name: &str,
60        port_interface: &T,
61    ) -> Result<RPortPrototype, AutosarAbstractionError> {
62        let ports = self.element().get_or_create_sub_element(ElementName::Ports)?;
63        RPortPrototype::new(name, &ports, port_interface)
64    }
65
66    /// create a new provided port with the given name and port interface
67    fn create_p_port<T: AbstractPortInterface>(
68        &self,
69        name: &str,
70        port_interface: &T,
71    ) -> Result<PPortPrototype, AutosarAbstractionError> {
72        let ports = self.element().get_or_create_sub_element(ElementName::Ports)?;
73        PPortPrototype::new(name, &ports, port_interface)
74    }
75
76    /// create a new provided required port with the given name and port interface
77    fn create_pr_port<T: AbstractPortInterface>(
78        &self,
79        name: &str,
80        port_interface: &T,
81    ) -> Result<PRPortPrototype, AutosarAbstractionError> {
82        let ports = self.element().get_or_create_sub_element(ElementName::Ports)?;
83        PRPortPrototype::new(name, &ports, port_interface)
84    }
85
86    /// get an iterator over the ports of the component
87    fn ports(&self) -> impl Iterator<Item = PortPrototype> + Send + use<Self> {
88        self.element()
89            .get_sub_element(ElementName::Ports)
90            .into_iter()
91            .flat_map(|ports| ports.sub_elements())
92            .filter_map(|elem| PortPrototype::try_from(elem).ok())
93    }
94
95    /// create a new port group
96    fn create_port_group(&self, name: &str) -> Result<PortGroup, AutosarAbstractionError> {
97        let port_groups = self.element().get_or_create_sub_element(ElementName::PortGroups)?;
98        PortGroup::new(name, &port_groups)
99    }
100}
101
102//##################################################################
103
104/// Shared trait identifiying atomic software components
105///
106/// An atomic software component is atomic in the sense that it cannot be further decomposed
107pub trait AtomicSwComponentType: AbstractSwComponentType {
108    /// create an `SwcInternalBehavior` for the component
109    ///
110    /// A component can have only one internal behavior, but since the internal behavior is a variation point,
111    /// more than one internal behavior can be created. In this case the variation point settings must ensure that only one
112    /// internal behavior is active.
113    fn create_swc_internal_behavior(&self, name: &str) -> Result<SwcInternalBehavior, AutosarAbstractionError> {
114        let internal_behaviors = self
115            .element()
116            .get_or_create_sub_element(ElementName::InternalBehaviors)?;
117        SwcInternalBehavior::new(name, &internal_behaviors)
118    }
119
120    /// iterate over all swc internal behaviors - typically zero or one
121    fn swc_internal_behaviors(&self) -> impl Iterator<Item = SwcInternalBehavior> + Send + use<Self> {
122        self.element()
123            .get_sub_element(ElementName::InternalBehaviors)
124            .into_iter()
125            .flat_map(|internal_behaviors| internal_behaviors.sub_elements())
126            .filter_map(|elem| SwcInternalBehavior::try_from(elem).ok())
127    }
128}
129
130//##################################################################
131
132/// A `CompositionSwComponentType` is a software component that contains other software components
133///
134/// Use [`ArPackage::create_composition_sw_component_type`] to create a new composition sw component type.
135#[derive(Debug, Clone, PartialEq, Eq, Hash)]
136pub struct CompositionSwComponentType(Element);
137abstraction_element!(CompositionSwComponentType, CompositionSwComponentType);
138impl IdentifiableAbstractionElement for CompositionSwComponentType {}
139
140impl CompositionSwComponentType {
141    /// create a new composition component with the given name
142    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
143        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
144        let composition = elements.create_named_sub_element(ElementName::CompositionSwComponentType, name)?;
145        Ok(Self(composition))
146    }
147
148    /// remove this `CompositionSwComponentType` from the model
149    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
150        for component in self.components() {
151            component.remove(deep)?;
152        }
153
154        for connector in self.connectors() {
155            connector.remove(deep)?;
156        }
157
158        let ref_parents = get_reference_parents(self.element())?;
159
160        AbstractionElement::remove(self, deep)?;
161
162        for (named_parent, _parent) in ref_parents {
163            match named_parent.element_name() {
164                ElementName::SwComponentPrototype => {
165                    if let Ok(component) = SwComponentPrototype::try_from(named_parent) {
166                        component.remove(deep)?;
167                    }
168                }
169                ElementName::RootSwCompositionPrototype => {
170                    if let Ok(composition) = RootSwCompositionPrototype::try_from(named_parent) {
171                        composition.remove(deep)?;
172                    }
173                }
174                _ => {}
175            }
176        }
177
178        Ok(())
179    }
180
181    /// check if the composition is a parent (or grand-parent, etc.) of the component
182    pub fn is_parent_of<T: AbstractSwComponentType>(&self, other: &T) -> bool {
183        // the expectation is that in normal cases each component has only one parent
184        // additionally there should never be any cycles in the composition hierarchy
185        let mut work_items = other.parent_compositions();
186        let mut counter = 1000; // just to prevent infinite loops, since I don't trust files generated by other tools
187        while !work_items.is_empty() && counter > 0 {
188            counter -= 1;
189            if work_items.contains(self) {
190                return true;
191            }
192            // the uses of pop here makes this a depth-first search in the case where there are multiple parents
193            let item = work_items.pop().unwrap();
194            work_items.extend(item.parent_compositions());
195        }
196
197        false
198    }
199
200    /// create a component of type `component_type` in the composition
201    ///
202    /// It is not allowed to form cycles in the composition hierarchy, and this will return an error
203    pub fn create_component<T: Into<SwComponentType> + Clone>(
204        &self,
205        name: &str,
206        component_type: &T,
207    ) -> Result<SwComponentPrototype, AutosarAbstractionError> {
208        let component_type = component_type.clone().into();
209        if let SwComponentType::Composition(composition_component) = &component_type
210            && composition_component.is_parent_of(self)
211        {
212            return Err(AutosarAbstractionError::InvalidParameter(
213                "Creating a cycle in the composition hierarchy".to_string(),
214            ));
215        }
216
217        let components = self.element().get_or_create_sub_element(ElementName::Components)?;
218        SwComponentPrototype::new(name, &components, &component_type)
219    }
220
221    /// get an iterator over the components of the composition
222    pub fn components(&self) -> impl Iterator<Item = SwComponentPrototype> + Send + use<> {
223        self.element()
224            .get_sub_element(ElementName::Components)
225            .into_iter()
226            .flat_map(|components| components.sub_elements())
227            .filter_map(|elem| SwComponentPrototype::try_from(elem).ok())
228    }
229
230    /// create a new delegation connector between an inner port and an outer port
231    ///
232    /// The two ports must be compatible.
233    pub fn create_delegation_connector<T1: Into<PortPrototype> + Clone, T2: Into<PortPrototype> + Clone>(
234        &self,
235        name: &str,
236        inner_port: &T1,
237        inner_sw_prototype: &SwComponentPrototype,
238        outer_port: &T2,
239    ) -> Result<DelegationSwConnector, AutosarAbstractionError> {
240        self.create_delegation_connector_internal(
241            name,
242            &inner_port.clone().into(),
243            inner_sw_prototype,
244            &outer_port.clone().into(),
245        )
246    }
247
248    /// create a new delegation connector between an inner port and an outer port
249    /// this is the actual implementation of the public method, but without the generic parameters
250    fn create_delegation_connector_internal(
251        &self,
252        name: &str,
253        inner_port: &PortPrototype,
254        inner_sw_prototype: &SwComponentPrototype,
255        outer_port: &PortPrototype,
256    ) -> Result<DelegationSwConnector, AutosarAbstractionError> {
257        // check the compatibility of the interfaces
258        let interface_1 = inner_port
259            .port_interface()
260            .ok_or(AutosarAbstractionError::InvalidParameter(
261                "Invalid port lacks a port interface".to_string(),
262            ))?;
263        let interface_2 = outer_port
264            .port_interface()
265            .ok_or(AutosarAbstractionError::InvalidParameter(
266                "Invalid port lacks a port interface".to_string(),
267            ))?;
268        if std::mem::discriminant(&interface_1) != std::mem::discriminant(&interface_2) {
269            return Err(AutosarAbstractionError::InvalidParameter(
270                "The interfaces of the two ports are not compatible".to_string(),
271            ));
272        }
273
274        // check that the inner port is part of the inner component
275        let inner_swc_from_port = SwComponentType::try_from(inner_port.element().named_parent()?.unwrap())?;
276        let inner_swc_from_component =
277            inner_sw_prototype
278                .component_type()
279                .ok_or(AutosarAbstractionError::InvalidParameter(
280                    "The inner component is incomplete and lacks a type reference".to_string(),
281                ))?;
282        if inner_swc_from_port != inner_swc_from_component {
283            return Err(AutosarAbstractionError::InvalidParameter(
284                "The inner port must be part of the inner component".to_string(),
285            ));
286        }
287
288        let swc_self = self.clone().into();
289        let outer_swc_from_port = SwComponentType::try_from(outer_port.element().named_parent()?.unwrap())?;
290        if outer_swc_from_port != swc_self {
291            return Err(AutosarAbstractionError::InvalidParameter(
292                "The outer port must be part of the composition".to_string(),
293            ));
294        }
295
296        // create the delegation connector
297        let connectors = self.element().get_or_create_sub_element(ElementName::Connectors)?;
298
299        DelegationSwConnector::new(
300            name,
301            &connectors,
302            inner_port, // inner port = port of the contained component
303            inner_sw_prototype,
304            outer_port, // outer port = port of the composition
305        )
306    }
307
308    /// create a new assembly connector between two ports of contained software components
309    ///
310    /// The two ports must be compatible.
311    pub fn create_assembly_connector<T1: Into<PortPrototype> + Clone, T2: Into<PortPrototype> + Clone>(
312        &self,
313        name: &str,
314        port_1: &T1,
315        sw_prototype_1: &SwComponentPrototype,
316        port_2: &T2,
317        sw_prototype_2: &SwComponentPrototype,
318    ) -> Result<AssemblySwConnector, AutosarAbstractionError> {
319        self.create_assembly_connector_internal(
320            name,
321            &port_1.clone().into(),
322            sw_prototype_1,
323            &port_2.clone().into(),
324            sw_prototype_2,
325        )
326    }
327
328    fn create_assembly_connector_internal(
329        &self,
330        name: &str,
331        port_1: &PortPrototype,
332        sw_prototype_1: &SwComponentPrototype,
333        port_2: &PortPrototype,
334        sw_prototype_2: &SwComponentPrototype,
335    ) -> Result<AssemblySwConnector, AutosarAbstractionError> {
336        // check the compatibility of the interfaces
337        let interface_1 = port_1
338            .port_interface()
339            .ok_or(AutosarAbstractionError::InvalidParameter(
340                "Invalid port lacks a port interface".to_string(),
341            ))?;
342        let interface_2 = port_2
343            .port_interface()
344            .ok_or(AutosarAbstractionError::InvalidParameter(
345                "Invalid port lacks a port interface".to_string(),
346            ))?;
347        if std::mem::discriminant(&interface_1) != std::mem::discriminant(&interface_2) {
348            return Err(AutosarAbstractionError::InvalidParameter(
349                "The interfaces of the two ports are not compatible".to_string(),
350            ));
351        }
352
353        // check that the ports are part of the correct components
354        let swc_1_from_port = SwComponentType::try_from(port_1.element().named_parent()?.unwrap())?;
355        let swc_1_from_component = sw_prototype_1
356            .component_type()
357            .ok_or(AutosarAbstractionError::InvalidParameter(
358                "SW component prototype 1 is incomplete and lacks a type reference".to_string(),
359            ))?;
360        if swc_1_from_port != swc_1_from_component {
361            return Err(AutosarAbstractionError::InvalidParameter(
362                "The first port must be part of the first software component".to_string(),
363            ));
364        }
365
366        let swc_2_from_port = SwComponentType::try_from(port_2.element().named_parent()?.unwrap())?;
367        let swc_2_from_component = sw_prototype_2
368            .component_type()
369            .ok_or(AutosarAbstractionError::InvalidParameter(
370                "SW component prototype 2 is incomplete and lacks a type reference".to_string(),
371            ))?;
372        if swc_2_from_port != swc_2_from_component {
373            return Err(AutosarAbstractionError::InvalidParameter(
374                "The second port must be part of the second software component".to_string(),
375            ));
376        }
377
378        // check that both SWCs are part of the composition
379        if &sw_prototype_1.parent_composition()? != self {
380            return Err(AutosarAbstractionError::InvalidParameter(
381                "The first software component must be part of the composition".to_string(),
382            ));
383        }
384        if &sw_prototype_2.parent_composition()? != self {
385            return Err(AutosarAbstractionError::InvalidParameter(
386                "The second software component must be part of the composition".to_string(),
387            ));
388        }
389
390        // create the assembly connector
391        let connectors = self.element().get_or_create_sub_element(ElementName::Connectors)?;
392        AssemblySwConnector::new(name, &connectors, port_1, sw_prototype_1, port_2, sw_prototype_2)
393    }
394
395    /// create a new passthrough connector between two outer ports of the composition
396    ///
397    /// The two ports must be compatible.
398    pub fn create_pass_through_connector<T1: Into<PortPrototype> + Clone, T2: Into<PortPrototype> + Clone>(
399        &self,
400        name: &str,
401        port_1: &T1,
402        port_2: &T2,
403    ) -> Result<PassThroughSwConnector, AutosarAbstractionError> {
404        self.create_pass_through_connector_internal(name, &port_1.clone().into(), &port_2.clone().into())
405    }
406
407    fn create_pass_through_connector_internal(
408        &self,
409        name: &str,
410        port_1: &PortPrototype,
411        port_2: &PortPrototype,
412    ) -> Result<PassThroughSwConnector, AutosarAbstractionError> {
413        // check the compatibility of the interfaces
414        let interface_1 = port_1
415            .port_interface()
416            .ok_or(AutosarAbstractionError::InvalidParameter(
417                "Invalid port lacks a port interface".to_string(),
418            ))?;
419        let interface_2 = port_2
420            .port_interface()
421            .ok_or(AutosarAbstractionError::InvalidParameter(
422                "Invalid port lacks a port interface".to_string(),
423            ))?;
424        if std::mem::discriminant(&interface_1) != std::mem::discriminant(&interface_2) {
425            return Err(AutosarAbstractionError::InvalidParameter(
426                "The interfaces of the two ports are not compatible".to_string(),
427            ));
428        }
429
430        // decide what kind of connector to create
431        let swc_1 = SwComponentType::try_from(port_1.element().named_parent()?.unwrap())?;
432        let swc_2 = SwComponentType::try_from(port_2.element().named_parent()?.unwrap())?;
433        let swc_self = self.clone().into();
434
435        // both ports must be part of the composition
436        if swc_1 != swc_self || swc_2 != swc_self {
437            return Err(AutosarAbstractionError::InvalidParameter(
438                "The ports must be part of the composition".to_string(),
439            ));
440        }
441
442        let connectors = self.element().get_or_create_sub_element(ElementName::Connectors)?;
443        PassThroughSwConnector::new(name, &connectors, port_1, port_2)
444    }
445
446    /// iterate over all connectors
447    pub fn connectors(&self) -> impl Iterator<Item = SwConnector> + Send + use<> {
448        self.element()
449            .get_sub_element(ElementName::Connectors)
450            .into_iter()
451            .flat_map(|connectors| connectors.sub_elements())
452            .filter_map(|elem| SwConnector::try_from(elem).ok())
453    }
454}
455
456impl AbstractSwComponentType for CompositionSwComponentType {}
457
458//##################################################################
459
460/// An `ApplicationSwComponentType` is a software component that provides application functionality
461///
462/// Use [`ArPackage::create_application_sw_component_type`] to create a new application sw component type.
463#[derive(Debug, Clone, PartialEq, Eq, Hash)]
464pub struct ApplicationSwComponentType(Element);
465abstraction_element!(ApplicationSwComponentType, ApplicationSwComponentType);
466impl IdentifiableAbstractionElement for ApplicationSwComponentType {}
467
468impl ApplicationSwComponentType {
469    /// create a new application component with the given name
470    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
471        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
472        let application = elements.create_named_sub_element(ElementName::ApplicationSwComponentType, name)?;
473        Ok(Self(application))
474    }
475
476    /// remove this `ApplicationSwComponentType` from the model
477    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
478        for swc_internal_behavior in self.swc_internal_behaviors() {
479            swc_internal_behavior.remove(deep)?;
480        }
481        let ref_parents = get_reference_parents(self.element())?;
482
483        AbstractionElement::remove(self, deep)?;
484
485        for (named_parent, _parent) in ref_parents {
486            if named_parent.element_name() == ElementName::SwComponentPrototype
487                && let Ok(component) = SwComponentPrototype::try_from(named_parent)
488            {
489                component.remove(deep)?;
490            }
491        }
492
493        Ok(())
494    }
495}
496
497impl AbstractSwComponentType for ApplicationSwComponentType {}
498impl AtomicSwComponentType for ApplicationSwComponentType {}
499
500//##################################################################
501
502/// A `ComplexDeviceDriverSwComponentType` is a software component that provides complex device driver functionality
503///
504/// Use [`ArPackage::create_complex_device_driver_sw_component_type`] to create a new complex device driver sw component type.
505#[derive(Debug, Clone, PartialEq, Eq, Hash)]
506pub struct ComplexDeviceDriverSwComponentType(Element);
507abstraction_element!(ComplexDeviceDriverSwComponentType, ComplexDeviceDriverSwComponentType);
508impl IdentifiableAbstractionElement for ComplexDeviceDriverSwComponentType {}
509
510impl ComplexDeviceDriverSwComponentType {
511    /// create a new complex device driver component with the given name
512    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
513        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
514        let cdd = elements.create_named_sub_element(ElementName::ComplexDeviceDriverSwComponentType, name)?;
515        Ok(Self(cdd))
516    }
517}
518
519impl AbstractSwComponentType for ComplexDeviceDriverSwComponentType {}
520impl AtomicSwComponentType for ComplexDeviceDriverSwComponentType {}
521
522//##################################################################
523
524/// `ServiceSwComponentType` is used for configuring services for a given ECU. Instances of this class should only
525/// be created in ECU Configuration phase for the specific purpose of the service configuration.
526///
527/// Use [`ArPackage::create_service_sw_component_type`] to create a new service sw component type.
528#[derive(Debug, Clone, PartialEq, Eq, Hash)]
529pub struct ServiceSwComponentType(Element);
530abstraction_element!(ServiceSwComponentType, ServiceSwComponentType);
531impl IdentifiableAbstractionElement for ServiceSwComponentType {}
532
533impl ServiceSwComponentType {
534    /// create a new service component with the given name
535    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
536        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
537        let service = elements.create_named_sub_element(ElementName::ServiceSwComponentType, name)?;
538        Ok(Self(service))
539    }
540}
541
542impl AbstractSwComponentType for ServiceSwComponentType {}
543impl AtomicSwComponentType for ServiceSwComponentType {}
544
545//##################################################################
546
547/// `SensorActuatorSwComponentType` is used to connect sensor/acutator devices to the ECU configuration
548///
549/// Use [`ArPackage::create_sensor_actuator_sw_component_type`] to create a new sensor/actuator sw component type.
550#[derive(Debug, Clone, PartialEq, Eq, Hash)]
551pub struct SensorActuatorSwComponentType(Element);
552abstraction_element!(SensorActuatorSwComponentType, SensorActuatorSwComponentType);
553impl IdentifiableAbstractionElement for SensorActuatorSwComponentType {}
554
555impl SensorActuatorSwComponentType {
556    /// create a new sensor/actuator component with the given name
557    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
558        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
559        let sensor_actuator = elements.create_named_sub_element(ElementName::SensorActuatorSwComponentType, name)?;
560        Ok(Self(sensor_actuator))
561    }
562}
563
564impl AbstractSwComponentType for SensorActuatorSwComponentType {}
565impl AtomicSwComponentType for SensorActuatorSwComponentType {}
566
567//##################################################################
568
569/// The `ECUAbstraction` is a special `AtomicSwComponentType` that resides between a software-component
570/// that wants to access ECU periphery and the Microcontroller Abstraction
571///
572/// Use [`ArPackage::create_ecu_abstraction_sw_component_type`] to create a new ECU abstraction sw component type.
573#[derive(Debug, Clone, PartialEq, Eq, Hash)]
574pub struct EcuAbstractionSwComponentType(Element);
575abstraction_element!(EcuAbstractionSwComponentType, EcuAbstractionSwComponentType);
576impl IdentifiableAbstractionElement for EcuAbstractionSwComponentType {}
577
578impl EcuAbstractionSwComponentType {
579    /// create a new ECU abstraction component with the given name
580    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
581        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
582        let ecu_abstraction = elements.create_named_sub_element(ElementName::EcuAbstractionSwComponentType, name)?;
583        Ok(Self(ecu_abstraction))
584    }
585}
586
587impl AbstractSwComponentType for EcuAbstractionSwComponentType {}
588impl AtomicSwComponentType for EcuAbstractionSwComponentType {}
589
590//##################################################################
591
592/// The `SwComponentType` enum represents all possible types of software components
593#[derive(Debug, Clone, PartialEq, Eq, Hash)]
594pub enum SwComponentType {
595    /// the component is `CompositionSwComponentType`
596    Composition(CompositionSwComponentType),
597    /// the component is `ApplicationSwComponentType`
598    Application(ApplicationSwComponentType),
599    /// the component is `ComplexDeviceDriverSwComponentType`
600    ComplexDeviceDriver(ComplexDeviceDriverSwComponentType),
601    /// the component is `ServiceSwComponentType`
602    Service(ServiceSwComponentType),
603    /// the component is `SensorActuatorSwComponentType`
604    SensorActuator(SensorActuatorSwComponentType),
605    /// the component is `EcuAbstractionSwComponentType`
606    EcuAbstraction(EcuAbstractionSwComponentType),
607}
608
609impl AbstractionElement for SwComponentType {
610    fn element(&self) -> &Element {
611        match self {
612            SwComponentType::Composition(comp) => comp.element(),
613            SwComponentType::Application(app) => app.element(),
614            SwComponentType::ComplexDeviceDriver(cdd) => cdd.element(),
615            SwComponentType::Service(service) => service.element(),
616            SwComponentType::SensorActuator(sensor_actuator) => sensor_actuator.element(),
617            SwComponentType::EcuAbstraction(ecu_abstraction) => ecu_abstraction.element(),
618        }
619    }
620}
621
622impl IdentifiableAbstractionElement for SwComponentType {}
623
624impl TryFrom<Element> for SwComponentType {
625    type Error = AutosarAbstractionError;
626
627    fn try_from(element: Element) -> Result<Self, Self::Error> {
628        match element.element_name() {
629            ElementName::CompositionSwComponentType => {
630                Ok(SwComponentType::Composition(CompositionSwComponentType(element)))
631            }
632            ElementName::ApplicationSwComponentType => {
633                Ok(SwComponentType::Application(ApplicationSwComponentType(element)))
634            }
635            ElementName::ComplexDeviceDriverSwComponentType => Ok(SwComponentType::ComplexDeviceDriver(
636                ComplexDeviceDriverSwComponentType(element),
637            )),
638            ElementName::ServiceSwComponentType => Ok(SwComponentType::Service(ServiceSwComponentType(element))),
639            ElementName::SensorActuatorSwComponentType => {
640                Ok(SwComponentType::SensorActuator(SensorActuatorSwComponentType(element)))
641            }
642            ElementName::EcuAbstractionSwComponentType => {
643                Ok(SwComponentType::EcuAbstraction(EcuAbstractionSwComponentType(element)))
644            }
645            _ => Err(AutosarAbstractionError::ConversionError {
646                element,
647                dest: "SwComponentType".to_string(),
648            }),
649        }
650    }
651}
652
653impl From<CompositionSwComponentType> for SwComponentType {
654    fn from(comp: CompositionSwComponentType) -> Self {
655        SwComponentType::Composition(comp)
656    }
657}
658
659impl From<ApplicationSwComponentType> for SwComponentType {
660    fn from(app: ApplicationSwComponentType) -> Self {
661        SwComponentType::Application(app)
662    }
663}
664
665impl From<ComplexDeviceDriverSwComponentType> for SwComponentType {
666    fn from(cdd: ComplexDeviceDriverSwComponentType) -> Self {
667        SwComponentType::ComplexDeviceDriver(cdd)
668    }
669}
670
671impl From<ServiceSwComponentType> for SwComponentType {
672    fn from(service: ServiceSwComponentType) -> Self {
673        SwComponentType::Service(service)
674    }
675}
676
677impl From<SensorActuatorSwComponentType> for SwComponentType {
678    fn from(sensor_actuator: SensorActuatorSwComponentType) -> Self {
679        SwComponentType::SensorActuator(sensor_actuator)
680    }
681}
682
683impl From<EcuAbstractionSwComponentType> for SwComponentType {
684    fn from(ecu_abstraction: EcuAbstractionSwComponentType) -> Self {
685        SwComponentType::EcuAbstraction(ecu_abstraction)
686    }
687}
688
689impl AbstractSwComponentType for SwComponentType {}
690
691impl SwComponentType {
692    /// remove this `SwComponentType` from the model
693    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
694        match self {
695            SwComponentType::Composition(comp) => comp.remove(deep),
696            SwComponentType::Application(app) => app.remove(deep),
697            SwComponentType::ComplexDeviceDriver(cdd) => cdd.remove(deep),
698            SwComponentType::Service(service) => service.remove(deep),
699            SwComponentType::SensorActuator(sensor_actuator) => sensor_actuator.remove(deep),
700            SwComponentType::EcuAbstraction(ecu_abstraction) => ecu_abstraction.remove(deep),
701        }
702    }
703}
704
705//##################################################################
706
707/// A `SwComponentPrototype` is an instance of a software component type
708#[derive(Debug, Clone, PartialEq, Eq, Hash)]
709pub struct SwComponentPrototype(Element);
710abstraction_element!(SwComponentPrototype, SwComponentPrototype);
711impl IdentifiableAbstractionElement for SwComponentPrototype {}
712
713impl SwComponentPrototype {
714    fn new(
715        name: &str,
716        components: &Element,
717        component_type: &SwComponentType,
718    ) -> Result<Self, AutosarAbstractionError> {
719        let component = components.create_named_sub_element(ElementName::SwComponentPrototype, name)?;
720        component
721            .create_sub_element(ElementName::TypeTref)?
722            .set_reference_target(component_type.element())?;
723
724        Ok(Self(component))
725    }
726
727    /// remove this `SwComponentPrototype` from the model
728    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
729        let ref_parents = get_reference_parents(self.element())?;
730
731        AbstractionElement::remove(self, deep)?;
732
733        for (named_parent, _parent) in ref_parents {
734            if named_parent.element_name() == ElementName::SwcToEcuMapping
735                && let Ok(swc_mapping) = SwcToEcuMapping::try_from(named_parent)
736            {
737                swc_mapping.remove(deep)?;
738            }
739        }
740
741        Ok(())
742    }
743
744    /// get the sw component type that this prototype is based on
745    #[must_use]
746    pub fn component_type(&self) -> Option<SwComponentType> {
747        let component_elem = self
748            .element()
749            .get_sub_element(ElementName::TypeTref)?
750            .get_reference_target()
751            .ok()?;
752        SwComponentType::try_from(component_elem).ok()
753    }
754
755    /// get the composition containing this component
756    pub fn parent_composition(&self) -> Result<CompositionSwComponentType, AutosarAbstractionError> {
757        let parent = self.element().named_parent()?.unwrap();
758        CompositionSwComponentType::try_from(parent)
759    }
760}
761
762//##################################################################
763
764/// The `RootSwCompositionPrototype` is a special kind of `SwComponentPrototype` that represents the root of the composition hierarchy
765#[derive(Debug, Clone, PartialEq, Eq, Hash)]
766pub struct RootSwCompositionPrototype(Element);
767abstraction_element!(RootSwCompositionPrototype, RootSwCompositionPrototype);
768impl IdentifiableAbstractionElement for RootSwCompositionPrototype {}
769
770impl RootSwCompositionPrototype {
771    pub(crate) fn new(
772        name: &str,
773        root_compositions: &Element,
774        composition_type: &CompositionSwComponentType,
775    ) -> Result<Self, AutosarAbstractionError> {
776        let root_composition =
777            root_compositions.create_named_sub_element(ElementName::RootSwCompositionPrototype, name)?;
778        root_composition
779            .create_sub_element(ElementName::SoftwareCompositionTref)?
780            .set_reference_target(composition_type.element())?;
781
782        Ok(Self(root_composition))
783    }
784
785    /// get the composition that this root component is based on
786    #[must_use]
787    pub fn composition(&self) -> Option<CompositionSwComponentType> {
788        let composition_elem = self
789            .element()
790            .get_sub_element(ElementName::SoftwareCompositionTref)?
791            .get_reference_target()
792            .ok()?;
793        CompositionSwComponentType::try_from(composition_elem).ok()
794    }
795}
796
797//##################################################################
798
799/// The `ComponentPrototype` enum represents all possible types of software component prototypes
800#[derive(Debug, Clone, PartialEq, Eq, Hash)]
801pub enum ComponentPrototype {
802    /// the component prototype is a `SwComponentPrototype`
803    SwComponent(SwComponentPrototype),
804    /// the component prototype is a `RootSwCompositionPrototype`
805    RootComposition(RootSwCompositionPrototype),
806}
807
808impl AbstractionElement for ComponentPrototype {
809    fn element(&self) -> &Element {
810        match self {
811            ComponentPrototype::SwComponent(swcp) => swcp.element(),
812            ComponentPrototype::RootComposition(root) => root.element(),
813        }
814    }
815}
816
817impl TryFrom<Element> for ComponentPrototype {
818    type Error = AutosarAbstractionError;
819
820    fn try_from(element: Element) -> Result<Self, Self::Error> {
821        match element.element_name() {
822            ElementName::SwComponentPrototype => Ok(ComponentPrototype::SwComponent(SwComponentPrototype(element))),
823            ElementName::RootSwCompositionPrototype => {
824                Ok(ComponentPrototype::RootComposition(RootSwCompositionPrototype(element)))
825            }
826            _ => Err(AutosarAbstractionError::ConversionError {
827                element,
828                dest: "ComponentPrototype".to_string(),
829            }),
830        }
831    }
832}
833
834impl IdentifiableAbstractionElement for ComponentPrototype {}
835
836impl ComponentPrototype {
837    #[must_use]
838    /// get the sw component type that this prototype is based on
839    pub fn component_type(&self) -> Option<SwComponentType> {
840        match self {
841            ComponentPrototype::SwComponent(swcp) => swcp.component_type(),
842            ComponentPrototype::RootComposition(rc) => rc.composition().map(std::convert::Into::into),
843        }
844    }
845
846    /// get the composition containing this component
847    ///
848    /// if the component is a root composition, this will always return None
849    pub fn parent_composition(&self) -> Result<Option<CompositionSwComponentType>, AutosarAbstractionError> {
850        match self {
851            ComponentPrototype::SwComponent(swcp) => swcp.parent_composition().map(Some),
852            ComponentPrototype::RootComposition(_) => Ok(None),
853        }
854    }
855}
856
857//##################################################################
858
859#[cfg(test)]
860mod test {
861    use super::*;
862    use crate::{AutosarModelAbstraction, SystemCategory};
863    use autosar_data::AutosarVersion;
864
865    #[test]
866    fn software_compositions() {
867        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
868        let package = model.get_or_create_package("/package").unwrap();
869
870        let comp1 = CompositionSwComponentType::new("comp1", &package).unwrap();
871        let comp2 = CompositionSwComponentType::new("comp2", &package).unwrap();
872        let comp3 = CompositionSwComponentType::new("comp3", &package).unwrap();
873        let comp4 = CompositionSwComponentType::new("comp4", &package).unwrap();
874
875        comp1.create_component("comp2", &comp2.clone()).unwrap();
876        comp2.create_component("comp3", &comp3.clone()).unwrap();
877        comp3.create_component("comp4", &comp4.clone()).unwrap();
878
879        assert_eq!(comp1.instances().len(), 0);
880        assert_eq!(comp2.instances().len(), 1);
881        assert_eq!(comp3.instances().len(), 1);
882        assert_eq!(comp4.instances().len(), 1);
883
884        assert!(comp1.is_parent_of(&comp2));
885        assert!(comp1.is_parent_of(&comp3));
886        assert!(comp1.is_parent_of(&comp4));
887
888        assert!(!comp2.is_parent_of(&comp1));
889        assert!(comp2.is_parent_of(&comp3));
890        assert!(comp2.is_parent_of(&comp4));
891
892        assert!(!comp3.is_parent_of(&comp1));
893        assert!(!comp3.is_parent_of(&comp2));
894        assert!(comp3.is_parent_of(&comp4));
895
896        assert!(!comp4.is_parent_of(&comp1));
897        assert!(!comp4.is_parent_of(&comp2));
898        assert!(!comp4.is_parent_of(&comp3));
899    }
900
901    #[test]
902    fn root_composition() {
903        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
904        let package = model.get_or_create_package("/package").unwrap();
905
906        let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
907        let comp = CompositionSwComponentType::new("comp", &package).unwrap();
908        let root_sw_component_prototype = system.set_root_sw_composition("root", &comp).unwrap();
909
910        assert_eq!(
911            ComponentPrototype::RootComposition(root_sw_component_prototype),
912            comp.instances()[0]
913        );
914        assert_eq!(comp.instances().len(), 1);
915    }
916
917    #[test]
918    fn components() {
919        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
920        let package = model.get_or_create_package("/package").unwrap();
921
922        let comp = CompositionSwComponentType::new("comp", &package).unwrap();
923        let app = ApplicationSwComponentType::new("app", &package).unwrap();
924        let cdd = ComplexDeviceDriverSwComponentType::new("cdd", &package).unwrap();
925        let service = ServiceSwComponentType::new("service", &package).unwrap();
926        let sensor_actuator = SensorActuatorSwComponentType::new("sensor_actuator", &package).unwrap();
927        let ecu_abstraction = EcuAbstractionSwComponentType::new("ecu_abstraction", &package).unwrap();
928
929        let container_comp = CompositionSwComponentType::new("container_comp", &package).unwrap();
930        let comp_prototype = container_comp.create_component("comp", &comp.clone()).unwrap();
931        let _app_prototype = container_comp.create_component("app", &app.clone()).unwrap();
932        let _cdd_prototype = container_comp.create_component("cdd", &cdd.clone()).unwrap();
933        let _service_prototype = container_comp.create_component("service", &service.clone()).unwrap();
934        let _sensor_actuator_prototype = container_comp
935            .create_component("sensor_actuator", &sensor_actuator.clone())
936            .unwrap();
937        let _ecu_abstraction_prototype = container_comp
938            .create_component("ecu_abstraction", &ecu_abstraction.clone())
939            .unwrap();
940
941        assert_eq!(container_comp.components().count(), 6);
942        let mut comp_prototype_iter = container_comp.components();
943        assert_eq!(
944            comp_prototype_iter.next().unwrap().component_type().unwrap(),
945            comp.clone().into()
946        );
947        assert_eq!(
948            comp_prototype_iter.next().unwrap().component_type().unwrap(),
949            app.into()
950        );
951        assert_eq!(
952            comp_prototype_iter.next().unwrap().component_type().unwrap(),
953            cdd.into()
954        );
955        assert_eq!(
956            comp_prototype_iter.next().unwrap().component_type().unwrap(),
957            service.into()
958        );
959        assert_eq!(
960            comp_prototype_iter.next().unwrap().component_type().unwrap(),
961            sensor_actuator.into()
962        );
963        assert_eq!(
964            comp_prototype_iter.next().unwrap().component_type().unwrap(),
965            ecu_abstraction.into()
966        );
967        assert!(comp_prototype_iter.next().is_none());
968
969        let component_prototype = ComponentPrototype::SwComponent(comp_prototype);
970        assert_eq!(component_prototype.component_type().unwrap(), comp.into());
971    }
972
973    #[test]
974    fn ports_and_connectors() {
975        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
976        let package = model.get_or_create_package("/package").unwrap();
977
978        // create some components:
979        // comp_parent contains comp_child, swc1, swc2
980        let comp_parent_type = package.create_composition_sw_component_type("comp_parent").unwrap();
981        let comp_child_type = package.create_composition_sw_component_type("comp_child").unwrap();
982        let swc_type = package.create_application_sw_component_type("swc_type1").unwrap();
983
984        let comp_child_proto = comp_parent_type.create_component("comp2", &comp_child_type).unwrap();
985        let swc_proto = comp_parent_type.create_component("swc1", &swc_type).unwrap();
986
987        // create port interfaces: S/R and C/S
988        let port_interface_sr = package.create_sender_receiver_interface("sr").unwrap();
989        let port_interface_cs = package.create_client_server_interface("cs").unwrap();
990
991        // connect S/R ports:
992        // - comp_parent R port to swc R port (delegation)
993        // - swc P port to comp_child R port (assembly)
994        // - comp_child R port to comp_child p port (passthrough)
995        let comp_parent_r_port = comp_parent_type.create_r_port("port_r", &port_interface_sr).unwrap();
996        let swc_r_port = swc_type.create_r_port("port_r", &port_interface_sr).unwrap();
997        let swc_p_port = swc_type.create_p_port("port_p", &port_interface_sr).unwrap();
998        let comp_child_r_port = comp_child_type.create_r_port("port_r", &port_interface_sr).unwrap();
999        let comp_child_p_port = comp_child_type.create_p_port("port_p", &port_interface_sr).unwrap();
1000
1001        comp_parent_type
1002            .create_delegation_connector("sr_delegation", &swc_r_port, &swc_proto, &comp_parent_r_port)
1003            .unwrap();
1004        comp_parent_type
1005            .create_assembly_connector(
1006                "sr_assembly",
1007                &swc_p_port,
1008                &swc_proto,
1009                &comp_child_r_port,
1010                &comp_child_proto,
1011            )
1012            .unwrap();
1013        comp_child_type
1014            .create_pass_through_connector("sr_passthrough", &comp_child_r_port, &comp_child_p_port)
1015            .unwrap();
1016
1017        // connect C/S ports:
1018        // - comp_parent S port to swc S port (delegation)
1019        // - swc C port to comp_child S port (assembly)
1020        // - comp_child S port to comp_child C port (passthrough)
1021        let comp_parent_s_port = comp_parent_type.create_p_port("port_s", &port_interface_cs).unwrap();
1022        let swc_s_port = swc_type.create_p_port("port_s", &port_interface_cs).unwrap();
1023        let swc_c_port = swc_type.create_r_port("port_c", &port_interface_cs).unwrap();
1024        let comp_child_s_port = comp_child_type.create_p_port("port_s", &port_interface_cs).unwrap();
1025        let comp_child_c_port = comp_child_type.create_r_port("port_c", &port_interface_cs).unwrap();
1026
1027        comp_parent_type
1028            .create_delegation_connector("cs_delegation", &swc_s_port, &swc_proto, &comp_parent_s_port)
1029            .unwrap();
1030        comp_parent_type
1031            .create_assembly_connector(
1032                "cs_assembly",
1033                &swc_c_port,
1034                &swc_proto,
1035                &comp_child_s_port,
1036                &comp_child_proto,
1037            )
1038            .unwrap();
1039        comp_child_type
1040            .create_pass_through_connector("cs_passthrough", &comp_child_s_port, &comp_child_c_port)
1041            .unwrap();
1042
1043        // check the connectors
1044        let mut parent_connectors = comp_parent_type.connectors();
1045        assert_eq!(parent_connectors.next().unwrap().name().unwrap(), "sr_delegation");
1046        assert_eq!(parent_connectors.next().unwrap().name().unwrap(), "sr_assembly");
1047        assert_eq!(parent_connectors.next().unwrap().name().unwrap(), "cs_delegation");
1048        assert_eq!(parent_connectors.next().unwrap().name().unwrap(), "cs_assembly");
1049        assert!(parent_connectors.next().is_none());
1050
1051        let mut child_connectors = comp_child_type.connectors();
1052        assert_eq!(child_connectors.next().unwrap().name().unwrap(), "sr_passthrough");
1053        assert_eq!(child_connectors.next().unwrap().name().unwrap(), "cs_passthrough");
1054        assert!(child_connectors.next().is_none());
1055
1056        // create a port group
1057        comp_parent_type.create_port_group("group").unwrap();
1058    }
1059
1060    #[test]
1061    fn remove_swc_type() {
1062        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1063        let package = model.get_or_create_package("/package").unwrap();
1064
1065        let comp_swc_type = CompositionSwComponentType::new("comp", &package).unwrap();
1066        let app_swc_type = ApplicationSwComponentType::new("app", &package).unwrap();
1067        let app_prototype = comp_swc_type.create_component("app", &app_swc_type.clone()).unwrap();
1068
1069        assert_eq!(comp_swc_type.components().count(), 1);
1070
1071        app_swc_type.remove(true).unwrap();
1072
1073        assert_eq!(comp_swc_type.components().count(), 0);
1074        assert!(app_prototype.element().path().is_err());
1075    }
1076}