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#[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 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 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 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 #[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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
85pub struct ModeGroup(Element);
86abstraction_element!(ModeGroup, ModeGroup);
87impl IdentifiableAbstractionElement for ModeGroup {}
88
89impl ModeGroup {
90 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 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 #[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#[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 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 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 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, ¶meters, data_type)
178 }
179
180 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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
196pub struct ParameterDataPrototype(Element);
197abstraction_element!(ParameterDataPrototype, ParameterDataPrototype);
198impl IdentifiableAbstractionElement for ParameterDataPrototype {}
199
200impl ParameterDataPrototype {
201 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 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 #[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 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 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 #[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#[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 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 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#[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 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 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
344pub trait AbstractPortInterface: AbstractionElement {
348 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 #[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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
374pub enum PortInterface {
375 SenderReceiverInterface(SenderReceiverInterface),
377 ClientServerInterface(ClientServerInterface),
379 ModeSwitchInterface(ModeSwitchInterface),
381 ParameterInterface(ParameterInterface),
383 NvDataInterface(NvDataInterface),
385 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 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#[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", ¶meter_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", ¶meter_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}