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,
8    abstraction_element,
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 + 'static {
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 + 'static {
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    /// check if the composition is a parent (or grand-parent, etc.) of the component
149    pub fn is_parent_of<T: AbstractSwComponentType>(&self, other: &T) -> bool {
150        // the expectation is that in normal cases each component has only one parent
151        // additionally there should never be any cycles in the composition hierarchy
152        let mut work_items = other.parent_compositions();
153        let mut counter = 1000; // just to prevent infinite loops, since I don't trust files generated by other tools
154        while !work_items.is_empty() && counter > 0 {
155            counter -= 1;
156            if work_items.contains(self) {
157                return true;
158            }
159            // the uses of pop here makes this a depth-first search in the case where there are multiple parents
160            let item = work_items.pop().unwrap();
161            work_items.extend(item.parent_compositions());
162        }
163
164        false
165    }
166
167    /// create a component of type `component_type` in the composition
168    ///
169    /// It is not allowed to form cycles in the composition hierarchy, and this will return an error
170    pub fn create_component<T: Into<SwComponentType> + Clone>(
171        &self,
172        name: &str,
173        component_type: &T,
174    ) -> Result<SwComponentPrototype, AutosarAbstractionError> {
175        let component_type = component_type.clone().into();
176        if let SwComponentType::Composition(composition_component) = &component_type {
177            if composition_component.is_parent_of(self) {
178                return Err(AutosarAbstractionError::InvalidParameter(
179                    "Creating a cycle in the composition hierarchy".to_string(),
180                ));
181            }
182        }
183
184        let components = self.element().get_or_create_sub_element(ElementName::Components)?;
185        SwComponentPrototype::new(name, &components, &component_type)
186    }
187
188    /// get an iterator over the components of the composition
189    pub fn components(&self) -> impl Iterator<Item = SwComponentPrototype> + Send + 'static {
190        self.element()
191            .get_sub_element(ElementName::Components)
192            .into_iter()
193            .flat_map(|components| components.sub_elements())
194            .filter_map(|elem| SwComponentPrototype::try_from(elem).ok())
195    }
196
197    /// create a new delegation connector between an inner port and an outer port
198    ///
199    /// The two ports must be compatible.
200    pub fn create_delegation_connector<T1: Into<PortPrototype> + Clone, T2: Into<PortPrototype> + Clone>(
201        &self,
202        name: &str,
203        inner_port: &T1,
204        inner_sw_prototype: &SwComponentPrototype,
205        outer_port: &T2,
206    ) -> Result<DelegationSwConnector, AutosarAbstractionError> {
207        self.create_delegation_connector_internal(
208            name,
209            &inner_port.clone().into(),
210            inner_sw_prototype,
211            &outer_port.clone().into(),
212        )
213    }
214
215    /// create a new delegation connector between an inner port and an outer port
216    /// this is the actual implementation of the public method, but without the generic parameters
217    fn create_delegation_connector_internal(
218        &self,
219        name: &str,
220        inner_port: &PortPrototype,
221        inner_sw_prototype: &SwComponentPrototype,
222        outer_port: &PortPrototype,
223    ) -> Result<DelegationSwConnector, AutosarAbstractionError> {
224        // check the compatibility of the interfaces
225        let interface_1 = inner_port.port_interface()?;
226        let interface_2 = outer_port.port_interface()?;
227        if std::mem::discriminant(&interface_1) != std::mem::discriminant(&interface_2) {
228            return Err(AutosarAbstractionError::InvalidParameter(
229                "The interfaces of the two ports are not compatible".to_string(),
230            ));
231        }
232
233        // check that the inner port is part of the inner component
234        let inner_swc_from_port = SwComponentType::try_from(inner_port.element().named_parent()?.unwrap())?;
235        let inner_swc_from_component =
236            inner_sw_prototype
237                .component_type()
238                .ok_or(AutosarAbstractionError::InvalidParameter(
239                    "The inner component is incomplete and lacks a type reference".to_string(),
240                ))?;
241        if inner_swc_from_port != inner_swc_from_component {
242            return Err(AutosarAbstractionError::InvalidParameter(
243                "The inner port must be part of the inner component".to_string(),
244            ));
245        }
246
247        let swc_self = self.clone().into();
248        let outer_swc_from_port = SwComponentType::try_from(outer_port.element().named_parent()?.unwrap())?;
249        if outer_swc_from_port != swc_self {
250            return Err(AutosarAbstractionError::InvalidParameter(
251                "The outer port must be part of the composition".to_string(),
252            ));
253        }
254
255        // create the delegation connector
256        let connectors = self.element().get_or_create_sub_element(ElementName::Connectors)?;
257
258        DelegationSwConnector::new(
259            name,
260            &connectors,
261            inner_port, // inner port = port of the contained component
262            inner_sw_prototype,
263            outer_port, // outer port = port of the composition
264        )
265    }
266
267    /// create a new assembly connector between two ports of contained software components
268    ///
269    /// The two ports must be compatible.
270    pub fn create_assembly_connector<T1: Into<PortPrototype> + Clone, T2: Into<PortPrototype> + Clone>(
271        &self,
272        name: &str,
273        port_1: &T1,
274        sw_prototype_1: &SwComponentPrototype,
275        port_2: &T2,
276        sw_prototype_2: &SwComponentPrototype,
277    ) -> Result<AssemblySwConnector, AutosarAbstractionError> {
278        self.create_assembly_connector_internal(
279            name,
280            &port_1.clone().into(),
281            sw_prototype_1,
282            &port_2.clone().into(),
283            sw_prototype_2,
284        )
285    }
286
287    fn create_assembly_connector_internal(
288        &self,
289        name: &str,
290        port_1: &PortPrototype,
291        sw_prototype_1: &SwComponentPrototype,
292        port_2: &PortPrototype,
293        sw_prototype_2: &SwComponentPrototype,
294    ) -> Result<AssemblySwConnector, AutosarAbstractionError> {
295        // check the compatibility of the interfaces
296        let interface_1 = port_1.port_interface()?;
297        let interface_2 = port_2.port_interface()?;
298        if std::mem::discriminant(&interface_1) != std::mem::discriminant(&interface_2) {
299            return Err(AutosarAbstractionError::InvalidParameter(
300                "The interfaces of the two ports are not compatible".to_string(),
301            ));
302        }
303
304        // check that the ports are part of the correct components
305        let swc_1_from_port = SwComponentType::try_from(port_1.element().named_parent()?.unwrap())?;
306        let swc_1_from_component = sw_prototype_1
307            .component_type()
308            .ok_or(AutosarAbstractionError::InvalidParameter(
309                "SW component prototype 1 is incomplete and lacks a type reference".to_string(),
310            ))?;
311        if swc_1_from_port != swc_1_from_component {
312            return Err(AutosarAbstractionError::InvalidParameter(
313                "The first port must be part of the first software component".to_string(),
314            ));
315        }
316
317        let swc_2_from_port = SwComponentType::try_from(port_2.element().named_parent()?.unwrap())?;
318        let swc_2_from_component = sw_prototype_2
319            .component_type()
320            .ok_or(AutosarAbstractionError::InvalidParameter(
321                "SW component prototype 2 is incomplete and lacks a type reference".to_string(),
322            ))?;
323        if swc_2_from_port != swc_2_from_component {
324            return Err(AutosarAbstractionError::InvalidParameter(
325                "The second port must be part of the second software component".to_string(),
326            ));
327        }
328
329        // check that both SWCs are part of the composition
330        if &sw_prototype_1.parent_composition()? != self {
331            return Err(AutosarAbstractionError::InvalidParameter(
332                "The first software component must be part of the composition".to_string(),
333            ));
334        }
335        if &sw_prototype_2.parent_composition()? != self {
336            return Err(AutosarAbstractionError::InvalidParameter(
337                "The second software component must be part of the composition".to_string(),
338            ));
339        }
340
341        // create the assembly connector
342        let connectors = self.element().get_or_create_sub_element(ElementName::Connectors)?;
343        AssemblySwConnector::new(name, &connectors, port_1, sw_prototype_1, port_2, sw_prototype_2)
344    }
345
346    /// create a new passthrough connector between two outer ports of the composition
347    ///
348    /// The two ports must be compatible.
349    pub fn create_pass_through_connector<T1: Into<PortPrototype> + Clone, T2: Into<PortPrototype> + Clone>(
350        &self,
351        name: &str,
352        port_1: &T1,
353        port_2: &T2,
354    ) -> Result<PassThroughSwConnector, AutosarAbstractionError> {
355        self.create_pass_through_connector_internal(name, &port_1.clone().into(), &port_2.clone().into())
356    }
357
358    fn create_pass_through_connector_internal(
359        &self,
360        name: &str,
361        port_1: &PortPrototype,
362        port_2: &PortPrototype,
363    ) -> Result<PassThroughSwConnector, AutosarAbstractionError> {
364        // check the compatibility of the interfaces
365        let interface_1 = port_1.port_interface()?;
366        let interface_2 = port_2.port_interface()?;
367        if std::mem::discriminant(&interface_1) != std::mem::discriminant(&interface_2) {
368            return Err(AutosarAbstractionError::InvalidParameter(
369                "The interfaces of the two ports are not compatible".to_string(),
370            ));
371        }
372
373        // decide what kind of connector to create
374        let swc_1 = SwComponentType::try_from(port_1.element().named_parent()?.unwrap())?;
375        let swc_2 = SwComponentType::try_from(port_2.element().named_parent()?.unwrap())?;
376        let swc_self = self.clone().into();
377
378        // both ports must be part of the composition
379        if swc_1 != swc_self || swc_2 != swc_self {
380            return Err(AutosarAbstractionError::InvalidParameter(
381                "The ports must be part of the composition".to_string(),
382            ));
383        }
384
385        let connectors = self.element().get_or_create_sub_element(ElementName::Connectors)?;
386        PassThroughSwConnector::new(name, &connectors, port_1, port_2)
387    }
388
389    /// iterate over all connectors
390    pub fn connectors(&self) -> impl Iterator<Item = SwConnector> + Send + 'static {
391        self.element()
392            .get_sub_element(ElementName::Connectors)
393            .into_iter()
394            .flat_map(|connectors| connectors.sub_elements())
395            .filter_map(|elem| SwConnector::try_from(elem).ok())
396    }
397}
398
399impl AbstractSwComponentType for CompositionSwComponentType {}
400
401//##################################################################
402
403/// An `ApplicationSwComponentType` is a software component that provides application functionality
404///
405/// Use [`ArPackage::create_application_sw_component_type`] to create a new application sw component type.
406#[derive(Debug, Clone, PartialEq, Eq, Hash)]
407pub struct ApplicationSwComponentType(Element);
408abstraction_element!(ApplicationSwComponentType, ApplicationSwComponentType);
409impl IdentifiableAbstractionElement for ApplicationSwComponentType {}
410
411impl ApplicationSwComponentType {
412    /// create a new application component with the given name
413    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
414        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
415        let application = elements.create_named_sub_element(ElementName::ApplicationSwComponentType, name)?;
416        Ok(Self(application))
417    }
418}
419
420impl AbstractSwComponentType for ApplicationSwComponentType {}
421impl AtomicSwComponentType for ApplicationSwComponentType {}
422
423//##################################################################
424
425/// A `ComplexDeviceDriverSwComponentType` is a software component that provides complex device driver functionality
426///
427/// Use [`ArPackage::create_complex_device_driver_sw_component_type`] to create a new complex device driver sw component type.
428#[derive(Debug, Clone, PartialEq, Eq, Hash)]
429pub struct ComplexDeviceDriverSwComponentType(Element);
430abstraction_element!(ComplexDeviceDriverSwComponentType, ComplexDeviceDriverSwComponentType);
431impl IdentifiableAbstractionElement for ComplexDeviceDriverSwComponentType {}
432
433impl ComplexDeviceDriverSwComponentType {
434    /// create a new complex device driver component with the given name
435    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
436        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
437        let cdd = elements.create_named_sub_element(ElementName::ComplexDeviceDriverSwComponentType, name)?;
438        Ok(Self(cdd))
439    }
440}
441
442impl AbstractSwComponentType for ComplexDeviceDriverSwComponentType {}
443impl AtomicSwComponentType for ComplexDeviceDriverSwComponentType {}
444
445//##################################################################
446
447/// `ServiceSwComponentType` is used for configuring services for a given ECU. Instances of this class should only
448/// be created in ECU Configuration phase for the specific purpose of the service configuration.
449///
450/// Use [`ArPackage::create_service_sw_component_type`] to create a new service sw component type.
451#[derive(Debug, Clone, PartialEq, Eq, Hash)]
452pub struct ServiceSwComponentType(Element);
453abstraction_element!(ServiceSwComponentType, ServiceSwComponentType);
454impl IdentifiableAbstractionElement for ServiceSwComponentType {}
455
456impl ServiceSwComponentType {
457    /// create a new service component with the given name
458    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
459        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
460        let service = elements.create_named_sub_element(ElementName::ServiceSwComponentType, name)?;
461        Ok(Self(service))
462    }
463}
464
465impl AbstractSwComponentType for ServiceSwComponentType {}
466impl AtomicSwComponentType for ServiceSwComponentType {}
467
468//##################################################################
469
470/// `SensorActuatorSwComponentType` is used to connect sensor/acutator devices to the ECU configuration
471///
472/// Use [`ArPackage::create_sensor_actuator_sw_component_type`] to create a new sensor/actuator sw component type.
473#[derive(Debug, Clone, PartialEq, Eq, Hash)]
474pub struct SensorActuatorSwComponentType(Element);
475abstraction_element!(SensorActuatorSwComponentType, SensorActuatorSwComponentType);
476impl IdentifiableAbstractionElement for SensorActuatorSwComponentType {}
477
478impl SensorActuatorSwComponentType {
479    /// create a new sensor/actuator component with the given name
480    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
481        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
482        let sensor_actuator = elements.create_named_sub_element(ElementName::SensorActuatorSwComponentType, name)?;
483        Ok(Self(sensor_actuator))
484    }
485}
486
487impl AbstractSwComponentType for SensorActuatorSwComponentType {}
488impl AtomicSwComponentType for SensorActuatorSwComponentType {}
489
490//##################################################################
491
492/// The `ECUAbstraction` is a special `AtomicSwComponentType` that resides between a software-component
493/// that wants to access ECU periphery and the Microcontroller Abstraction
494///
495/// Use [`ArPackage::create_ecu_abstraction_sw_component_type`] to create a new ECU abstraction sw component type.
496#[derive(Debug, Clone, PartialEq, Eq, Hash)]
497pub struct EcuAbstractionSwComponentType(Element);
498abstraction_element!(EcuAbstractionSwComponentType, EcuAbstractionSwComponentType);
499impl IdentifiableAbstractionElement for EcuAbstractionSwComponentType {}
500
501impl EcuAbstractionSwComponentType {
502    /// create a new ECU abstraction component with the given name
503    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
504        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
505        let ecu_abstraction = elements.create_named_sub_element(ElementName::EcuAbstractionSwComponentType, name)?;
506        Ok(Self(ecu_abstraction))
507    }
508}
509
510impl AbstractSwComponentType for EcuAbstractionSwComponentType {}
511impl AtomicSwComponentType for EcuAbstractionSwComponentType {}
512
513//##################################################################
514
515/// The `SwComponentType` enum represents all possible types of software components
516#[derive(Debug, Clone, PartialEq, Eq, Hash)]
517pub enum SwComponentType {
518    /// the component is `CompositionSwComponentType`
519    Composition(CompositionSwComponentType),
520    /// the component is `ApplicationSwComponentType`
521    Application(ApplicationSwComponentType),
522    /// the component is `ComplexDeviceDriverSwComponentType`
523    ComplexDeviceDriver(ComplexDeviceDriverSwComponentType),
524    /// the component is `ServiceSwComponentType`
525    Service(ServiceSwComponentType),
526    /// the component is `SensorActuatorSwComponentType`
527    SensorActuator(SensorActuatorSwComponentType),
528    /// the component is `EcuAbstractionSwComponentType`
529    EcuAbstraction(EcuAbstractionSwComponentType),
530}
531
532impl AbstractionElement for SwComponentType {
533    fn element(&self) -> &Element {
534        match self {
535            SwComponentType::Composition(comp) => comp.element(),
536            SwComponentType::Application(app) => app.element(),
537            SwComponentType::ComplexDeviceDriver(cdd) => cdd.element(),
538            SwComponentType::Service(service) => service.element(),
539            SwComponentType::SensorActuator(sensor_actuator) => sensor_actuator.element(),
540            SwComponentType::EcuAbstraction(ecu_abstraction) => ecu_abstraction.element(),
541        }
542    }
543}
544
545impl IdentifiableAbstractionElement for SwComponentType {}
546
547impl TryFrom<Element> for SwComponentType {
548    type Error = AutosarAbstractionError;
549
550    fn try_from(element: Element) -> Result<Self, Self::Error> {
551        match element.element_name() {
552            ElementName::CompositionSwComponentType => {
553                Ok(SwComponentType::Composition(CompositionSwComponentType(element)))
554            }
555            ElementName::ApplicationSwComponentType => {
556                Ok(SwComponentType::Application(ApplicationSwComponentType(element)))
557            }
558            ElementName::ComplexDeviceDriverSwComponentType => Ok(SwComponentType::ComplexDeviceDriver(
559                ComplexDeviceDriverSwComponentType(element),
560            )),
561            ElementName::ServiceSwComponentType => Ok(SwComponentType::Service(ServiceSwComponentType(element))),
562            ElementName::SensorActuatorSwComponentType => {
563                Ok(SwComponentType::SensorActuator(SensorActuatorSwComponentType(element)))
564            }
565            ElementName::EcuAbstractionSwComponentType => {
566                Ok(SwComponentType::EcuAbstraction(EcuAbstractionSwComponentType(element)))
567            }
568            _ => Err(AutosarAbstractionError::ConversionError {
569                element,
570                dest: "SwComponentType".to_string(),
571            }),
572        }
573    }
574}
575
576impl From<CompositionSwComponentType> for SwComponentType {
577    fn from(comp: CompositionSwComponentType) -> Self {
578        SwComponentType::Composition(comp)
579    }
580}
581
582impl From<ApplicationSwComponentType> for SwComponentType {
583    fn from(app: ApplicationSwComponentType) -> Self {
584        SwComponentType::Application(app)
585    }
586}
587
588impl From<ComplexDeviceDriverSwComponentType> for SwComponentType {
589    fn from(cdd: ComplexDeviceDriverSwComponentType) -> Self {
590        SwComponentType::ComplexDeviceDriver(cdd)
591    }
592}
593
594impl From<ServiceSwComponentType> for SwComponentType {
595    fn from(service: ServiceSwComponentType) -> Self {
596        SwComponentType::Service(service)
597    }
598}
599
600impl From<SensorActuatorSwComponentType> for SwComponentType {
601    fn from(sensor_actuator: SensorActuatorSwComponentType) -> Self {
602        SwComponentType::SensorActuator(sensor_actuator)
603    }
604}
605
606impl From<EcuAbstractionSwComponentType> for SwComponentType {
607    fn from(ecu_abstraction: EcuAbstractionSwComponentType) -> Self {
608        SwComponentType::EcuAbstraction(ecu_abstraction)
609    }
610}
611
612impl AbstractSwComponentType for SwComponentType {}
613
614//##################################################################
615
616/// A `SwComponentPrototype` is an instance of a software component type
617#[derive(Debug, Clone, PartialEq, Eq, Hash)]
618pub struct SwComponentPrototype(Element);
619abstraction_element!(SwComponentPrototype, SwComponentPrototype);
620impl IdentifiableAbstractionElement for SwComponentPrototype {}
621
622impl SwComponentPrototype {
623    fn new(
624        name: &str,
625        components: &Element,
626        component_type: &SwComponentType,
627    ) -> Result<Self, AutosarAbstractionError> {
628        let component = components.create_named_sub_element(ElementName::SwComponentPrototype, name)?;
629        component
630            .create_sub_element(ElementName::TypeTref)?
631            .set_reference_target(component_type.element())?;
632
633        Ok(Self(component))
634    }
635
636    /// get the sw component type that this prototype is based on
637    #[must_use]
638    pub fn component_type(&self) -> Option<SwComponentType> {
639        let component_elem = self
640            .element()
641            .get_sub_element(ElementName::TypeTref)?
642            .get_reference_target()
643            .ok()?;
644        SwComponentType::try_from(component_elem).ok()
645    }
646
647    /// get the composition containing this component
648    pub fn parent_composition(&self) -> Result<CompositionSwComponentType, AutosarAbstractionError> {
649        let parent = self.element().named_parent()?.unwrap();
650        CompositionSwComponentType::try_from(parent)
651    }
652}
653
654//##################################################################
655
656/// The `RootSwCompositionPrototype` is a special kind of `SwComponentPrototype` that represents the root of the composition hierarchy
657#[derive(Debug, Clone, PartialEq, Eq, Hash)]
658pub struct RootSwCompositionPrototype(Element);
659abstraction_element!(RootSwCompositionPrototype, RootSwCompositionPrototype);
660impl IdentifiableAbstractionElement for RootSwCompositionPrototype {}
661
662impl RootSwCompositionPrototype {
663    pub(crate) fn new(
664        name: &str,
665        root_compositions: &Element,
666        composition_type: &CompositionSwComponentType,
667    ) -> Result<Self, AutosarAbstractionError> {
668        let root_composition =
669            root_compositions.create_named_sub_element(ElementName::RootSwCompositionPrototype, name)?;
670        root_composition
671            .create_sub_element(ElementName::SoftwareCompositionTref)?
672            .set_reference_target(composition_type.element())?;
673
674        Ok(Self(root_composition))
675    }
676
677    /// get the composition that this root component is based on
678    #[must_use]
679    pub fn composition(&self) -> Option<CompositionSwComponentType> {
680        let composition_elem = self
681            .element()
682            .get_sub_element(ElementName::SoftwareCompositionTref)?
683            .get_reference_target()
684            .ok()?;
685        CompositionSwComponentType::try_from(composition_elem).ok()
686    }
687}
688
689//##################################################################
690
691/// The `ComponentPrototype` enum represents all possible types of software component prototypes
692#[derive(Debug, Clone, PartialEq, Eq, Hash)]
693pub enum ComponentPrototype {
694    /// the component prototype is a `SwComponentPrototype`
695    SwComponent(SwComponentPrototype),
696    /// the component prototype is a `RootSwCompositionPrototype`
697    RootComposition(RootSwCompositionPrototype),
698}
699
700impl AbstractionElement for ComponentPrototype {
701    fn element(&self) -> &Element {
702        match self {
703            ComponentPrototype::SwComponent(swcp) => swcp.element(),
704            ComponentPrototype::RootComposition(root) => root.element(),
705        }
706    }
707}
708
709impl TryFrom<Element> for ComponentPrototype {
710    type Error = AutosarAbstractionError;
711
712    fn try_from(element: Element) -> Result<Self, Self::Error> {
713        match element.element_name() {
714            ElementName::SwComponentPrototype => Ok(ComponentPrototype::SwComponent(SwComponentPrototype(element))),
715            ElementName::RootSwCompositionPrototype => {
716                Ok(ComponentPrototype::RootComposition(RootSwCompositionPrototype(element)))
717            }
718            _ => Err(AutosarAbstractionError::ConversionError {
719                element,
720                dest: "ComponentPrototype".to_string(),
721            }),
722        }
723    }
724}
725
726impl IdentifiableAbstractionElement for ComponentPrototype {}
727
728impl ComponentPrototype {
729    #[must_use]
730    /// get the sw component type that this prototype is based on
731    pub fn component_type(&self) -> Option<SwComponentType> {
732        match self {
733            ComponentPrototype::SwComponent(swcp) => swcp.component_type(),
734            ComponentPrototype::RootComposition(rc) => rc.composition().map(std::convert::Into::into),
735        }
736    }
737
738    /// get the composition containing this component
739    ///
740    /// if the component is a root composition, this will always return None
741    pub fn parent_composition(&self) -> Result<Option<CompositionSwComponentType>, AutosarAbstractionError> {
742        match self {
743            ComponentPrototype::SwComponent(swcp) => swcp.parent_composition().map(Some),
744            ComponentPrototype::RootComposition(_) => Ok(None),
745        }
746    }
747}
748
749//##################################################################
750
751#[cfg(test)]
752mod test {
753    use super::*;
754    use crate::{AutosarModelAbstraction, SystemCategory};
755    use autosar_data::AutosarVersion;
756
757    #[test]
758    fn software_compositions() {
759        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
760        let package = model.get_or_create_package("/package").unwrap();
761
762        let comp1 = CompositionSwComponentType::new("comp1", &package).unwrap();
763        let comp2 = CompositionSwComponentType::new("comp2", &package).unwrap();
764        let comp3 = CompositionSwComponentType::new("comp3", &package).unwrap();
765        let comp4 = CompositionSwComponentType::new("comp4", &package).unwrap();
766
767        comp1.create_component("comp2", &comp2.clone()).unwrap();
768        comp2.create_component("comp3", &comp3.clone()).unwrap();
769        comp3.create_component("comp4", &comp4.clone()).unwrap();
770
771        assert_eq!(comp1.instances().len(), 0);
772        assert_eq!(comp2.instances().len(), 1);
773        assert_eq!(comp3.instances().len(), 1);
774        assert_eq!(comp4.instances().len(), 1);
775
776        assert!(comp1.is_parent_of(&comp2));
777        assert!(comp1.is_parent_of(&comp3));
778        assert!(comp1.is_parent_of(&comp4));
779
780        assert!(!comp2.is_parent_of(&comp1));
781        assert!(comp2.is_parent_of(&comp3));
782        assert!(comp2.is_parent_of(&comp4));
783
784        assert!(!comp3.is_parent_of(&comp1));
785        assert!(!comp3.is_parent_of(&comp2));
786        assert!(comp3.is_parent_of(&comp4));
787
788        assert!(!comp4.is_parent_of(&comp1));
789        assert!(!comp4.is_parent_of(&comp2));
790        assert!(!comp4.is_parent_of(&comp3));
791    }
792
793    #[test]
794    fn root_composition() {
795        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
796        let package = model.get_or_create_package("/package").unwrap();
797
798        let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
799        let comp = CompositionSwComponentType::new("comp", &package).unwrap();
800        let root_sw_component_prototype = system.set_root_sw_composition("root", &comp).unwrap();
801
802        assert_eq!(
803            ComponentPrototype::RootComposition(root_sw_component_prototype),
804            comp.instances()[0]
805        );
806        assert_eq!(comp.instances().len(), 1);
807    }
808
809    #[test]
810    fn components() {
811        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
812        let package = model.get_or_create_package("/package").unwrap();
813
814        let comp = CompositionSwComponentType::new("comp", &package).unwrap();
815        let app = ApplicationSwComponentType::new("app", &package).unwrap();
816        let cdd = ComplexDeviceDriverSwComponentType::new("cdd", &package).unwrap();
817        let service = ServiceSwComponentType::new("service", &package).unwrap();
818        let sensor_actuator = SensorActuatorSwComponentType::new("sensor_actuator", &package).unwrap();
819        let ecu_abstraction = EcuAbstractionSwComponentType::new("ecu_abstraction", &package).unwrap();
820
821        let container_comp = CompositionSwComponentType::new("container_comp", &package).unwrap();
822        let comp_prototype = container_comp.create_component("comp", &comp.clone()).unwrap();
823        let _app_prototype = container_comp.create_component("app", &app.clone()).unwrap();
824        let _cdd_prototype = container_comp.create_component("cdd", &cdd.clone()).unwrap();
825        let _service_prototype = container_comp.create_component("service", &service.clone()).unwrap();
826        let _sensor_actuator_prototype = container_comp
827            .create_component("sensor_actuator", &sensor_actuator.clone())
828            .unwrap();
829        let _ecu_abstraction_prototype = container_comp
830            .create_component("ecu_abstraction", &ecu_abstraction.clone())
831            .unwrap();
832
833        assert_eq!(container_comp.components().count(), 6);
834        let mut comp_prototype_iter = container_comp.components();
835        assert_eq!(
836            comp_prototype_iter.next().unwrap().component_type().unwrap(),
837            comp.clone().into()
838        );
839        assert_eq!(
840            comp_prototype_iter.next().unwrap().component_type().unwrap(),
841            app.into()
842        );
843        assert_eq!(
844            comp_prototype_iter.next().unwrap().component_type().unwrap(),
845            cdd.into()
846        );
847        assert_eq!(
848            comp_prototype_iter.next().unwrap().component_type().unwrap(),
849            service.into()
850        );
851        assert_eq!(
852            comp_prototype_iter.next().unwrap().component_type().unwrap(),
853            sensor_actuator.into()
854        );
855        assert_eq!(
856            comp_prototype_iter.next().unwrap().component_type().unwrap(),
857            ecu_abstraction.into()
858        );
859        assert!(comp_prototype_iter.next().is_none());
860
861        let component_prototype = ComponentPrototype::SwComponent(comp_prototype);
862        assert_eq!(component_prototype.component_type().unwrap(), comp.into());
863    }
864
865    #[test]
866    fn ports_and_connectors() {
867        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
868        let package = model.get_or_create_package("/package").unwrap();
869
870        // create some components:
871        // comp_parent contains comp_child, swc1, swc2
872        let comp_parent_type = package.create_composition_sw_component_type("comp_parent").unwrap();
873        let comp_child_type = package.create_composition_sw_component_type("comp_child").unwrap();
874        let swc_type = package.create_application_sw_component_type("swc_type1").unwrap();
875
876        let comp_child_proto = comp_parent_type.create_component("comp2", &comp_child_type).unwrap();
877        let swc_proto = comp_parent_type.create_component("swc1", &swc_type).unwrap();
878
879        // create port interfaces: S/R and C/S
880        let port_interface_sr = package.create_sender_receiver_interface("sr").unwrap();
881        let port_interface_cs = package.create_client_server_interface("cs").unwrap();
882
883        // connect S/R ports:
884        // - comp_parent R port to swc R port (delegation)
885        // - swc P port to comp_child R port (assembly)
886        // - comp_child R port to comp_child p port (passthrough)
887        let comp_parent_r_port = comp_parent_type.create_r_port("port_r", &port_interface_sr).unwrap();
888        let swc_r_port = swc_type.create_r_port("port_r", &port_interface_sr).unwrap();
889        let swc_p_port = swc_type.create_p_port("port_p", &port_interface_sr).unwrap();
890        let comp_child_r_port = comp_child_type.create_r_port("port_r", &port_interface_sr).unwrap();
891        let comp_child_p_port = comp_child_type.create_p_port("port_p", &port_interface_sr).unwrap();
892
893        comp_parent_type
894            .create_delegation_connector("sr_delegation", &swc_r_port, &swc_proto, &comp_parent_r_port)
895            .unwrap();
896        comp_parent_type
897            .create_assembly_connector(
898                "sr_assembly",
899                &swc_p_port,
900                &swc_proto,
901                &comp_child_r_port,
902                &comp_child_proto,
903            )
904            .unwrap();
905        comp_child_type
906            .create_pass_through_connector("sr_passthrough", &comp_child_r_port, &comp_child_p_port)
907            .unwrap();
908
909        // connect C/S ports:
910        // - comp_parent S port to swc S port (delegation)
911        // - swc C port to comp_child S port (assembly)
912        // - comp_child S port to comp_child C port (passthrough)
913        let comp_parent_s_port = comp_parent_type.create_p_port("port_s", &port_interface_cs).unwrap();
914        let swc_s_port = swc_type.create_p_port("port_s", &port_interface_cs).unwrap();
915        let swc_c_port = swc_type.create_r_port("port_c", &port_interface_cs).unwrap();
916        let comp_child_s_port = comp_child_type.create_p_port("port_s", &port_interface_cs).unwrap();
917        let comp_child_c_port = comp_child_type.create_r_port("port_c", &port_interface_cs).unwrap();
918
919        comp_parent_type
920            .create_delegation_connector("cs_delegation", &swc_s_port, &swc_proto, &comp_parent_s_port)
921            .unwrap();
922        comp_parent_type
923            .create_assembly_connector(
924                "cs_assembly",
925                &swc_c_port,
926                &swc_proto,
927                &comp_child_s_port,
928                &comp_child_proto,
929            )
930            .unwrap();
931        comp_child_type
932            .create_pass_through_connector("cs_passthrough", &comp_child_s_port, &comp_child_c_port)
933            .unwrap();
934
935        // check the connectors
936        let mut parent_connectors = comp_parent_type.connectors();
937        assert_eq!(parent_connectors.next().unwrap().name().unwrap(), "sr_delegation");
938        assert_eq!(parent_connectors.next().unwrap().name().unwrap(), "sr_assembly");
939        assert_eq!(parent_connectors.next().unwrap().name().unwrap(), "cs_delegation");
940        assert_eq!(parent_connectors.next().unwrap().name().unwrap(), "cs_assembly");
941        assert!(parent_connectors.next().is_none());
942
943        let mut child_connectors = comp_child_type.connectors();
944        assert_eq!(child_connectors.next().unwrap().name().unwrap(), "sr_passthrough");
945        assert_eq!(child_connectors.next().unwrap().name().unwrap(), "cs_passthrough");
946        assert!(child_connectors.next().is_none());
947
948        // create a port group
949        comp_parent_type.create_port_group("group").unwrap();
950    }
951}