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