autosar_data_abstraction/software_component/
port.rs

1use crate::{
2    AbstractionElement, AutosarAbstractionError, IdentifiableAbstractionElement, abstraction_element,
3    get_reference_parents, is_used, software_component,
4};
5use autosar_data::{Element, ElementName};
6use software_component::{AbstractPortInterface, PortInterface, SwComponentType};
7
8//#########################################################
9
10/// `RPortPrototype` represents a required port prototype
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub struct RPortPrototype(Element);
13abstraction_element!(RPortPrototype, RPortPrototype);
14impl IdentifiableAbstractionElement for RPortPrototype {}
15
16impl RPortPrototype {
17    /// Create a new `RPortPrototype`
18    pub(crate) fn new<T: AbstractPortInterface>(
19        name: &str,
20        parent_element: &Element,
21        interface: &T,
22    ) -> Result<Self, AutosarAbstractionError> {
23        let r_port_prototype = parent_element.create_named_sub_element(ElementName::RPortPrototype, name)?;
24        r_port_prototype
25            .create_sub_element(ElementName::RequiredInterfaceTref)?
26            .set_reference_target(interface.element())?;
27
28        Ok(Self(r_port_prototype))
29    }
30
31    /// remove the `RPortPrototype` from the model
32    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
33        let opt_port_interface = self.port_interface();
34        let ref_parents = get_reference_parents(self.element())?;
35
36        AbstractionElement::remove(self, deep)?;
37
38        if deep
39            && let Some(port_interface) = opt_port_interface
40            && !is_used(port_interface.element())
41        {
42            port_interface.remove(true)?;
43        }
44
45        for (named_parent, _parent) in ref_parents {
46            match named_parent.element_name() {
47                ElementName::DelegationSwConnector
48                | ElementName::AssemblySwConnector
49                | ElementName::PassThroughSwConnector => {
50                    if let Ok(connector) = software_component::SwConnector::try_from(named_parent) {
51                        connector.remove(deep)?;
52                    };
53                }
54                _ => {}
55            }
56        }
57
58        Ok(())
59    }
60
61    /// Get the port interface of the port prototype
62    pub fn port_interface(&self) -> Option<PortInterface> {
63        let interface_elem = self
64            .element()
65            .get_sub_element(ElementName::RequiredInterfaceTref)
66            .and_then(|r| r.get_reference_target().ok())?;
67        PortInterface::try_from(interface_elem).ok()
68    }
69
70    /// Get the component type containing the port prototype
71    pub fn component_type(&self) -> Result<SwComponentType, AutosarAbstractionError> {
72        let component_type_elem = self.element().named_parent()?.unwrap();
73        SwComponentType::try_from(component_type_elem)
74    }
75}
76
77//##################################################################
78
79/// `PPortPrototype` represents a provided port prototype
80#[derive(Debug, Clone, PartialEq, Eq, Hash)]
81pub struct PPortPrototype(Element);
82abstraction_element!(PPortPrototype, PPortPrototype);
83impl IdentifiableAbstractionElement for PPortPrototype {}
84
85impl PPortPrototype {
86    /// Create a new `PPortPrototype`
87    pub(crate) fn new<T: AbstractPortInterface>(
88        name: &str,
89        parent_element: &Element,
90        interface: &T,
91    ) -> Result<Self, AutosarAbstractionError> {
92        let p_port_prototype = parent_element.create_named_sub_element(ElementName::PPortPrototype, name)?;
93        p_port_prototype
94            .create_sub_element(ElementName::ProvidedInterfaceTref)?
95            .set_reference_target(interface.element())?;
96
97        Ok(Self(p_port_prototype))
98    }
99
100    /// remove the `PPortPrototype` from the model
101    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
102        let opt_port_interface = self.port_interface();
103        let ref_parents = get_reference_parents(self.element())?;
104
105        AbstractionElement::remove(self, deep)?;
106
107        if deep
108            && let Some(port_interface) = opt_port_interface
109            && !is_used(port_interface.element())
110        {
111            port_interface.remove(true)?;
112        }
113
114        for (named_parent, _parent) in ref_parents {
115            match named_parent.element_name() {
116                ElementName::DelegationSwConnector
117                | ElementName::AssemblySwConnector
118                | ElementName::PassThroughSwConnector => {
119                    if let Ok(connector) = software_component::SwConnector::try_from(named_parent) {
120                        connector.remove(deep)?;
121                    };
122                }
123                _ => {}
124            }
125        }
126
127        Ok(())
128    }
129
130    /// Get the port interface of the port prototype
131    pub fn port_interface(&self) -> Option<PortInterface> {
132        let interface_elem = self
133            .element()
134            .get_sub_element(ElementName::ProvidedInterfaceTref)
135            .and_then(|r| r.get_reference_target().ok())?;
136        PortInterface::try_from(interface_elem).ok()
137    }
138
139    /// Get the component type containing the port prototype
140    pub fn component_type(&self) -> Result<SwComponentType, AutosarAbstractionError> {
141        let component_type_elem = self.element().named_parent()?.unwrap();
142        SwComponentType::try_from(component_type_elem)
143    }
144}
145
146//##################################################################
147
148/// `PRPortPrototype` represents a provided and required port prototype
149#[derive(Debug, Clone, PartialEq, Eq, Hash)]
150pub struct PRPortPrototype(Element);
151abstraction_element!(PRPortPrototype, PrPortPrototype);
152impl IdentifiableAbstractionElement for PRPortPrototype {}
153
154impl PRPortPrototype {
155    /// Create a new `PRPortPrototype`
156    pub(crate) fn new<T: AbstractPortInterface>(
157        name: &str,
158        parent_element: &Element,
159        interface: &T,
160    ) -> Result<Self, AutosarAbstractionError> {
161        if interface.element().element_name() == ElementName::ParameterInterface {
162            return Err(AutosarAbstractionError::InvalidParameter(
163                "ParameterInterface is not allowed for PRPortPrototype".to_string(),
164            ));
165        }
166
167        let pr_port_prototype = parent_element.create_named_sub_element(ElementName::PrPortPrototype, name)?;
168        pr_port_prototype
169            .create_sub_element(ElementName::ProvidedRequiredInterfaceTref)?
170            .set_reference_target(interface.element())?;
171
172        Ok(Self(pr_port_prototype))
173    }
174
175    /// remove the `PRPortPrototype` from the model
176    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
177        let opt_port_interface = self.port_interface();
178        let ref_parents = get_reference_parents(self.element())?;
179
180        AbstractionElement::remove(self, deep)?;
181
182        if deep
183            && let Some(port_interface) = opt_port_interface
184            && !is_used(port_interface.element())
185        {
186            port_interface.remove(true)?;
187        }
188
189        for (named_parent, _parent) in ref_parents {
190            match named_parent.element_name() {
191                ElementName::DelegationSwConnector
192                | ElementName::AssemblySwConnector
193                | ElementName::PassThroughSwConnector => {
194                    if let Ok(connector) = software_component::SwConnector::try_from(named_parent) {
195                        connector.remove(deep)?;
196                    };
197                }
198                _ => {}
199            }
200        }
201
202        Ok(())
203    }
204
205    /// Get the port interface of the port prototype
206    pub fn port_interface(&self) -> Option<PortInterface> {
207        let interface_elem = self
208            .element()
209            .get_sub_element(ElementName::ProvidedRequiredInterfaceTref)
210            .and_then(|r| r.get_reference_target().ok())?;
211        PortInterface::try_from(interface_elem).ok()
212    }
213
214    /// Get the component type containing the port prototype
215    pub fn component_type(&self) -> Result<SwComponentType, AutosarAbstractionError> {
216        let component_type_elem = self.element().named_parent()?.unwrap();
217        SwComponentType::try_from(component_type_elem)
218    }
219}
220
221//##################################################################
222
223/// The `PortPrototype` enum represents all possible kinds of port prototypes
224#[derive(Debug, Clone, PartialEq, Eq, Hash)]
225pub enum PortPrototype {
226    /// A required port prototype
227    R(RPortPrototype),
228    /// A provided port prototype
229    P(PPortPrototype),
230    /// A provided and required port prototype
231    PR(PRPortPrototype),
232}
233
234impl AbstractionElement for PortPrototype {
235    fn element(&self) -> &Element {
236        match self {
237            PortPrototype::R(port) => port.element(),
238            PortPrototype::P(port) => port.element(),
239            PortPrototype::PR(port) => port.element(),
240        }
241    }
242}
243
244impl IdentifiableAbstractionElement for PortPrototype {}
245
246impl From<RPortPrototype> for PortPrototype {
247    fn from(port: RPortPrototype) -> Self {
248        PortPrototype::R(port)
249    }
250}
251
252impl From<PPortPrototype> for PortPrototype {
253    fn from(port: PPortPrototype) -> Self {
254        PortPrototype::P(port)
255    }
256}
257
258impl From<PRPortPrototype> for PortPrototype {
259    fn from(port: PRPortPrototype) -> Self {
260        PortPrototype::PR(port)
261    }
262}
263
264impl TryFrom<Element> for PortPrototype {
265    type Error = AutosarAbstractionError;
266
267    fn try_from(element: Element) -> Result<Self, Self::Error> {
268        match element.element_name() {
269            ElementName::RPortPrototype => Ok(PortPrototype::R(RPortPrototype(element))),
270            ElementName::PPortPrototype => Ok(PortPrototype::P(PPortPrototype(element))),
271            ElementName::PrPortPrototype => Ok(PortPrototype::PR(PRPortPrototype(element))),
272            _ => Err(AutosarAbstractionError::ConversionError {
273                element: element.clone(),
274                dest: "PortPrototype".to_string(),
275            }),
276        }
277    }
278}
279
280impl PortPrototype {
281    /// Get the port interface of the port prototype
282    pub fn port_interface(&self) -> Option<PortInterface> {
283        match self {
284            PortPrototype::R(port) => port.port_interface(),
285            PortPrototype::P(port) => port.port_interface(),
286            PortPrototype::PR(port) => port.port_interface(),
287        }
288    }
289
290    /// Get the component type containing the port prototype
291    pub fn component_type(&self) -> Result<SwComponentType, AutosarAbstractionError> {
292        let component_type_elem = self.element().named_parent()?.unwrap();
293        SwComponentType::try_from(component_type_elem)
294    }
295
296    /// remove the `PortPrototype` from the model
297    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
298        match self {
299            PortPrototype::R(port) => port.remove(deep),
300            PortPrototype::P(port) => port.remove(deep),
301            PortPrototype::PR(port) => port.remove(deep),
302        }
303    }
304}
305
306//##################################################################
307
308/// `PortGroup` represents a group of ports
309#[derive(Debug, Clone, PartialEq, Eq, Hash)]
310pub struct PortGroup(Element);
311abstraction_element!(PortGroup, PortGroup);
312impl IdentifiableAbstractionElement for PortGroup {}
313
314impl PortGroup {
315    /// Create a new `PortGroup`
316    pub(crate) fn new(name: &str, parent_element: &Element) -> Result<Self, AutosarAbstractionError> {
317        let port_group = parent_element.create_named_sub_element(ElementName::PortGroup, name)?;
318
319        Ok(Self(port_group))
320    }
321}
322
323//##################################################################
324
325#[cfg(test)]
326mod test {
327    use super::*;
328    use crate::AutosarModelAbstraction;
329    use autosar_data::AutosarVersion;
330    use software_component::AbstractSwComponentType;
331
332    #[test]
333    fn ports() {
334        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
335        let package = model.get_or_create_package("/package").unwrap();
336
337        let comp = package.create_composition_sw_component_type("comp").unwrap();
338
339        let port_interface = package.create_sender_receiver_interface("sr_interface").unwrap();
340        let r_port = comp.create_r_port("sr_r_port", &port_interface).unwrap();
341        let p_port = comp.create_p_port("sr_p_port", &port_interface).unwrap();
342        let pr_port = comp.create_pr_port("sr_pr_port", &port_interface).unwrap();
343
344        assert_eq!(comp.ports().count(), 3);
345        let ports: Vec<PortPrototype> = comp.ports().collect();
346        assert_eq!(ports[0], r_port.clone().into());
347        assert_eq!(ports[1], p_port.clone().into());
348        assert_eq!(ports[2], pr_port.clone().into());
349        assert_eq!(r_port.component_type().unwrap(), comp.clone().into());
350        assert_eq!(p_port.component_type().unwrap(), comp.clone().into());
351        assert_eq!(pr_port.component_type().unwrap(), comp.clone().into());
352        assert_eq!(ports[0].component_type().unwrap(), comp.clone().into());
353
354        let port_interface = package.create_client_server_interface("cs_interface").unwrap();
355        let r_port = comp.create_r_port("cs_r_port", &port_interface).unwrap();
356        let p_port = comp.create_p_port("cs_p_port", &port_interface).unwrap();
357        let pr_port = comp.create_pr_port("cs_pr_port", &port_interface).unwrap();
358
359        assert_eq!(comp.ports().count(), 6);
360        let ports: Vec<PortPrototype> = comp.ports().collect();
361        assert_eq!(ports[3], r_port.into());
362        assert_eq!(ports[4], p_port.into());
363        assert_eq!(ports[5], pr_port.into());
364
365        let port_interface = package.create_mode_switch_interface("ms_interface").unwrap();
366        let r_port = comp.create_r_port("ms_r_port", &port_interface).unwrap();
367        let p_port = comp.create_p_port("ms_p_port", &port_interface).unwrap();
368        let pr_port = comp.create_pr_port("ms_pr_port", &port_interface).unwrap();
369
370        assert_eq!(comp.ports().count(), 9);
371        let ports: Vec<PortPrototype> = comp.ports().collect();
372        assert_eq!(ports[6], r_port.into());
373        assert_eq!(ports[7], p_port.into());
374        assert_eq!(ports[8], pr_port.into());
375
376        let port_interface = package.create_nv_data_interface("nv_interface").unwrap();
377        let r_port = comp.create_r_port("nv_r_port", &port_interface).unwrap();
378        let p_port = comp.create_p_port("nv_p_port", &port_interface).unwrap();
379        let pr_port = comp.create_pr_port("nv_pr_port", &port_interface).unwrap();
380
381        assert_eq!(comp.ports().count(), 12);
382        let ports: Vec<PortPrototype> = comp.ports().collect();
383        assert_eq!(ports[9], r_port.into());
384        assert_eq!(ports[10], p_port.into());
385        assert_eq!(ports[11], pr_port.into());
386
387        let port_interface = package.create_parameter_interface("param_interface").unwrap();
388        let r_port = comp.create_r_port("param_r_port", &port_interface).unwrap();
389        let p_port = comp.create_p_port("param_p_port", &port_interface).unwrap();
390        let pr_port_result = comp.create_pr_port("param_pr_port", &port_interface);
391        assert!(pr_port_result.is_err());
392
393        assert_eq!(comp.ports().count(), 14);
394        let ports: Vec<PortPrototype> = comp.ports().collect();
395        assert_eq!(ports[12], r_port.into());
396        assert_eq!(ports[13], p_port.into());
397
398        let port_interface = package.create_trigger_interface("trigger_interface").unwrap();
399        let r_port = comp.create_r_port("trigger_r_port", &port_interface).unwrap();
400        let p_port = comp.create_p_port("trigger_p_port", &port_interface).unwrap();
401        let pr_port = comp.create_pr_port("trigger_pr_port", &port_interface).unwrap();
402
403        assert_eq!(comp.ports().count(), 17);
404        let ports: Vec<PortPrototype> = comp.ports().collect();
405        assert_eq!(ports[14], r_port.into());
406        assert_eq!(ports[15], p_port.into());
407        assert_eq!(ports[16], pr_port.into());
408    }
409
410    #[test]
411    fn remove_port() {
412        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
413        let package = model.get_or_create_package("/package").unwrap();
414        let sender_receiver_interface = package.create_sender_receiver_interface("TestInterface").unwrap();
415
416        let composition_type = package.create_composition_sw_component_type("comp_parent").unwrap();
417        let r_port = composition_type
418            .create_r_port("port_r", &sender_receiver_interface)
419            .unwrap();
420        let p_port = composition_type
421            .create_p_port("port_p", &sender_receiver_interface)
422            .unwrap();
423        let pr_port = composition_type
424            .create_pr_port("port_pr", &sender_receiver_interface)
425            .unwrap();
426
427        // Create an application component type to delegate ports to
428        let app_swc_type = package.create_application_sw_component_type("app_swc").unwrap();
429        let app_r_port = app_swc_type
430            .create_r_port("app_port_r", &sender_receiver_interface)
431            .unwrap();
432        let app_prototype = composition_type.create_component("app_proto", &app_swc_type).unwrap();
433        // connect the local r_port to the r_port of the application component prototype
434        composition_type
435            .create_delegation_connector("delegation_connector", &app_r_port, &app_prototype, &r_port)
436            .unwrap();
437        assert_eq!(composition_type.connectors().count(), 1);
438
439        assert_eq!(composition_type.ports().count(), 3);
440        r_port.remove(true).unwrap();
441        assert_eq!(composition_type.connectors().count(), 0);
442        assert_eq!(composition_type.ports().count(), 2);
443        p_port.remove(true).unwrap();
444        assert_eq!(composition_type.ports().count(), 1);
445        pr_port.remove(true).unwrap();
446        assert_eq!(composition_type.ports().count(), 0);
447    }
448}