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