autosar_data_abstraction/software_component/
connector.rs

1use crate::{
2    AbstractionElement, AutosarAbstractionError, IdentifiableAbstractionElement, abstraction_element,
3    software_component,
4};
5use autosar_data::{Element, ElementName};
6use software_component::{PortInterface, PortPrototype, SwComponentPrototype};
7
8//#########################################################
9
10/// A `DelegationSwConnector` connects a port of a software component that is contained inside a `SwCompositionType` with a port of the `SwCompositionType`.
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub struct DelegationSwConnector(Element);
13abstraction_element!(DelegationSwConnector, DelegationSwConnector);
14impl IdentifiableAbstractionElement for DelegationSwConnector {}
15
16impl DelegationSwConnector {
17    /// Create a new `DelegationSwConnector`
18    ///
19    /// # Arguments
20    /// `inner_port`: A port of a software component that is contained inside the `SwCompositionType`.
21    /// `outer_port`: A port of the `SwCompositionType`.
22    pub(crate) fn new(
23        name: &str,
24        parent_element: &Element,
25        inner_port: &PortPrototype,
26        inner_sw_prototype: &SwComponentPrototype,
27        outer_port: &PortPrototype,
28    ) -> Result<Self, AutosarAbstractionError> {
29        let inner_port_interface = inner_port
30            .port_interface()
31            .ok_or(AutosarAbstractionError::InvalidParameter(
32                "Invalid port lacks a port interface".to_string(),
33            ))?;
34        // the caller (CompositionSwComponentType::add_connector) ensures that the inner and outer port both have the same kind of interface
35        match &inner_port_interface {
36            PortInterface::SenderReceiverInterface(_) | PortInterface::NvDataInterface(_) => {
37                if (matches!(inner_port, PortPrototype::R(_)) && matches!(outer_port, PortPrototype::P(_)))
38                    || (matches!(inner_port, PortPrototype::P(_)) && matches!(outer_port, PortPrototype::R(_)))
39                {
40                    return Err(AutosarAbstractionError::InvalidParameter(
41                        "Invalid combination of provide and require ports".to_string(),
42                    ));
43                }
44            }
45            PortInterface::ClientServerInterface(_)
46            | PortInterface::ModeSwitchInterface(_)
47            | PortInterface::TriggerInterface(_) => {
48                // table of valid combinations; Table 4.14 in AUTOSAR_TPS_SoftwareComponentTemplate.pdf:
49                // inner_port\outer_port | P   | R   | PR
50                // P                     | yes | no  | no
51                // R                     | no  | yes | no
52                // PR                    | no  | yes | no
53                match (inner_port, outer_port) {
54                    (PortPrototype::P(_) | PortPrototype::PR(_), PortPrototype::P(_))
55                    | (PortPrototype::R(_), PortPrototype::R(_)) => {}
56                    _ => {
57                        return Err(AutosarAbstractionError::InvalidParameter(
58                            "Invalid combination of provide and require ports".to_string(),
59                        ));
60                    }
61                }
62            }
63            PortInterface::ParameterInterface(_) => { /* no specific restrictions on ParameterInterfaces */ }
64        }
65
66        let delegation_sw_connector =
67            parent_element.create_named_sub_element(ElementName::DelegationSwConnector, name)?;
68        let inner_iref = delegation_sw_connector.create_sub_element(ElementName::InnerPortIref)?;
69        // let inner_swc = SwComponentType::try_from(inner_port.element().named_parent()?.unwrap())?;
70        // The inner port is either described by an RPortInCompositionInstanceRef or a PPortInCompositionInstanceRef, depending on the port type.
71        // If the inner port is a PRPortPrototype, the inner port is described by an PPortInCompositionInstanceRef, as required by [TPS_SWCT_01515].
72        if matches!(inner_port, PortPrototype::R(_)) {
73            // inner port is a required port
74            let r_port_in_instance = inner_iref.create_sub_element(ElementName::RPortInCompositionInstanceRef)?;
75            r_port_in_instance
76                .create_sub_element(ElementName::TargetRPortRef)?
77                .set_reference_target(inner_port.element())?;
78            r_port_in_instance
79                .create_sub_element(ElementName::ContextComponentRef)?
80                .set_reference_target(inner_sw_prototype.element())?;
81        } else {
82            // inner port is a provided port or a PR port
83            let p_port_in_instance = inner_iref.create_sub_element(ElementName::PPortInCompositionInstanceRef)?;
84            p_port_in_instance
85                .create_sub_element(ElementName::TargetPPortRef)?
86                .set_reference_target(inner_port.element())?;
87            p_port_in_instance
88                .create_sub_element(ElementName::ContextComponentRef)?
89                .set_reference_target(inner_sw_prototype.element())?;
90        };
91        delegation_sw_connector
92            .create_sub_element(ElementName::OuterPortRef)?
93            .set_reference_target(outer_port.element())?;
94
95        Ok(Self(delegation_sw_connector))
96    }
97
98    /// Get the inner port of the delegation connector
99    #[must_use]
100    pub fn inner_port(&self) -> Option<PortPrototype> {
101        let inner_port_iref = self.element().get_sub_element(ElementName::InnerPortIref)?;
102        if let Some(r_port_in_instance) = inner_port_iref.get_sub_element(ElementName::RPortInCompositionInstanceRef) {
103            let inner_port_elem = r_port_in_instance
104                .get_sub_element(ElementName::TargetRPortRef)?
105                .get_reference_target()
106                .ok()?;
107            PortPrototype::try_from(inner_port_elem).ok()
108        } else if let Some(p_port_in_instance) =
109            inner_port_iref.get_sub_element(ElementName::PPortInCompositionInstanceRef)
110        {
111            let inner_port_elem = p_port_in_instance
112                .get_sub_element(ElementName::TargetPPortRef)?
113                .get_reference_target()
114                .ok()?;
115            PortPrototype::try_from(inner_port_elem).ok()
116        } else {
117            None
118        }
119    }
120
121    /// Get the component containing the inner port of the delegation connector
122    #[must_use]
123    pub fn inner_sw_component(&self) -> Option<SwComponentPrototype> {
124        let inner_port_iref = self.element().get_sub_element(ElementName::InnerPortIref)?;
125        if let Some(r_port_in_instance) = inner_port_iref.get_sub_element(ElementName::RPortInCompositionInstanceRef) {
126            let inner_sw_component_elem = r_port_in_instance
127                .get_sub_element(ElementName::ContextComponentRef)?
128                .get_reference_target()
129                .ok()?;
130            SwComponentPrototype::try_from(inner_sw_component_elem).ok()
131        } else if let Some(p_port_in_instance) =
132            inner_port_iref.get_sub_element(ElementName::PPortInCompositionInstanceRef)
133        {
134            let inner_sw_component_elem = p_port_in_instance
135                .get_sub_element(ElementName::ContextComponentRef)?
136                .get_reference_target()
137                .ok()?;
138            SwComponentPrototype::try_from(inner_sw_component_elem).ok()
139        } else {
140            None
141        }
142    }
143
144    /// Get the outer port of the delegation connector
145    #[must_use]
146    pub fn outer_port(&self) -> Option<PortPrototype> {
147        let outer_port_elem = self
148            .element()
149            .get_sub_element(ElementName::OuterPortRef)?
150            .get_reference_target()
151            .ok()?;
152        PortPrototype::try_from(outer_port_elem).ok()
153    }
154}
155
156//##################################################################
157
158/// An `AssemblySwConnector` connects ports of two `SwCompositionType`s.
159#[derive(Debug, Clone, PartialEq, Eq, Hash)]
160pub struct AssemblySwConnector(Element);
161abstraction_element!(AssemblySwConnector, AssemblySwConnector);
162impl IdentifiableAbstractionElement for AssemblySwConnector {}
163
164impl AssemblySwConnector {
165    /// Create a new `AssemblySwConnector`
166    pub(crate) fn new(
167        name: &str,
168        parent_element: &Element,
169        port_1: &PortPrototype,
170        sw_prototype_1: &SwComponentPrototype,
171        port_2: &PortPrototype,
172        sw_prototype_2: &SwComponentPrototype,
173    ) -> Result<Self, AutosarAbstractionError> {
174        // find the provider and requester port; also filter out invalid combinations such as P-P and R-R
175        let (provider, p_proto_swc, requester, r_proto_swc) = match (port_1, port_2) {
176            (PortPrototype::P(_), PortPrototype::R(_)) => (port_1, sw_prototype_1, port_2, sw_prototype_2),
177            (PortPrototype::R(_), PortPrototype::P(_)) => (port_2, sw_prototype_2, port_1, sw_prototype_1),
178            (PortPrototype::P(_), PortPrototype::PR(_)) => (port_1, sw_prototype_1, port_2, sw_prototype_2),
179            (PortPrototype::PR(_), PortPrototype::P(_)) => (port_2, sw_prototype_2, port_1, sw_prototype_1),
180            (PortPrototype::R(_), PortPrototype::PR(_)) => (port_2, sw_prototype_2, port_1, sw_prototype_1),
181            (PortPrototype::PR(_), PortPrototype::R(_)) => (port_1, sw_prototype_1, port_2, sw_prototype_2),
182            (PortPrototype::PR(_), PortPrototype::PR(_)) => (port_1, sw_prototype_1, port_2, sw_prototype_2),
183            _ => {
184                return Err(AutosarAbstractionError::InvalidParameter(
185                    "Invalid port roles".to_string(),
186                ));
187            }
188        };
189
190        let port_interface = provider
191            .port_interface()
192            .ok_or(AutosarAbstractionError::InvalidParameter(
193                "Invalid port lacks a port interface".to_string(),
194            ))?;
195        // additional restrictions beyond the basic rules in the match above
196        // apply to ClientServer, ModeSwitch, and Trigger interfaces
197        if matches!(
198            &port_interface,
199            PortInterface::ClientServerInterface(_)
200                | PortInterface::ModeSwitchInterface(_)
201                | PortInterface::TriggerInterface(_)
202        ) {
203            // can only connect R to P or PR. All other combinations are forbidden.
204            // As a result of the match above, we know that provider is P or PR and requester is R or PR.
205            if !matches!(requester, PortPrototype::R(_)) {
206                return Err(AutosarAbstractionError::InvalidParameter(
207                    "Invalid combination of provide and require ports".to_string(),
208                ));
209            }
210        }
211
212        let assembly_sw_connector = parent_element.create_named_sub_element(ElementName::AssemblySwConnector, name)?;
213
214        let provider_iref = assembly_sw_connector.create_sub_element(ElementName::ProviderIref)?;
215        provider_iref
216            .create_sub_element(ElementName::TargetPPortRef)?
217            .set_reference_target(provider.element())?;
218        provider_iref
219            .create_sub_element(ElementName::ContextComponentRef)?
220            .set_reference_target(p_proto_swc.element())?;
221        let requester_iref = assembly_sw_connector.create_sub_element(ElementName::RequesterIref)?;
222        requester_iref
223            .create_sub_element(ElementName::TargetRPortRef)?
224            .set_reference_target(requester.element())?;
225        requester_iref
226            .create_sub_element(ElementName::ContextComponentRef)?
227            .set_reference_target(r_proto_swc.element())?;
228
229        Ok(Self(assembly_sw_connector))
230    }
231
232    /// Get the provider port of the assembly connector
233    #[must_use]
234    pub fn p_port(&self) -> Option<PortPrototype> {
235        let provider_iref = self.element().get_sub_element(ElementName::ProviderIref)?;
236        let provider_port_elem = provider_iref
237            .get_sub_element(ElementName::TargetPPortRef)?
238            .get_reference_target()
239            .ok()?;
240        PortPrototype::try_from(provider_port_elem).ok()
241    }
242
243    /// get the component containing the `p_port` of the assembly connector
244    #[must_use]
245    pub fn p_sw_component(&self) -> Option<SwComponentPrototype> {
246        let provider_iref = self.element().get_sub_element(ElementName::ProviderIref)?;
247        let provider_swc_elem = provider_iref
248            .get_sub_element(ElementName::ContextComponentRef)?
249            .get_reference_target()
250            .ok()?;
251        SwComponentPrototype::try_from(provider_swc_elem).ok()
252    }
253
254    /// Get the requester port of the assembly connector
255    #[must_use]
256    pub fn r_port(&self) -> Option<PortPrototype> {
257        let requester_iref = self.element().get_sub_element(ElementName::RequesterIref)?;
258        let requester_port_elem = requester_iref
259            .get_sub_element(ElementName::TargetRPortRef)?
260            .get_reference_target()
261            .ok()?;
262        PortPrototype::try_from(requester_port_elem).ok()
263    }
264
265    /// get the component containing the `r_port` of the assembly connector
266    #[must_use]
267    pub fn r_sw_component(&self) -> Option<SwComponentPrototype> {
268        let requester_iref = self.element().get_sub_element(ElementName::RequesterIref)?;
269        let requester_swc_elem = requester_iref
270            .get_sub_element(ElementName::ContextComponentRef)?
271            .get_reference_target()
272            .ok()?;
273        SwComponentPrototype::try_from(requester_swc_elem).ok()
274    }
275}
276
277//##################################################################
278
279/// A `PassThroughSwConnector` connects two ports of a `SwCompositionType`.
280#[derive(Debug, Clone, PartialEq, Eq, Hash)]
281pub struct PassThroughSwConnector(Element);
282abstraction_element!(PassThroughSwConnector, PassThroughSwConnector);
283impl IdentifiableAbstractionElement for PassThroughSwConnector {}
284
285impl PassThroughSwConnector {
286    /// Create a new `PassThroughSwConnector`
287    pub(crate) fn new(
288        name: &str,
289        parent_element: &Element,
290        port_1: &PortPrototype,
291        port_2: &PortPrototype,
292    ) -> Result<Self, AutosarAbstractionError> {
293        let (provided_port, required_port) = match (&port_1, &port_2) {
294            (PortPrototype::P(_), PortPrototype::R(_)) => (port_1, port_2),
295            (PortPrototype::R(_), PortPrototype::P(_)) => (port_2, port_1),
296            (PortPrototype::P(_), PortPrototype::PR(_)) => (port_1, port_2),
297            (PortPrototype::PR(_), PortPrototype::P(_)) => (port_2, port_1),
298            (PortPrototype::R(_), PortPrototype::PR(_)) => (port_2, port_1),
299            (PortPrototype::PR(_), PortPrototype::R(_)) => (port_1, port_2),
300            (PortPrototype::PR(_), PortPrototype::PR(_)) => (port_1, port_2),
301            _ => {
302                return Err(AutosarAbstractionError::InvalidParameter(
303                    "Invalid port roles".to_string(),
304                ));
305            }
306        };
307
308        let pass_through_sw_connector =
309            parent_element.create_named_sub_element(ElementName::PassThroughSwConnector, name)?;
310
311        pass_through_sw_connector
312            .create_sub_element(ElementName::ProvidedOuterPortRef)?
313            .set_reference_target(provided_port.element())?;
314        pass_through_sw_connector
315            .create_sub_element(ElementName::RequiredOuterPortRef)?
316            .set_reference_target(required_port.element())?;
317
318        Ok(Self(pass_through_sw_connector))
319    }
320
321    /// Get the provided port of the pass-through connector
322    #[must_use]
323    pub fn p_port(&self) -> Option<PortPrototype> {
324        let provided_port_elem = self
325            .element()
326            .get_sub_element(ElementName::ProvidedOuterPortRef)?
327            .get_reference_target()
328            .ok()?;
329        PortPrototype::try_from(provided_port_elem).ok()
330    }
331
332    /// Get the required port of the pass-through connector
333    #[must_use]
334    pub fn r_port(&self) -> Option<PortPrototype> {
335        let required_port_elem = self
336            .element()
337            .get_sub_element(ElementName::RequiredOuterPortRef)?
338            .get_reference_target()
339            .ok()?;
340        PortPrototype::try_from(required_port_elem).ok()
341    }
342}
343
344//##################################################################
345
346/// A `SwConnector` is a generic enum that can represent any kind of software connector.
347#[derive(Debug, Clone, PartialEq, Eq, Hash)]
348pub enum SwConnector {
349    /// The connector is a `DelegationSwConnector`
350    Delegation(DelegationSwConnector),
351    /// The connector is an `AssemblySwConnector`
352    Assembly(AssemblySwConnector),
353    /// The connector is a `PassThroughSwConnector`
354    PassThrough(PassThroughSwConnector),
355}
356
357impl AbstractionElement for SwConnector {
358    fn element(&self) -> &Element {
359        match self {
360            SwConnector::Delegation(connector) => connector.element(),
361            SwConnector::Assembly(connector) => connector.element(),
362            SwConnector::PassThrough(connector) => connector.element(),
363        }
364    }
365}
366
367impl TryFrom<Element> for SwConnector {
368    type Error = AutosarAbstractionError;
369
370    fn try_from(element: Element) -> Result<Self, Self::Error> {
371        match element.element_name() {
372            ElementName::DelegationSwConnector => Ok(SwConnector::Delegation(DelegationSwConnector(element))),
373            ElementName::AssemblySwConnector => Ok(SwConnector::Assembly(AssemblySwConnector(element))),
374            ElementName::PassThroughSwConnector => Ok(SwConnector::PassThrough(PassThroughSwConnector(element))),
375            _ => Err(AutosarAbstractionError::ConversionError {
376                element: element.clone(),
377                dest: "SwConnector".to_string(),
378            }),
379        }
380    }
381}
382
383impl IdentifiableAbstractionElement for SwConnector {}
384
385//##################################################################
386
387#[cfg(test)]
388mod test {
389    use super::*;
390    use crate::AutosarModelAbstraction;
391    use autosar_data::{AutosarVersion, ElementName};
392    use software_component::{
393        AbstractSwComponentType, ApplicationSwComponentType, ClientServerInterface, CompositionSwComponentType,
394        SenderReceiverInterface,
395    };
396
397    #[test]
398    fn test_delegation_sw_connector() {
399        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
400        let package = model.get_or_create_package("/package").unwrap();
401
402        // create interfaces for the ports
403        let sr_interface = package.create_sender_receiver_interface("sr_interface").unwrap();
404        let cs_interface = package.create_client_server_interface("cs_interface").unwrap();
405
406        // create a composition and an application sw component type
407        let composition = package.create_composition_sw_component_type("composition").unwrap();
408        let swc_type = package.create_application_sw_component_type("app_type").unwrap();
409
410        // create multiple ports with different interfaces and directions
411        let outer_sr_p_port = composition.create_p_port("outer_sr_p_port", &sr_interface).unwrap();
412        let inner_sr_p_port = swc_type.create_p_port("inner_sr_p_port", &sr_interface).unwrap();
413        let outer_sr_r_port = composition.create_r_port("outer_sr_r_port", &sr_interface).unwrap();
414        let inner_sr_r_port = swc_type.create_r_port("inner_sr_r_port", &sr_interface).unwrap();
415        let outer_sr_pr_port = composition.create_pr_port("outer_sr_pr_port", &sr_interface).unwrap();
416        let inner_sr_pr_port = swc_type.create_pr_port("inner_sr_pr_port", &sr_interface).unwrap();
417
418        let outer_cs_p_port = composition.create_p_port("outer_cs_p_port", &cs_interface).unwrap();
419        let inner_cs_p_port = swc_type.create_p_port("inner_cs_p_port", &cs_interface).unwrap();
420        let outer_cs_r_port = composition.create_r_port("outer_cs_r_port", &cs_interface).unwrap();
421        let inner_cs_r_port = swc_type.create_r_port("inner_cs_r_port", &cs_interface).unwrap();
422        let outer_cs_pr_port = composition.create_pr_port("outer_cs_pr_port", &cs_interface).unwrap();
423        let inner_cs_pr_port = swc_type.create_pr_port("inner_cs_pr_port", &cs_interface).unwrap();
424
425        // add the application sw component type to the composition
426        let app_prototype = composition.create_component("app_prototype", &swc_type).unwrap();
427
428        // connect the outer port of the composition with the inner port of the application sw component type
429        let sr_p_connector = composition
430            .create_delegation_connector("sr_p_connector", &inner_sr_p_port, &app_prototype, &outer_sr_p_port)
431            .unwrap();
432        assert_eq!(sr_p_connector.inner_port().unwrap(), inner_sr_p_port.clone().into());
433        assert_eq!(sr_p_connector.outer_port().unwrap(), outer_sr_p_port.clone().into());
434        assert_eq!(sr_p_connector.inner_sw_component().unwrap(), app_prototype);
435        let sr_r_connector = composition
436            .create_delegation_connector("sr_r_connector", &inner_sr_r_port, &app_prototype, &outer_sr_r_port)
437            .unwrap();
438        assert_eq!(sr_r_connector.inner_port().unwrap(), inner_sr_r_port.clone().into());
439        assert_eq!(sr_r_connector.outer_port().unwrap(), outer_sr_r_port.clone().into());
440        assert_eq!(sr_r_connector.inner_sw_component().unwrap(), app_prototype);
441        let _sr_pr_connector = composition
442            .create_delegation_connector("sr_pr_connector", &inner_sr_pr_port, &app_prototype, &outer_sr_pr_port)
443            .unwrap();
444        let _cs_p_connector = composition
445            .create_delegation_connector("cs_p_connector", &inner_cs_p_port, &app_prototype, &outer_cs_p_port)
446            .unwrap();
447        let _cs_r_connector = composition
448            .create_delegation_connector("cs_r_connector", &inner_cs_r_port, &app_prototype, &outer_cs_r_port)
449            .unwrap();
450        // connecting a PR port to a PR port is not allowed for ClientServerInterfaces
451        let cs_pr_connector_result = composition.create_delegation_connector(
452            "cs_pr_connector",
453            &inner_cs_pr_port,
454            &app_prototype,
455            &outer_cs_pr_port,
456        );
457        assert!(cs_pr_connector_result.is_err());
458
459        // connecting different interfaces is not allowed
460        let result = composition.create_delegation_connector(
461            "invalid_connector",
462            &inner_sr_p_port,
463            &app_prototype,
464            &outer_cs_p_port,
465        );
466        assert!(result.is_err());
467
468        assert_eq!(sr_p_connector.name(), Some("sr_p_connector".to_string()));
469        assert_eq!(
470            sr_p_connector.element().element_name(),
471            ElementName::DelegationSwConnector
472        );
473    }
474
475    #[test]
476    fn test_assembly_sw_connector() {
477        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
478        let package = model.get_or_create_package("/package").unwrap();
479
480        // create interfaces for the ports
481        let sr_interface = SenderReceiverInterface::new("sr_interface", &package).unwrap();
482        let cs_interface = ClientServerInterface::new("cs_interface", &package).unwrap();
483
484        // create a composition and two application sw component types
485        let composition = CompositionSwComponentType::new("composition", &package).unwrap();
486        let swc_type_1 = ApplicationSwComponentType::new("app_type_1", &package).unwrap();
487        let swc_type_2 = ApplicationSwComponentType::new("app_type_2", &package).unwrap();
488
489        // create multiple ports with different interfaces and directions
490        let swc1_sr_p_port = swc_type_1.create_p_port("swc1_sr_p_port", &sr_interface).unwrap();
491        let swc2_sr_p_port = swc_type_2.create_p_port("swc2_sr_p_port", &sr_interface).unwrap();
492        let swc1_sr_r_port = swc_type_1.create_r_port("swc1_sr_r_port", &sr_interface).unwrap();
493        let swc2_sr_r_port = swc_type_2.create_r_port("swc2_sr_r_port", &sr_interface).unwrap();
494        let swc1_sr_pr_port = swc_type_1.create_pr_port("swc1_sr_pr_port", &sr_interface).unwrap();
495        let swc2_sr_pr_port = swc_type_2.create_pr_port("swc2_sr_pr_port", &sr_interface).unwrap();
496        let swc1_cs_p_port = swc_type_1.create_p_port("swc1_cs_p_port", &cs_interface).unwrap();
497        let swc2_cs_p_port = swc_type_2.create_p_port("swc2_cs_p_port", &cs_interface).unwrap();
498        let swc1_cs_r_port = swc_type_1.create_r_port("swc1_cs_r_port", &cs_interface).unwrap();
499        let swc2_cs_r_port = swc_type_2.create_r_port("swc2_cs_r_port", &cs_interface).unwrap();
500        let swc1_cs_pr_port = swc_type_1.create_pr_port("swc1_cs_pr_port", &cs_interface).unwrap();
501        let swc2_cs_pr_port = swc_type_2.create_pr_port("swc2_cs_pr_port", &cs_interface).unwrap();
502
503        // add both application sw component types to the composition
504        let app_prototype_1 = composition.create_component("app_prototype_1", &swc_type_1).unwrap();
505        let app_prototype_2 = composition.create_component("app_prototype_2", &swc_type_2).unwrap();
506
507        // connect the ports of the two application sw component types
508        // SR: P -> R (valid)
509        let sr_p_r_connector = composition
510            .create_assembly_connector(
511                "sr_p_r_connector",
512                &swc1_sr_p_port,
513                &app_prototype_1,
514                &swc2_sr_r_port,
515                &app_prototype_2,
516            )
517            .unwrap();
518        assert_eq!(sr_p_r_connector.p_port().unwrap(), swc1_sr_p_port.clone().into());
519        assert_eq!(sr_p_r_connector.r_port().unwrap(), swc2_sr_r_port.clone().into());
520        assert_eq!(sr_p_r_connector.p_sw_component().unwrap(), app_prototype_1);
521        assert_eq!(sr_p_r_connector.r_sw_component().unwrap(), app_prototype_2);
522        // SR: R -> P (valid)
523        let _sr_r_p_connector = composition
524            .create_assembly_connector(
525                "sr_r_p_connector",
526                &swc1_sr_r_port,
527                &app_prototype_1,
528                &swc2_sr_p_port,
529                &app_prototype_2,
530            )
531            .unwrap();
532        // SR: P -> PR (valid)
533        let _sr_p_pr_connector = composition
534            .create_assembly_connector(
535                "sr_p_pr_connector",
536                &swc1_sr_p_port,
537                &app_prototype_1,
538                &swc2_sr_pr_port,
539                &app_prototype_2,
540            )
541            .unwrap();
542        // SR: R -> PR (valid)
543        let _sr_r_pr_connector = composition
544            .create_assembly_connector(
545                "sr_r_pr_connector",
546                &swc1_sr_r_port,
547                &app_prototype_1,
548                &swc2_sr_pr_port,
549                &app_prototype_2,
550            )
551            .unwrap();
552        // SR: PR -> P (valid)
553        let _sr_pr_p_connector = composition
554            .create_assembly_connector(
555                "sr_pr_p_connector",
556                &swc1_sr_pr_port,
557                &app_prototype_1,
558                &swc2_sr_p_port,
559                &app_prototype_2,
560            )
561            .unwrap();
562        // SR: PR -> R (valid)
563        let _sr_pr_r_connector = composition
564            .create_assembly_connector(
565                "sr_pr_r_connector",
566                &swc1_sr_pr_port,
567                &app_prototype_1,
568                &swc2_sr_r_port,
569                &app_prototype_2,
570            )
571            .unwrap();
572        // CS: P -> R (valid)
573        let _cs_p_r_connector = composition
574            .create_assembly_connector(
575                "cs_p_r_connector",
576                &swc1_cs_p_port,
577                &app_prototype_1,
578                &swc2_cs_r_port,
579                &app_prototype_2,
580            )
581            .unwrap();
582        // CS: R -> P (valid)
583        let _cs_r_p_connector = composition
584            .create_assembly_connector(
585                "cs_r_p_connector",
586                &swc1_cs_r_port,
587                &app_prototype_1,
588                &swc2_cs_p_port,
589                &app_prototype_2,
590            )
591            .unwrap();
592        // CS: P -> PR (invalid)
593        let cs_p_pr_connector_result = composition.create_assembly_connector(
594            "cs_p_pr_connector",
595            &swc1_cs_p_port,
596            &app_prototype_1,
597            &swc2_cs_pr_port,
598            &app_prototype_2,
599        );
600        assert!(cs_p_pr_connector_result.is_err());
601        // CS: R -> PR (valid)
602        let _cs_r_pr_connector = composition
603            .create_assembly_connector(
604                "cs_r_pr_connector",
605                &swc1_cs_r_port,
606                &app_prototype_1,
607                &swc2_cs_pr_port,
608                &app_prototype_2,
609            )
610            .unwrap();
611        // CS: PR -> P (invalid)
612        let cs_pr_p_connector_result = composition.create_assembly_connector(
613            "cs_pr_p_connector",
614            &swc1_cs_pr_port,
615            &app_prototype_1,
616            &swc2_cs_p_port,
617            &app_prototype_2,
618        );
619        assert!(cs_pr_p_connector_result.is_err());
620        // CS: PR -> R (valid)
621        let _cs_pr_r_connector = composition
622            .create_assembly_connector(
623                "cs_pr_r_connector",
624                &swc1_cs_pr_port,
625                &app_prototype_1,
626                &swc2_cs_r_port,
627                &app_prototype_2,
628            )
629            .unwrap();
630
631        // SR: P -> P (invalid)
632        let sr_p_p_connector_result = composition.create_assembly_connector(
633            "sr_p_p_connector",
634            &swc1_sr_p_port,
635            &app_prototype_1,
636            &swc2_sr_p_port,
637            &app_prototype_2,
638        );
639        assert!(sr_p_p_connector_result.is_err());
640        // SR: R -> R (invalid)
641        let sr_r_r_connector_result = composition.create_assembly_connector(
642            "sr_r_r_connector",
643            &swc1_sr_r_port,
644            &app_prototype_1,
645            &swc2_sr_r_port,
646            &app_prototype_2,
647        );
648        assert!(sr_r_r_connector_result.is_err());
649
650        // connecting different interfaces is not allowed
651        let result = composition.create_assembly_connector(
652            "invalid_connector",
653            &swc1_sr_p_port,
654            &app_prototype_1,
655            &swc2_cs_r_port,
656            &app_prototype_2,
657        );
658        assert!(result.is_err());
659    }
660
661    #[test]
662    fn test_pass_through_sw_connector() {
663        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
664        let package = model.get_or_create_package("/package").unwrap();
665
666        // create interfaces for the ports
667        let sr_interface = SenderReceiverInterface::new("sr_interface", &package).unwrap();
668        let cs_interface = ClientServerInterface::new("cs_interface", &package).unwrap();
669
670        // create a composition
671        let composition = CompositionSwComponentType::new("composition", &package).unwrap();
672
673        // create multiple ports with different interfaces and directions
674        let sr_p_port = composition.create_p_port("sr_p_port", &sr_interface).unwrap();
675        let sr_r_port = composition.create_r_port("sr_r_port", &sr_interface).unwrap();
676        let cs_p_port = composition.create_p_port("cs_p_port", &cs_interface).unwrap();
677        let cs_r_port = composition.create_r_port("cs_r_port", &cs_interface).unwrap();
678
679        // connect the ports of the composition
680        // SR: P -> R (valid)
681        let sr_p_r_connector = composition
682            .create_pass_through_connector("sr_p_r_connector", &sr_p_port, &sr_r_port)
683            .unwrap();
684        assert_eq!(sr_p_r_connector.p_port().unwrap(), sr_p_port.clone().into());
685        assert_eq!(sr_p_r_connector.r_port().unwrap(), sr_r_port.clone().into());
686        // CS: R -> P (valid)
687        let _cs_r_p_connector = composition
688            .create_pass_through_connector("cs_r_p_connector", &cs_r_port, &cs_p_port)
689            .unwrap();
690
691        // connecting different interfaces is not allowed
692        let result = composition.create_pass_through_connector("invalid_connector", &sr_p_port, &cs_r_port);
693        assert!(result.is_err());
694    }
695}