autosar_data_abstraction/software_component/interface/
mod.rs

1use crate::{
2    AbstractionElement, ArPackage, AutosarAbstractionError, Element, IdentifiableAbstractionElement,
3    abstraction_element,
4    datatype::{AbstractAutosarDataType, AutosarDataType, ValueSpecification},
5    get_reference_parents,
6    software_component::{ModeDeclarationGroup, PortPrototype},
7};
8use autosar_data::ElementName;
9
10mod clientserver;
11mod senderreceiver;
12
13pub use clientserver::*;
14pub use senderreceiver::*;
15
16//##################################################################
17
18/// A `ModeSwitchInterface` defines a set of modes that can be switched
19///
20/// Use [`ArPackage::create_mode_switch_interface`] to create a new mode switch interface
21#[derive(Debug, Clone, PartialEq, Eq, Hash)]
22pub struct ModeSwitchInterface(Element);
23abstraction_element!(ModeSwitchInterface, ModeSwitchInterface);
24impl IdentifiableAbstractionElement for ModeSwitchInterface {}
25impl AbstractPortInterface for ModeSwitchInterface {}
26
27impl ModeSwitchInterface {
28    /// Create a new `ModeSwitchInterface`
29    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
30        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
31        let mode_switch_interface = elements.create_named_sub_element(ElementName::ModeSwitchInterface, name)?;
32
33        Ok(Self(mode_switch_interface))
34    }
35
36    /// remove this `ModeSwitchInterface` from the model
37    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
38        if let Some(mode_group) = self.mode_group() {
39            mode_group.remove(true)?;
40        }
41
42        let ref_parents = get_reference_parents(self.element())?;
43
44        AbstractionElement::remove(self, deep)?;
45
46        for (named_parent, _parent) in ref_parents {
47            match named_parent.element_name() {
48                ElementName::PPortPrototype | ElementName::RPortPrototype | ElementName::PrPortPrototype => {
49                    if let Ok(port) = PortPrototype::try_from(named_parent) {
50                        port.remove(deep)?;
51                    }
52                }
53                _ => {}
54            }
55        }
56
57        Ok(())
58    }
59
60    /// Create a mode group in this `ModeSwitchInterface`
61    ///
62    /// The `ModeSwitchInterface` can contain one mode group
63    pub fn create_mode_group(
64        &self,
65        name: &str,
66        mode_declaration_group: &ModeDeclarationGroup,
67    ) -> Result<ModeGroup, AutosarAbstractionError> {
68        ModeGroup::new(name, self.element(), mode_declaration_group)
69    }
70
71    /// Get the mode group for this `ModeSwitchInterface`
72    #[must_use]
73    pub fn mode_group(&self) -> Option<ModeGroup> {
74        let mode_group_elem = self.element().get_sub_element(ElementName::ModeGroup)?;
75        ModeGroup::try_from(mode_group_elem).ok()
76    }
77}
78
79//##################################################################
80
81/// A `ModeGroup` represents a mode group in a `ModeSwitchInterface`
82///
83/// aka ModeDeclarationGroupPrototype in the AUTOSAR standard
84#[derive(Debug, Clone, PartialEq, Eq, Hash)]
85pub struct ModeGroup(Element);
86abstraction_element!(ModeGroup, ModeGroup);
87impl IdentifiableAbstractionElement for ModeGroup {}
88
89impl ModeGroup {
90    /// Create a new `ModeGroup`
91    fn new(
92        name: &str,
93        parent_element: &Element,
94        mode_declaration_group: &ModeDeclarationGroup,
95    ) -> Result<Self, AutosarAbstractionError> {
96        let mode_group_elem = parent_element.create_named_sub_element(ElementName::ModeGroup, name)?;
97        let mode_group = Self(mode_group_elem);
98        mode_group.set_mode_declaration_group(mode_declaration_group)?;
99
100        Ok(mode_group)
101    }
102
103    /// Set the mode declaration group for this `ModeGroup`
104    pub fn set_mode_declaration_group(
105        &self,
106        mode_declaration_group: &ModeDeclarationGroup,
107    ) -> Result<(), AutosarAbstractionError> {
108        self.element()
109            .get_or_create_sub_element(ElementName::TypeTref)?
110            .set_reference_target(mode_declaration_group.element())?;
111        Ok(())
112    }
113
114    /// Get the mode declaration group for this `ModeGroup`
115    #[must_use]
116    pub fn mode_declaration_group(&self) -> Option<ModeDeclarationGroup> {
117        let mode_declaration_group_elem = self
118            .element()
119            .get_sub_element(ElementName::TypeTref)?
120            .get_reference_target()
121            .ok()?;
122        ModeDeclarationGroup::try_from(mode_declaration_group_elem).ok()
123    }
124}
125
126//##################################################################
127
128/// A `ParameterInterface` defines a set of parameters that can be accessed
129///
130/// Use [`ArPackage::create_parameter_interface`] to create a new parameter interface
131#[derive(Debug, Clone, PartialEq, Eq, Hash)]
132pub struct ParameterInterface(Element);
133abstraction_element!(ParameterInterface, ParameterInterface);
134impl IdentifiableAbstractionElement for ParameterInterface {}
135impl AbstractPortInterface for ParameterInterface {}
136
137impl ParameterInterface {
138    /// Create a new `ParameterInterface`
139    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
140        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
141        let parameter_interface = elements.create_named_sub_element(ElementName::ParameterInterface, name)?;
142
143        Ok(Self(parameter_interface))
144    }
145
146    /// remove this `ParameterInterface` from the model
147    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
148        for parameter in self.parameters() {
149            parameter.remove(true)?;
150        }
151
152        let ref_parents = get_reference_parents(self.element())?;
153
154        AbstractionElement::remove(self, deep)?;
155
156        for (named_parent, _parent) in ref_parents {
157            match named_parent.element_name() {
158                ElementName::PPortPrototype | ElementName::RPortPrototype | ElementName::PrPortPrototype => {
159                    if let Ok(port) = PortPrototype::try_from(named_parent) {
160                        port.remove(deep)?;
161                    }
162                }
163                _ => {}
164            }
165        }
166
167        Ok(())
168    }
169
170    /// Create a new `ParameterDataPrototype` in this `ParameterInterface`
171    pub fn create_parameter<T: AbstractAutosarDataType>(
172        &self,
173        name: &str,
174        data_type: &T,
175    ) -> Result<ParameterDataPrototype, AutosarAbstractionError> {
176        let parameters = self.element().get_or_create_sub_element(ElementName::Parameters)?;
177        ParameterDataPrototype::new(name, &parameters, data_type)
178    }
179
180    /// iterate over all `ParameterDataPrototype` in this `ParameterInterface`
181    pub fn parameters(&self) -> impl Iterator<Item = ParameterDataPrototype> + Send + use<> {
182        self.element()
183            .get_sub_element(ElementName::Parameters)
184            .into_iter()
185            .flat_map(|parameters| parameters.sub_elements())
186            .filter_map(|param| ParameterDataPrototype::try_from(param).ok())
187    }
188}
189
190//##################################################################
191
192/// A `ParameterDataPrototype` defines a read-only parameter.
193///
194/// Typically such a parameter can be calibrated, but this is not required.
195#[derive(Debug, Clone, PartialEq, Eq, Hash)]
196pub struct ParameterDataPrototype(Element);
197abstraction_element!(ParameterDataPrototype, ParameterDataPrototype);
198impl IdentifiableAbstractionElement for ParameterDataPrototype {}
199
200impl ParameterDataPrototype {
201    /// Create a new `ParameterDataPrototype`
202    fn new<T: AbstractAutosarDataType>(
203        name: &str,
204        parent_element: &Element,
205        data_type: &T,
206    ) -> Result<Self, AutosarAbstractionError> {
207        let pdp = parent_element.create_named_sub_element(ElementName::ParameterDataPrototype, name)?;
208
209        let pdp = Self(pdp);
210        pdp.set_data_type(data_type)?;
211
212        Ok(pdp)
213    }
214
215    /// set the init value for this signal
216    pub fn set_init_value<T: Into<ValueSpecification>>(
217        &self,
218        value_spec: Option<T>,
219    ) -> Result<(), AutosarAbstractionError> {
220        if let Some(value_spec) = value_spec {
221            let value_spec: ValueSpecification = value_spec.into();
222            let init_value_elem = self.element().get_or_create_sub_element(ElementName::InitValue)?;
223            value_spec.store(&init_value_elem)?;
224        } else {
225            let _ = self.element().remove_sub_element_kind(ElementName::InitValue);
226        }
227        Ok(())
228    }
229
230    /// get the init value for this signal
231    #[must_use]
232    pub fn init_value(&self) -> Option<ValueSpecification> {
233        let init_value_elem = self
234            .element()
235            .get_sub_element(ElementName::InitValue)?
236            .get_sub_element_at(0)?;
237        ValueSpecification::load(&init_value_elem)
238    }
239
240    /// Get the interface containing the data element
241    pub fn interface(&self) -> Result<ParameterInterface, AutosarAbstractionError> {
242        let named_parent = self.element().named_parent()?.unwrap();
243        ParameterInterface::try_from(named_parent)
244    }
245
246    /// Set the data type of the parameter
247    pub fn set_data_type<T: AbstractAutosarDataType>(&self, data_type: &T) -> Result<(), AutosarAbstractionError> {
248        self.element()
249            .get_or_create_sub_element(ElementName::TypeTref)?
250            .set_reference_target(data_type.element())?;
251        Ok(())
252    }
253
254    /// Get the data type of the parameter
255    #[must_use]
256    pub fn data_type(&self) -> Option<AutosarDataType> {
257        let type_tref = self.element().get_sub_element(ElementName::TypeTref)?;
258        AutosarDataType::try_from(type_tref.get_reference_target().ok()?).ok()
259    }
260}
261
262//##################################################################
263
264/// An `NvDataInterface` defines non-volatile data that can be accessed through the interface
265///
266/// Use [`ArPackage::create_nv_data_interface`] to create a new non-volatile data interface
267#[derive(Debug, Clone, PartialEq, Eq, Hash)]
268pub struct NvDataInterface(Element);
269abstraction_element!(NvDataInterface, NvDataInterface);
270impl IdentifiableAbstractionElement for NvDataInterface {}
271impl AbstractPortInterface for NvDataInterface {}
272
273impl NvDataInterface {
274    /// Create a new `NvDataInterface`
275    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
276        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
277        let nv_data_interface = elements.create_named_sub_element(ElementName::NvDataInterface, name)?;
278
279        Ok(Self(nv_data_interface))
280    }
281
282    /// remove this `NvDataInterface` from the model
283    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
284        let ref_parents = get_reference_parents(self.element())?;
285
286        AbstractionElement::remove(self, deep)?;
287
288        for (named_parent, _parent) in ref_parents {
289            match named_parent.element_name() {
290                ElementName::PPortPrototype | ElementName::RPortPrototype | ElementName::PrPortPrototype => {
291                    if let Ok(port) = PortPrototype::try_from(named_parent) {
292                        port.remove(deep)?;
293                    }
294                }
295                _ => {}
296            }
297        }
298
299        Ok(())
300    }
301}
302
303//##################################################################
304
305/// A `TriggerInterface` declares a number of triggers that can be sent by an trigger source
306///
307/// Use [`ArPackage::create_trigger_interface`] to create a new trigger interface
308#[derive(Debug, Clone, PartialEq, Eq, Hash)]
309pub struct TriggerInterface(Element);
310abstraction_element!(TriggerInterface, TriggerInterface);
311impl IdentifiableAbstractionElement for TriggerInterface {}
312impl AbstractPortInterface for TriggerInterface {}
313
314impl TriggerInterface {
315    /// Create a new `TriggerInterface`
316    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
317        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
318        let trigger_interface = elements.create_named_sub_element(ElementName::TriggerInterface, name)?;
319
320        Ok(Self(trigger_interface))
321    }
322
323    /// remove this `TriggerInterface` from the model
324    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
325        let ref_parents = get_reference_parents(self.element())?;
326
327        AbstractionElement::remove(self, deep)?;
328
329        for (named_parent, _parent) in ref_parents {
330            match named_parent.element_name() {
331                ElementName::PPortPrototype | ElementName::RPortPrototype | ElementName::PrPortPrototype => {
332                    if let Ok(port) = PortPrototype::try_from(named_parent) {
333                        port.remove(deep)?;
334                    }
335                }
336                _ => {}
337            }
338        }
339
340        Ok(())
341    }
342}
343
344//##################################################################
345
346/// The `AbstractPortInterface` trait is a marker trait for all port interfaces
347pub trait AbstractPortInterface: AbstractionElement {
348    /// Set the isService property for this port interface
349    fn set_is_service(&self, is_service: Option<bool>) -> Result<(), AutosarAbstractionError> {
350        if let Some(is_service) = is_service {
351            self.element()
352                .get_or_create_sub_element(ElementName::IsService)?
353                .set_character_data(is_service)?;
354        } else {
355            let _ = self.element().remove_sub_element_kind(ElementName::IsService);
356        }
357        Ok(())
358    }
359
360    /// Get the isService property for this port interface
361    #[must_use]
362    fn is_service(&self) -> Option<bool> {
363        self.element()
364            .get_sub_element(ElementName::IsService)
365            .and_then(|elem| elem.character_data())
366            .and_then(|cdata| cdata.parse_bool())
367    }
368}
369
370//##################################################################
371
372/// The `PortInterface` enum represents all possible port interfaces
373#[derive(Debug, Clone, PartialEq, Eq, Hash)]
374pub enum PortInterface {
375    /// The interface is a sender-receiver interface
376    SenderReceiverInterface(SenderReceiverInterface),
377    /// The interface is a client-server interface
378    ClientServerInterface(ClientServerInterface),
379    /// The interface is a mode switch interface
380    ModeSwitchInterface(ModeSwitchInterface),
381    /// The interface is a parameter interface
382    ParameterInterface(ParameterInterface),
383    /// The interface is a non-volatile data interface
384    NvDataInterface(NvDataInterface),
385    /// The interface is a trigger interface
386    TriggerInterface(TriggerInterface),
387}
388
389impl AbstractionElement for PortInterface {
390    fn element(&self) -> &Element {
391        match self {
392            PortInterface::SenderReceiverInterface(sender_receiver_interface) => sender_receiver_interface.element(),
393            PortInterface::ClientServerInterface(client_server_interface) => client_server_interface.element(),
394            PortInterface::ModeSwitchInterface(mode_switch_interface) => mode_switch_interface.element(),
395            PortInterface::ParameterInterface(parameter_interface) => parameter_interface.element(),
396            PortInterface::NvDataInterface(nv_data_interface) => nv_data_interface.element(),
397            PortInterface::TriggerInterface(trigger_interface) => trigger_interface.element(),
398        }
399    }
400}
401
402impl IdentifiableAbstractionElement for PortInterface {}
403impl AbstractPortInterface for PortInterface {}
404
405impl TryFrom<Element> for PortInterface {
406    type Error = AutosarAbstractionError;
407
408    fn try_from(element: Element) -> Result<Self, Self::Error> {
409        match element.element_name() {
410            ElementName::SenderReceiverInterface => {
411                Ok(PortInterface::SenderReceiverInterface(SenderReceiverInterface(element)))
412            }
413            ElementName::ClientServerInterface => {
414                Ok(PortInterface::ClientServerInterface(ClientServerInterface(element)))
415            }
416            ElementName::ModeSwitchInterface => Ok(PortInterface::ModeSwitchInterface(ModeSwitchInterface(element))),
417            ElementName::ParameterInterface => Ok(PortInterface::ParameterInterface(ParameterInterface(element))),
418            ElementName::NvDataInterface => Ok(PortInterface::NvDataInterface(NvDataInterface(element))),
419            ElementName::TriggerInterface => Ok(PortInterface::TriggerInterface(TriggerInterface(element))),
420            _ => Err(AutosarAbstractionError::ConversionError {
421                element,
422                dest: "PortInterface".to_string(),
423            }),
424        }
425    }
426}
427
428impl PortInterface {
429    /// Remove this port interface from the model
430    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
431        match self {
432            PortInterface::SenderReceiverInterface(interface) => interface.remove(deep),
433            PortInterface::ClientServerInterface(interface) => interface.remove(deep),
434            PortInterface::ModeSwitchInterface(interface) => interface.remove(deep),
435            PortInterface::ParameterInterface(interface) => interface.remove(deep),
436            PortInterface::NvDataInterface(interface) => interface.remove(deep),
437            PortInterface::TriggerInterface(interface) => interface.remove(deep),
438        }
439    }
440}
441
442//##################################################################
443
444#[cfg(test)]
445mod test {
446    use super::*;
447    use crate::{
448        AutosarModelAbstraction,
449        datatype::{BaseTypeEncoding, ImplementationDataTypeSettings, TextValueSpecification},
450        software_component::AbstractSwComponentType,
451    };
452    use autosar_data::AutosarVersion;
453
454    #[test]
455    fn test_interfaces() {
456        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
457        let package = model.get_or_create_package("/package").unwrap();
458
459        let sender_receiver_interface = package
460            .create_sender_receiver_interface("sender_receiver_interface")
461            .unwrap();
462        let client_server_interface = package
463            .create_client_server_interface("client_server_interface")
464            .unwrap();
465        let mode_switch_interface = package.create_mode_switch_interface("mode_switch_interface").unwrap();
466        let parameter_interface = package.create_parameter_interface("parameter_interface").unwrap();
467        let nv_data_interface = package.create_nv_data_interface("nv_data_interface").unwrap();
468        let trigger_interface = package.create_trigger_interface("trigger_interface").unwrap();
469
470        let composition = package.create_composition_sw_component_type("composition").unwrap();
471
472        let port_1 = composition.create_p_port("port_1", &sender_receiver_interface).unwrap();
473        assert!(matches!(
474            port_1.port_interface(),
475            Some(PortInterface::SenderReceiverInterface(interface)) if interface == sender_receiver_interface
476        ));
477        assert_eq!(
478            port_1.port_interface().unwrap().element(),
479            sender_receiver_interface.element()
480        );
481
482        let port_2 = composition.create_p_port("port_2", &client_server_interface).unwrap();
483        assert!(matches!(
484            port_2.port_interface(),
485            Some(PortInterface::ClientServerInterface(interface)) if interface == client_server_interface
486        ));
487        assert_eq!(
488            port_2.port_interface().unwrap().element(),
489            client_server_interface.element()
490        );
491
492        let port_3 = composition.create_p_port("port_3", &mode_switch_interface).unwrap();
493        assert!(matches!(
494            port_3.port_interface(),
495            Some(PortInterface::ModeSwitchInterface(interface)) if interface == mode_switch_interface
496        ));
497        assert_eq!(
498            port_3.port_interface().unwrap().element(),
499            mode_switch_interface.element()
500        );
501
502        let port_4 = composition.create_p_port("port_4", &parameter_interface).unwrap();
503        assert!(matches!(
504            port_4.port_interface(),
505            Some(PortInterface::ParameterInterface(interface)) if interface == parameter_interface
506        ));
507        assert_eq!(
508            port_4.port_interface().unwrap().element(),
509            parameter_interface.element()
510        );
511
512        let port_5 = composition.create_p_port("port_5", &nv_data_interface).unwrap();
513        assert!(matches!(
514            port_5.port_interface(),
515            Some(PortInterface::NvDataInterface(interface)) if interface == nv_data_interface
516        ));
517        assert_eq!(port_5.port_interface().unwrap().element(), nv_data_interface.element());
518
519        let port_6 = composition.create_p_port("port_6", &trigger_interface).unwrap();
520        assert!(matches!(
521            port_6.port_interface(),
522            Some(PortInterface::TriggerInterface(interface)) if interface == trigger_interface
523        ));
524        assert_eq!(port_6.port_interface().unwrap().element(), trigger_interface.element());
525    }
526
527    #[test]
528    fn parameter_interface() {
529        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
530        let package = model.get_or_create_package("/package").unwrap();
531
532        let parameter_interface = package.create_parameter_interface("parameter_interface").unwrap();
533        let base_type = package
534            .create_sw_base_type("base", 32, BaseTypeEncoding::None, None, None, None)
535            .unwrap();
536        let datatype = package
537            .create_implementation_data_type(&ImplementationDataTypeSettings::Value {
538                name: "ImplementationValue".to_string(),
539                base_type: base_type.clone(),
540                compu_method: None,
541                data_constraint: None,
542            })
543            .unwrap();
544
545        let parameter = parameter_interface.create_parameter("parameter", &datatype).unwrap();
546        assert_eq!(parameter.name().as_deref().unwrap(), "parameter");
547
548        assert_eq!(parameter_interface.parameters().count(), 1);
549
550        assert_eq!(parameter.interface().unwrap(), parameter_interface);
551        assert_eq!(
552            parameter.data_type().unwrap(),
553            AutosarDataType::ImplementationDataType(datatype)
554        );
555
556        parameter_interface.set_is_service(Some(true)).unwrap();
557        assert_eq!(parameter_interface.is_service(), Some(true));
558        parameter_interface.set_is_service(None).unwrap();
559        assert_eq!(parameter_interface.is_service(), None);
560
561        let value_spec = TextValueSpecification {
562            label: None,
563            value: "42".to_string(),
564        };
565        parameter.set_init_value(Some(value_spec)).unwrap();
566        assert_eq!(
567            parameter.init_value().unwrap(),
568            TextValueSpecification {
569                label: None,
570                value: "42".to_string()
571            }
572            .into()
573        );
574    }
575
576    #[test]
577    fn mode_switch_interface() {
578        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
579        let package = model.get_or_create_package("/package").unwrap();
580
581        let mode_declaration_group = package
582            .create_mode_declaration_group("mode_declaration_group", None)
583            .unwrap();
584
585        let mode_switch_interface = package.create_mode_switch_interface("mode_switch_interface").unwrap();
586        mode_switch_interface.set_is_service(Some(true)).unwrap();
587        assert_eq!(mode_switch_interface.is_service(), Some(true));
588        mode_switch_interface.set_is_service(None).unwrap();
589        assert_eq!(mode_switch_interface.is_service(), None);
590
591        let mode_group = mode_switch_interface
592            .create_mode_group("mode_group", &mode_declaration_group)
593            .unwrap();
594        assert_eq!(mode_switch_interface.mode_group().unwrap(), mode_group);
595        assert_eq!(mode_group.mode_declaration_group().unwrap(), mode_declaration_group);
596    }
597
598    #[test]
599    fn remove_mode_switch_interface() {
600        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
601        let package = model.get_or_create_package("/package").unwrap();
602        let mode_switch_interface = package.create_mode_switch_interface("mode_switch_interface").unwrap();
603
604        let composition_type = package.create_composition_sw_component_type("comp_parent").unwrap();
605        let _composition_r_port = composition_type
606            .create_r_port("port_r", &mode_switch_interface)
607            .unwrap();
608
609        assert_eq!(composition_type.ports().count(), 1);
610        mode_switch_interface.remove(true).unwrap();
611        assert_eq!(composition_type.ports().count(), 0);
612    }
613
614    #[test]
615    fn remove_parameter_interface() {
616        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
617        let package = model.get_or_create_package("/package").unwrap();
618        let parameter_interface = package.create_parameter_interface("parameter_interface").unwrap();
619
620        let composition_type = package.create_composition_sw_component_type("comp_parent").unwrap();
621        let _composition_r_port = composition_type.create_r_port("port_r", &parameter_interface).unwrap();
622
623        assert_eq!(composition_type.ports().count(), 1);
624        parameter_interface.remove(true).unwrap();
625        assert_eq!(composition_type.ports().count(), 0);
626    }
627
628    #[test]
629    fn remove_nv_data_interface() {
630        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
631        let package = model.get_or_create_package("/package").unwrap();
632        let nv_data_interface = package.create_nv_data_interface("nv_data_interface").unwrap();
633
634        let composition_type = package.create_composition_sw_component_type("comp_parent").unwrap();
635        let _composition_r_port = composition_type.create_r_port("port_r", &nv_data_interface).unwrap();
636
637        assert_eq!(composition_type.ports().count(), 1);
638        nv_data_interface.remove(true).unwrap();
639        assert_eq!(composition_type.ports().count(), 0);
640    }
641
642    #[test]
643    fn remove_trigger_interface() {
644        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
645        let package = model.get_or_create_package("/package").unwrap();
646        let trigger_interface = package.create_trigger_interface("trigger_interface").unwrap();
647
648        let composition_type = package.create_composition_sw_component_type("comp_parent").unwrap();
649        let _composition_r_port = composition_type.create_r_port("port_r", &trigger_interface).unwrap();
650
651        assert_eq!(composition_type.ports().count(), 1);
652        trigger_interface.remove(true).unwrap();
653        assert_eq!(composition_type.ports().count(), 0);
654    }
655}