autosar_data_abstraction/system/
mod.rs

1use crate::communication::{
2    CanCluster, CanFrame, CanTpConfig, Cluster, CommunicationDirection, ContainerIPdu, ContainerIPduHeaderType,
3    DcmIPdu, DiagPduType, DoIpTpConfig, EthernetCluster, EventGroupControlType, FlexrayArTpConfig, FlexrayCluster,
4    FlexrayClusterSettings, FlexrayFrame, FlexrayTpConfig, Frame, GeneralPurposeIPdu, GeneralPurposeIPduCategory,
5    GeneralPurposePdu, GeneralPurposePduCategory, ISignal, ISignalGroup, ISignalIPdu, ISignalIPduGroup, LinCluster,
6    LinEventTriggeredFrame, LinSporadicFrame, LinUnconditionalFrame, MultiplexedIPdu, NPdu, NmConfig, NmPdu, Pdu,
7    RxAcceptContainedIPdu, SecureCommunicationProps, SecuredIPdu, ServiceInstanceCollectionSet, SoAdRoutingGroup,
8    SocketConnectionIpduIdentifierSet, SomeipTpConfig, SystemSignal, SystemSignalGroup, UserDefinedPdu,
9};
10use crate::datatype::SwBaseType;
11use crate::software_component::{CompositionSwComponentType, RootSwCompositionPrototype};
12use crate::{
13    AbstractionElement, ArPackage, AutosarAbstractionError, EcuInstance, IdentifiableAbstractionElement,
14    abstraction_element,
15};
16use autosar_data::{AutosarModel, Element, ElementName, WeakElement};
17
18mod mapping;
19
20pub use mapping::*;
21
22/// The System is the top level of a system template
23///
24/// It defines how ECUs communicate with each other over various networks.
25/// It also contains the mapping of software components to ECUs.
26#[derive(Debug, Clone, PartialEq, Eq, Hash)]
27pub struct System(Element);
28abstraction_element!(System, System);
29impl IdentifiableAbstractionElement for System {}
30
31impl System {
32    // find an existing \<SYSTEM\> in the model, if it exists
33    #[must_use]
34    pub(crate) fn find(model: &AutosarModel) -> Option<Self> {
35        let elem = model
36            .identifiable_elements()
37            .filter_map(|(_, weak)| weak.upgrade())
38            .find(|elem| elem.element_name() == ElementName::System)?;
39        Some(Self(elem))
40    }
41
42    /// Create a new SYSTEM in the given AR-PACKAGE
43    ///
44    /// Note that an Autosar model should ony contain one SYSTEM. This is not checked here.
45    ///
46    /// Use [`ArPackage::create_system`] to create a new system.
47    ///
48    /// # Example
49    ///
50    /// ```
51    /// # use autosar_data::*;
52    /// # use autosar_data_abstraction::*;
53    /// # fn main() -> Result<(), AutosarAbstractionError> {
54    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
55    /// let package = model.get_or_create_package("/my/pkg")?;
56    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
57    /// assert!(model.get_element_by_path("/my/pkg/System").is_some());
58    /// # Ok(())}
59    /// ```
60    ///
61    /// # Errors
62    ///
63    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the SYSTEM element
64    pub(crate) fn new(
65        name: &str,
66        package: &ArPackage,
67        category: SystemCategory,
68    ) -> Result<Self, AutosarAbstractionError> {
69        let pkg_elem_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
70
71        let system_elem = pkg_elem_elements.create_named_sub_element(ElementName::System, name)?;
72        let system = System(system_elem);
73        system.set_category(category)?;
74
75        Ok(system)
76    }
77
78    /// remove this `System` from the model
79    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
80        // remove all ECU instances of this System
81        for mapping in self
82            .0
83            .get_sub_element(ElementName::Mappings)
84            .into_iter()
85            .flat_map(|mappings| mappings.sub_elements())
86            .filter_map(|mapping| SystemMapping::try_from(mapping).ok())
87        {
88            mapping.remove(deep)?;
89        }
90
91        if let Some(root_sw_comp) = self.root_sw_composition() {
92            root_sw_comp.remove(deep)?;
93        }
94
95        // lots of elements that are not directly nested in the system are connected to it
96        // all of these are deleted if `deep` is requested
97        if deep {
98            for cluster in self.clusters() {
99                cluster.remove(deep)?;
100            }
101
102            for frame in self.frames() {
103                frame.remove(deep)?;
104            }
105
106            for pdu in self.pdus() {
107                pdu.remove(deep)?;
108            }
109
110            for isignal_ipdu_group in self.isignal_ipdu_groups() {
111                isignal_ipdu_group.remove(deep)?;
112            }
113
114            for isignal in self.isignals() {
115                isignal.remove(deep)?;
116            }
117
118            for isignal_group in self.isignal_groups() {
119                isignal_group.remove(deep)?;
120            }
121
122            if let Some(nm_config) = self.nm_config() {
123                nm_config.remove(deep)?;
124            }
125
126            for ecu_instance in self.ecu_instances() {
127                ecu_instance.remove(deep)?;
128            }
129        }
130
131        AbstractionElement::remove(self, deep)
132    }
133
134    /// set the category of the system
135    pub fn set_category(&self, category: SystemCategory) -> Result<(), AutosarAbstractionError> {
136        self.0
137            .get_or_create_sub_element(ElementName::Category)?
138            .set_character_data(category.to_string())?;
139        Ok(())
140    }
141
142    /// get the category of the system
143    #[must_use]
144    pub fn category(&self) -> Option<SystemCategory> {
145        self.0
146            .get_sub_element(ElementName::Category)?
147            .character_data()?
148            .string_value()?
149            .parse()
150            .ok()
151    }
152
153    /// set the pncVectorLength of the system
154    pub fn set_pnc_vector_length(&self, length: Option<u32>) -> Result<(), AutosarAbstractionError> {
155        if let Some(length) = length {
156            self.0
157                .get_or_create_sub_element(ElementName::PncVectorLength)?
158                .set_character_data(length as u64)?;
159        } else {
160            let _ = self.0.remove_sub_element_kind(ElementName::PncVectorLength);
161        }
162        Ok(())
163    }
164
165    /// get the pncVectorLength of the system
166    #[must_use]
167    pub fn pnc_vector_length(&self) -> Option<u32> {
168        self.0
169            .get_sub_element(ElementName::PncVectorLength)?
170            .character_data()?
171            .parse_integer()
172    }
173
174    /// set the pncVectorOffset of the system
175    pub fn set_pnc_vector_offset(&self, offset: Option<u32>) -> Result<(), AutosarAbstractionError> {
176        if let Some(offset) = offset {
177            self.0
178                .get_or_create_sub_element(ElementName::PncVectorOffset)?
179                .set_character_data(offset as u64)?;
180        } else {
181            let _ = self.0.remove_sub_element_kind(ElementName::PncVectorOffset);
182        }
183        Ok(())
184    }
185
186    /// get the pncVectorOffset of the system
187    #[must_use]
188    pub fn pnc_vector_offset(&self) -> Option<u32> {
189        self.0
190            .get_sub_element(ElementName::PncVectorOffset)?
191            .character_data()?
192            .parse_integer()
193    }
194
195    /// create an `EcuInstance` that is connected to this System
196    ///
197    /// # Example
198    ///
199    /// ```
200    /// # use autosar_data::*;
201    /// # use autosar_data_abstraction::*;
202    /// # fn main() -> Result<(), AutosarAbstractionError> {
203    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
204    /// # let package1 = model.get_or_create_package("/pkg1")?;
205    /// let system = package1.create_system("System", SystemCategory::SystemExtract)?;
206    /// # let package2 = model.get_or_create_package("/pkg2")?;
207    /// let ecu_instance = system.create_ecu_instance("ecu_name", &package2)?;
208    /// # Ok(())}
209    /// ```
210    ///
211    /// # Errors
212    ///
213    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the ECU-INSTANCE
214    pub fn create_ecu_instance(&self, name: &str, package: &ArPackage) -> Result<EcuInstance, AutosarAbstractionError> {
215        let ecu_instance = EcuInstance::new(name, package)?;
216        self.create_fibex_element_ref_unchecked(ecu_instance.element())?;
217
218        Ok(ecu_instance)
219    }
220
221    /// get an iterator over all ECU-INSTANCEs in this SYSTEM
222    ///
223    /// # Example
224    ///
225    /// ```
226    /// # use autosar_data::*;
227    /// # use autosar_data_abstraction::*;
228    /// # fn main() -> Result<(), AutosarAbstractionError> {
229    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
230    /// # let package = model.get_or_create_package("/pkg1")?;
231    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
232    /// system.create_ecu_instance("ecu_name1", &package)?;
233    /// system.create_ecu_instance("ecu_name2", &package)?;
234    /// for ecu in system.ecu_instances() {
235    ///     // do something
236    /// }
237    /// assert_eq!(system.ecu_instances().count(), 2);
238    /// # Ok(())}
239    /// ```
240    pub fn ecu_instances(&self) -> impl Iterator<Item = EcuInstance> + Send + use<> {
241        self.0
242            .get_sub_element(ElementName::FibexElements)
243            .into_iter()
244            .flat_map(|fibexelems| fibexelems.sub_elements())
245            .filter_map(|ferc| {
246                ferc.get_sub_element(ElementName::FibexElementRef)
247                    .and_then(|fer| fer.get_reference_target().ok())
248                    .and_then(|elem| EcuInstance::try_from(elem).ok())
249            })
250    }
251
252    /// create a new CAN-CLUSTER
253    ///
254    /// The cluster must have a channel to be valid, but this channel is not created automatically.
255    /// Call [`CanCluster::create_physical_channel`] to create it.
256    ///
257    /// # Example
258    ///
259    /// ```
260    /// # use autosar_data::*;
261    /// # use autosar_data_abstraction::*;
262    /// # use autosar_data_abstraction::communication::*;
263    /// # fn main() -> Result<(), AutosarAbstractionError> {
264    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
265    /// # let package = model.get_or_create_package("/pkg1")?;
266    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
267    /// let cluster = system.create_can_cluster("can_cluster", &package, None)?;
268    /// cluster.create_physical_channel("can_channel");
269    /// # Ok(())}
270    /// ```
271    ///
272    /// # Errors
273    ///
274    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the can cluster
275    pub fn create_can_cluster(
276        &self,
277        cluster_name: &str,
278        package: &ArPackage,
279        can_baudrate: Option<u32>,
280    ) -> Result<CanCluster, AutosarAbstractionError> {
281        let cluster = CanCluster::new(cluster_name, package, can_baudrate)?;
282        self.create_fibex_element_ref_unchecked(cluster.element())?;
283
284        Ok(cluster)
285    }
286
287    /// create a new ETHERNET-CLUSTER and connect it to the SYSTEM
288    ///
289    /// The cluster must have at least one channel to be valid.
290    /// Call [`EthernetCluster::create_physical_channel`] to create it.
291    ///
292    /// # Example
293    ///
294    /// ```
295    /// # use autosar_data::*;
296    /// # use autosar_data_abstraction::*;
297    /// # use autosar_data_abstraction::communication::*;
298    /// # fn main() -> Result<(), AutosarAbstractionError> {
299    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
300    /// # let package = model.get_or_create_package("/pkg1")?;
301    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
302    /// let cluster = system.create_ethernet_cluster("ethernet_cluster", &package)?;
303    /// let vlan_info = EthernetVlanInfo { vlan_name: "VLAN_1".to_string(), vlan_id: 1};
304    /// cluster.create_physical_channel("ethernet_channel", Some(&vlan_info));
305    /// # Ok(())}
306    /// ```
307    ///
308    /// # Errors
309    ///
310    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the ethernet cluster
311    pub fn create_ethernet_cluster(
312        &self,
313        cluster_name: &str,
314        package: &ArPackage,
315    ) -> Result<EthernetCluster, AutosarAbstractionError> {
316        let cluster = EthernetCluster::new(cluster_name, package)?;
317        self.create_fibex_element_ref_unchecked(cluster.element())?;
318
319        Ok(cluster)
320    }
321
322    /// create a new FLEXRAY-CLUSTER and connect it to the SYSTEM
323    ///
324    /// A `FlexrayClusterSettings` structure containing the timings and parameters for the Flexray cluster must be provided.
325    ///
326    /// The cluster must have at least one channel to be valid.
327    /// Call [`FlexrayCluster::create_physical_channel`] to create it.
328    ///
329    /// # Example
330    ///
331    /// ```
332    /// # use autosar_data::*;
333    /// # use autosar_data_abstraction::*;
334    /// # use autosar_data_abstraction::communication::*;
335    /// # fn main() -> Result<(), AutosarAbstractionError> {
336    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
337    /// # let package = model.get_or_create_package("/pkg1")?;
338    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
339    /// let cluster = system.create_flexray_cluster("flexray_cluster", &package, &FlexrayClusterSettings::default())?;
340    /// cluster.create_physical_channel("flexray_channel", FlexrayChannelName::A);
341    /// # Ok(())}
342    /// ```
343    ///
344    /// # Errors
345    ///
346    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the flexray cluster
347    pub fn create_flexray_cluster(
348        &self,
349        cluster_name: &str,
350        package: &ArPackage,
351        settings: &FlexrayClusterSettings,
352    ) -> Result<FlexrayCluster, AutosarAbstractionError> {
353        let cluster = FlexrayCluster::new(cluster_name, package, settings)?;
354        self.create_fibex_element_ref_unchecked(cluster.element())?;
355
356        Ok(cluster)
357    }
358
359    /// create a new LIN-CLUSTER
360    ///
361    /// The cluster must have a channel to be valid, but this channel is not created automatically.
362    /// Call [`LinCluster::create_physical_channel`] to create it.
363    ///
364    /// # Example
365    ///
366    /// ```
367    /// # use autosar_data::*;
368    /// # use autosar_data_abstraction::*;
369    /// # use autosar_data_abstraction::communication::*;
370    /// # fn main() -> Result<(), AutosarAbstractionError> {
371    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
372    /// # let package = model.get_or_create_package("/pkg1")?;
373    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
374    /// let cluster = system.create_lin_cluster("lin_cluster", &package)?;
375    /// cluster.create_physical_channel("can_channel");
376    /// # Ok(())}
377    /// ```
378    ///
379    /// # Errors
380    ///
381    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the lin cluster
382    pub fn create_lin_cluster(
383        &self,
384        cluster_name: &str,
385        package: &ArPackage,
386    ) -> Result<LinCluster, AutosarAbstractionError> {
387        let cluster = LinCluster::new(cluster_name, package)?;
388        self.create_fibex_element_ref_unchecked(cluster.element())?;
389
390        Ok(cluster)
391    }
392
393    /// Create an iterator over all clusters connected to the SYSTEM
394    ///
395    /// # Example
396    ///
397    /// ```
398    /// # use autosar_data::*;
399    /// # use autosar_data_abstraction::*;
400    /// # use autosar_data_abstraction::communication::*;
401    /// # fn main() -> Result<(), AutosarAbstractionError> {
402    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
403    /// # let package = model.get_or_create_package("/pkg1")?;
404    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
405    /// system.create_can_cluster("can_cluster", &package, None)?;
406    /// system.create_flexray_cluster("flexray_cluster", &package, &FlexrayClusterSettings::default())?;
407    /// for cluster in system.clusters() {
408    ///     // do something
409    /// }
410    /// assert_eq!(system.clusters().count(), 2);
411    /// # Ok(())}
412    /// ```
413    pub fn clusters(&self) -> impl Iterator<Item = Cluster> + Send + use<> {
414        self.0
415            .get_sub_element(ElementName::FibexElements)
416            .into_iter()
417            .flat_map(|fibexelems| fibexelems.sub_elements())
418            .filter_map(|ferc| {
419                ferc.get_sub_element(ElementName::FibexElementRef)
420                    .and_then(|fer| fer.get_reference_target().ok())
421                    .and_then(|elem| Cluster::try_from(elem).ok())
422            })
423    }
424
425    /// create a new [`CanFrame`]
426    ///
427    /// This new frame needs to be linked to a `CanPhysicalChannel`
428    pub fn create_can_frame(
429        &self,
430        name: &str,
431        package: &ArPackage,
432        byte_length: u64,
433    ) -> Result<CanFrame, AutosarAbstractionError> {
434        let can_frame = CanFrame::new(name, package, byte_length)?;
435        self.create_fibex_element_ref_unchecked(can_frame.element())?;
436
437        Ok(can_frame)
438    }
439
440    /// create a new [`FlexrayFrame`]
441    ///
442    /// This new frame needs to be linked to a `FlexrayPhysicalChannel`
443    pub fn create_flexray_frame(
444        &self,
445        name: &str,
446        package: &ArPackage,
447        byte_length: u64,
448    ) -> Result<FlexrayFrame, AutosarAbstractionError> {
449        let flexray_frame = FlexrayFrame::new(name, package, byte_length)?;
450        self.create_fibex_element_ref_unchecked(flexray_frame.element())?;
451
452        Ok(flexray_frame)
453    }
454
455    /// create a new [`LinEventTriggeredFrame`]
456    ///
457    /// This new frame needs to be linked to a `LinPhysicalChannel`
458    pub fn create_lin_event_triggered_frame(
459        &self,
460        name: &str,
461        package: &ArPackage,
462        byte_length: u64,
463    ) -> Result<LinEventTriggeredFrame, AutosarAbstractionError> {
464        let lin_event_triggered_frame = LinEventTriggeredFrame::new(name, package, byte_length)?;
465        self.create_fibex_element_ref_unchecked(lin_event_triggered_frame.element())?;
466
467        Ok(lin_event_triggered_frame)
468    }
469
470    /// create a new [`LinSporadicFrame`]
471    ///
472    /// This new frame needs to be linked to a `LinPhysicalChannel`
473    pub fn create_lin_sporadic_frame(
474        &self,
475        name: &str,
476        package: &ArPackage,
477        byte_length: u64,
478    ) -> Result<LinSporadicFrame, AutosarAbstractionError> {
479        let lin_sporadic_frame = LinSporadicFrame::new(name, package, byte_length)?;
480        self.create_fibex_element_ref_unchecked(lin_sporadic_frame.element())?;
481
482        Ok(lin_sporadic_frame)
483    }
484
485    /// create a new [`LinUnconditionalFrame`]
486    ///
487    /// This new frame needs to be linked to a `LinPhysicalChannel`
488    pub fn create_lin_unconditional_frame(
489        &self,
490        name: &str,
491        package: &ArPackage,
492        byte_length: u64,
493    ) -> Result<LinUnconditionalFrame, AutosarAbstractionError> {
494        let lin_unconditional_frame = LinUnconditionalFrame::new(name, package, byte_length)?;
495        self.create_fibex_element_ref_unchecked(lin_unconditional_frame.element())?;
496
497        Ok(lin_unconditional_frame)
498    }
499
500    /// iterate over all Frames in the System
501    ///
502    /// This iterator returns all CAN and Flexray frames that are connected to the System using a `FibexElementRef`.
503    pub fn frames(&self) -> impl Iterator<Item = Frame> + Send + use<> {
504        self.0
505            .get_sub_element(ElementName::FibexElements)
506            .into_iter()
507            .flat_map(|fibexelems| fibexelems.sub_elements())
508            .filter_map(|ferc| {
509                ferc.get_sub_element(ElementName::FibexElementRef)
510                    .and_then(|fer| fer.get_reference_target().ok())
511                    .and_then(|elem| Frame::try_from(elem).ok())
512            })
513    }
514
515    /// create a new isignal in the [`System`]
516    ///
517    /// # Example
518    ///
519    /// ```
520    /// # use autosar_data::*;
521    /// # use autosar_data_abstraction::*;
522    /// # use autosar_data_abstraction::communication::*;
523    /// # fn main() -> Result<(), AutosarAbstractionError> {
524    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
525    /// # let package = model.get_or_create_package("/pkg1")?;
526    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
527    /// let sig_package = model.get_or_create_package("/ISignals")?;
528    /// let sys_package = model.get_or_create_package("/SystemSignals")?;
529    /// let system_signal = sys_package.create_system_signal("signal1")?;
530    /// system.create_isignal("signal1", &sig_package, 32, &system_signal, None)?;
531    /// # Ok(())}
532    /// ```
533    ///
534    /// # Errors
535    ///
536    /// - [`AutosarAbstractionError::InvalidParameter`] `sig_package` and `sys_package` may not be identical
537    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
538    pub fn create_isignal(
539        &self,
540        name: &str,
541        package: &ArPackage,
542        bit_length: u64,
543        syssignal: &SystemSignal,
544        datatype: Option<&SwBaseType>,
545    ) -> Result<ISignal, AutosarAbstractionError> {
546        let i_signal = ISignal::new(name, package, bit_length, syssignal, datatype)?;
547
548        self.create_fibex_element_ref_unchecked(i_signal.element())?;
549
550        Ok(i_signal)
551    }
552
553    /// iterate over all `ISignals` in the System
554    ///
555    /// This iterator returns all `ISignals` that are connected to the System using a `FibexElementRef`.
556    pub fn isignals(&self) -> impl Iterator<Item = ISignal> + Send + use<> {
557        self.0
558            .get_sub_element(ElementName::FibexElements)
559            .into_iter()
560            .flat_map(|fibexelems| fibexelems.sub_elements())
561            .filter_map(|ferc| {
562                ferc.get_sub_element(ElementName::FibexElementRef)
563                    .and_then(|fer| fer.get_reference_target().ok())
564                    .and_then(|elem| ISignal::try_from(elem).ok())
565            })
566    }
567
568    /// create a new signal group in the [`System`]
569    ///
570    /// `I-SIGNAL-GROUP` and `SYSTEM-SIGNAL-GROUP` are created using the same name; therefore they must be placed in
571    /// different packages: `sig_package` and `sys_package` may not be identical.
572    ///
573    /// # Example
574    ///
575    /// ```
576    /// # use autosar_data::*;
577    /// # use autosar_data_abstraction::*;
578    /// # use autosar_data_abstraction::communication::*;
579    /// # fn main() -> Result<(), AutosarAbstractionError> {
580    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
581    /// # let package = model.get_or_create_package("/pkg1")?;
582    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
583    /// let sig_package = model.get_or_create_package("/ISignals")?;
584    /// let sys_package = model.get_or_create_package("/SystemSignals")?;
585    /// let system_signal_group = sys_package.create_system_signal_group("signalgroup")?;
586    /// system.create_isignal_group("signal_group", &sig_package, &system_signal_group)?;
587    /// # Ok(())}
588    /// ```
589    ///
590    /// # Errors
591    ///
592    /// - [`AutosarAbstractionError::InvalidParameter`] `sig_package` and `sys_package` may not be identical
593    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
594    pub fn create_isignal_group(
595        &self,
596        name: &str,
597        package: &ArPackage,
598        system_signal_group: &SystemSignalGroup,
599    ) -> Result<ISignalGroup, AutosarAbstractionError> {
600        let i_signal_group = ISignalGroup::new(name, package, system_signal_group)?;
601
602        self.create_fibex_element_ref_unchecked(i_signal_group.element())?;
603
604        Ok(i_signal_group)
605    }
606
607    /// iterate over all `ISignalGroups` in the System
608    ///
609    /// This iterator returns all `ISignalGroups` that are connected to the System using a `FibexElementRef`.
610    pub fn isignal_groups(&self) -> impl Iterator<Item = ISignalGroup> + Send + use<> {
611        self.0
612            .get_sub_element(ElementName::FibexElements)
613            .into_iter()
614            .flat_map(|fibexelems| fibexelems.sub_elements())
615            .filter_map(|ferc| {
616                ferc.get_sub_element(ElementName::FibexElementRef)
617                    .and_then(|fer| fer.get_reference_target().ok())
618                    .and_then(|elem| ISignalGroup::try_from(elem).ok())
619            })
620    }
621
622    /// create an [`ISignalIPdu`] in the [`System`]
623    ///
624    /// # Example
625    ///
626    /// ```
627    /// # use autosar_data::*;
628    /// # use autosar_data_abstraction::*;
629    /// # use autosar_data_abstraction::communication::*;
630    /// # fn main() -> Result<(), AutosarAbstractionError> {
631    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
632    /// # let package = model.get_or_create_package("/pkg1")?;
633    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
634    /// let package = model.get_or_create_package("/Pdus")?;
635    /// system.create_isignal_ipdu("pdu", &package, 42)?;
636    /// # Ok(())}
637    /// ```
638    ///
639    /// # Errors
640    ///
641    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
642    pub fn create_isignal_ipdu(
643        &self,
644        name: &str,
645        package: &ArPackage,
646        length: u32,
647    ) -> Result<ISignalIPdu, AutosarAbstractionError> {
648        let pdu = ISignalIPdu::new(name, package, length)?;
649        self.create_fibex_element_ref_unchecked(pdu.element())?;
650
651        Ok(pdu)
652    }
653
654    /// create an [`NmPdu`] in the [`System`]
655    ///
656    /// # Example
657    ///
658    /// ```
659    /// # use autosar_data::*;
660    /// # use autosar_data_abstraction::*;
661    /// # use autosar_data_abstraction::communication::*;
662    /// # fn main() -> Result<(), AutosarAbstractionError> {
663    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
664    /// # let package = model.get_or_create_package("/pkg1")?;
665    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
666    /// let package = model.get_or_create_package("/Pdus")?;
667    /// system.create_nm_pdu("pdu", &package, 42)?;
668    /// # Ok(())}
669    /// ```
670    ///
671    /// # Errors
672    ///
673    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
674    pub fn create_nm_pdu(
675        &self,
676        name: &str,
677        package: &ArPackage,
678        length: u32,
679    ) -> Result<NmPdu, AutosarAbstractionError> {
680        let pdu = NmPdu::new(name, package, length)?;
681        self.create_fibex_element_ref_unchecked(pdu.element())?;
682
683        Ok(pdu)
684    }
685
686    /// create an [`NPdu`] in the [`System`]
687    ///
688    /// # Example
689    ///
690    /// ```
691    /// # use autosar_data::*;
692    /// # use autosar_data_abstraction::*;
693    /// # use autosar_data_abstraction::communication::*;
694    /// # fn main() -> Result<(), AutosarAbstractionError> {
695    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
696    /// # let package = model.get_or_create_package("/pkg1")?;
697    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
698    /// let package = model.get_or_create_package("/Pdus")?;
699    /// system.create_n_pdu("pdu", &package, 42)?;
700    /// # Ok(())}
701    /// ```
702    ///
703    /// # Errors
704    ///
705    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
706    pub fn create_n_pdu(&self, name: &str, package: &ArPackage, length: u32) -> Result<NPdu, AutosarAbstractionError> {
707        let pdu = NPdu::new(name, package, length)?;
708        self.create_fibex_element_ref_unchecked(pdu.element())?;
709
710        Ok(pdu)
711    }
712
713    /// create a [`DcmIPdu`] in the [`System`]
714    ///
715    /// # Example
716    ///
717    /// ```
718    /// # use autosar_data::*;
719    /// # use autosar_data_abstraction::*;
720    /// # use autosar_data_abstraction::communication::*;
721    /// # fn main() -> Result<(), AutosarAbstractionError> {
722    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
723    /// # let package = model.get_or_create_package("/pkg1")?;
724    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
725    /// let package = model.get_or_create_package("/Pdus")?;
726    /// system.create_dcm_ipdu("pdu", &package, 42, DiagPduType::DiagRequest)?;
727    /// # Ok(())}
728    /// ```
729    ///
730    /// # Errors
731    ///
732    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
733    pub fn create_dcm_ipdu(
734        &self,
735        name: &str,
736        package: &ArPackage,
737        length: u32,
738        diag_pdu_type: DiagPduType,
739    ) -> Result<DcmIPdu, AutosarAbstractionError> {
740        let pdu = DcmIPdu::new(name, package, length, diag_pdu_type)?;
741        self.create_fibex_element_ref_unchecked(pdu.element())?;
742
743        Ok(pdu)
744    }
745
746    /// create a [`GeneralPurposePdu`] in the [`System`]
747    ///
748    /// # Example
749    ///
750    /// ```
751    /// # use autosar_data::*;
752    /// # use autosar_data_abstraction::*;
753    /// # use autosar_data_abstraction::communication::*;
754    /// # fn main() -> Result<(), AutosarAbstractionError> {
755    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
756    /// # let package = model.get_or_create_package("/pkg1")?;
757    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
758    /// let package = model.get_or_create_package("/Pdus")?;
759    /// system.create_general_purpose_pdu("pdu", &package, 42, GeneralPurposePduCategory::GlobalTime)?;
760    /// # Ok(())}
761    /// ```
762    ///
763    /// # Errors
764    ///
765    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
766    pub fn create_general_purpose_pdu(
767        &self,
768        name: &str,
769        package: &ArPackage,
770        length: u32,
771        category: GeneralPurposePduCategory,
772    ) -> Result<GeneralPurposePdu, AutosarAbstractionError> {
773        let pdu = GeneralPurposePdu::new(name, package, length, category)?;
774        self.create_fibex_element_ref_unchecked(pdu.element())?;
775
776        Ok(pdu)
777    }
778
779    /// create a [`GeneralPurposeIPdu`] in the [`System`]
780    ///
781    /// # Example
782    ///
783    /// ```
784    /// # use autosar_data::*;
785    /// # use autosar_data_abstraction::*;
786    /// # use autosar_data_abstraction::communication::*;
787    /// # fn main() -> Result<(), AutosarAbstractionError> {
788    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
789    /// # let package = model.get_or_create_package("/pkg1")?;
790    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
791    /// let package = model.get_or_create_package("/Pdus")?;
792    /// system.create_general_purpose_ipdu("pdu", &package, 42, GeneralPurposeIPduCategory::Xcp)?;
793    /// # Ok(())}
794    /// ```
795    ///
796    /// # Errors
797    ///
798    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
799    pub fn create_general_purpose_ipdu(
800        &self,
801        name: &str,
802        package: &ArPackage,
803        length: u32,
804        category: GeneralPurposeIPduCategory,
805    ) -> Result<GeneralPurposeIPdu, AutosarAbstractionError> {
806        let pdu = GeneralPurposeIPdu::new(name, package, length, category)?;
807        self.create_fibex_element_ref_unchecked(pdu.element())?;
808
809        Ok(pdu)
810    }
811
812    /// create a [`ContainerIPdu`] in the [`System`]
813    ///
814    /// # Example
815    ///
816    /// ```
817    /// # use autosar_data::*;
818    /// # use autosar_data_abstraction::*;
819    /// # use autosar_data_abstraction::communication::*;
820    /// # fn main() -> Result<(), AutosarAbstractionError> {
821    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
822    /// # let package = model.get_or_create_package("/pkg1")?;
823    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
824    /// let package = model.get_or_create_package("/Pdus")?;
825    /// system.create_container_ipdu("pdu", &package, 42, ContainerIPduHeaderType::ShortHeader, RxAcceptContainedIPdu::AcceptAll)?;
826    /// # Ok(())}
827    /// ```
828    ///
829    /// # Errors
830    ///
831    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
832    pub fn create_container_ipdu(
833        &self,
834        name: &str,
835        package: &ArPackage,
836        length: u32,
837        header_type: ContainerIPduHeaderType,
838        rx_accept: RxAcceptContainedIPdu,
839    ) -> Result<ContainerIPdu, AutosarAbstractionError> {
840        let pdu = ContainerIPdu::new(name, package, length, header_type, rx_accept)?;
841        self.create_fibex_element_ref_unchecked(pdu.element())?;
842
843        Ok(pdu)
844    }
845
846    /// create a [`SecuredIPdu`] in the [`System`]
847    ///
848    /// # Example
849    ///
850    /// ```
851    /// # use autosar_data::*;
852    /// # use autosar_data_abstraction::*;
853    /// # use autosar_data_abstraction::communication::*;
854    /// # fn main() -> Result<(), AutosarAbstractionError> {
855    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
856    /// # let package = model.get_or_create_package("/pkg1")?;
857    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
858    /// let package = model.get_or_create_package("/Pdus")?;
859    /// let secure_communication_props = SecureCommunicationProps::default();
860    /// system.create_secured_ipdu("pdu", &package, 42, &secure_communication_props)?;
861    /// # Ok(())}
862    /// ```
863    ///
864    /// # Errors
865    ///
866    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
867    pub fn create_secured_ipdu(
868        &self,
869        name: &str,
870        package: &ArPackage,
871        length: u32,
872        secure_props: &SecureCommunicationProps,
873    ) -> Result<SecuredIPdu, AutosarAbstractionError> {
874        let pdu = SecuredIPdu::new(name, package, length, secure_props)?;
875        self.create_fibex_element_ref_unchecked(pdu.element())?;
876
877        Ok(pdu)
878    }
879
880    /// create a [`MultiplexedIPdu`] in the [`System`]
881    ///
882    /// # Example
883    ///
884    /// ```
885    /// # use autosar_data::*;
886    /// # use autosar_data_abstraction::*;
887    /// # use autosar_data_abstraction::communication::*;
888    /// # fn main() -> Result<(), AutosarAbstractionError> {
889    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
890    /// # let package = model.get_or_create_package("/pkg1")?;
891    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
892    /// let package = model.get_or_create_package("/Pdus")?;
893    /// system.create_multiplexed_ipdu("pdu", &package, 42)?;
894    /// # Ok(())}
895    /// ```
896    ///
897    /// # Errors
898    ///
899    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
900    pub fn create_multiplexed_ipdu(
901        &self,
902        name: &str,
903        package: &ArPackage,
904        length: u32,
905    ) -> Result<MultiplexedIPdu, AutosarAbstractionError> {
906        let pdu = MultiplexedIPdu::new(name, package, length)?;
907        self.create_fibex_element_ref_unchecked(pdu.element())?;
908
909        Ok(pdu)
910    }
911
912    /// create a [`UserDefinedPdu`] in the [`System`]
913    ///
914    /// # Example
915    ///
916    /// ```
917    /// # use autosar_data::*;
918    /// # use autosar_data_abstraction::*;
919    /// # use autosar_data_abstraction::communication::*;
920    /// # fn main() -> Result<(), AutosarAbstractionError> {
921    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
922    /// # let package = model.get_or_create_package("/pkg1")?;
923    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
924    /// let package = model.get_or_create_package("/Pdus")?;
925    /// system.create_user_defined_pdu("pdu", &package, 42)?;
926    /// # Ok(())}
927    /// ```
928    ///
929    /// # Errors
930    ///
931    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
932    pub fn create_user_defined_pdu(
933        &self,
934        name: &str,
935        package: &ArPackage,
936        length: u32,
937    ) -> Result<UserDefinedPdu, AutosarAbstractionError> {
938        let pdu = UserDefinedPdu::new(name, package, length)?;
939        self.create_fibex_element_ref_unchecked(pdu.element())?;
940
941        Ok(pdu)
942    }
943
944    /// iterate over all PDUs in the System
945    ///
946    /// This iterator returns all PDUs that are connected to the System using a `FibexElementRef`.
947    pub fn pdus(&self) -> impl Iterator<Item = Pdu> + Send + use<> {
948        self.0
949            .get_sub_element(ElementName::FibexElements)
950            .into_iter()
951            .flat_map(|fibexelems| fibexelems.sub_elements())
952            .filter_map(|ferc| {
953                ferc.get_sub_element(ElementName::FibexElementRef)
954                    .and_then(|fer| fer.get_reference_target().ok())
955                    .and_then(|elem| Pdu::try_from(elem).ok())
956            })
957    }
958
959    /// create a new `ISignalIPduGroup` in the package
960    ///
961    /// # Example
962    ///
963    /// ```
964    /// # use autosar_data::*;
965    /// # use autosar_data_abstraction::{*, communication::*};
966    /// # fn main() -> Result<(), AutosarAbstractionError> {
967    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
968    /// # let package = model.get_or_create_package("/some/package")?;
969    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
970    /// let pdu_group = system.create_isignal_ipdu_group("PduGroup", &package, CommunicationDirection::In)?;
971    /// # assert!(model.get_element_by_path("/some/package/PduGroup").is_some());
972    /// # Ok(())}
973    /// ```
974    ///
975    /// # Errors
976    ///
977    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the IMPLEMENTATION-DATA-TYPE element
978    pub fn create_isignal_ipdu_group(
979        &self,
980        name: &str,
981        package: &ArPackage,
982        communication_direction: CommunicationDirection,
983    ) -> Result<ISignalIPduGroup, AutosarAbstractionError> {
984        let ipdu_group = ISignalIPduGroup::new(name, package, communication_direction)?;
985        self.create_fibex_element_ref_unchecked(ipdu_group.element())?;
986
987        Ok(ipdu_group)
988    }
989
990    /// iterate over all ISignalIPduGroups in the System
991    ///
992    /// This iterator returns all ISignalIPduGroups that are connected to the System using a `FibexElementRef`.
993    pub fn isignal_ipdu_groups(&self) -> impl Iterator<Item = ISignalIPduGroup> + Send + use<> {
994        self.0
995            .get_sub_element(ElementName::FibexElements)
996            .into_iter()
997            .flat_map(|fibexelems| fibexelems.sub_elements())
998            .filter_map(|ferc| {
999                ferc.get_sub_element(ElementName::FibexElementRef)
1000                    .and_then(|fer| fer.get_reference_target().ok())
1001                    .and_then(|elem| ISignalIPduGroup::try_from(elem).ok())
1002            })
1003    }
1004
1005    /// Create a `SocketConnectionIpduIdentifierSet` in the SYSTEM
1006    ///
1007    /// `SocketConnectionIpduIdentifierSet` are part of the new ethernet modeling that was introduced in Autosar 4.5.0 (`AUTOSAR_00048`).
1008    ///
1009    /// # Example
1010    ///
1011    /// ```
1012    /// # use autosar_data::*;
1013    /// # use autosar_data_abstraction::*;
1014    /// # use autosar_data_abstraction::communication::*;
1015    /// # fn main() -> Result<(), AutosarAbstractionError> {
1016    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1017    /// # let package = model.get_or_create_package("/pkg1")?;
1018    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
1019    /// let set = system.create_socket_connection_ipdu_identifier_set("set", &package)?;
1020    /// # Ok(())}
1021    /// ```
1022    pub fn create_socket_connection_ipdu_identifier_set(
1023        &self,
1024        name: &str,
1025        package: &ArPackage,
1026    ) -> Result<SocketConnectionIpduIdentifierSet, AutosarAbstractionError> {
1027        let set = SocketConnectionIpduIdentifierSet::new(name, package)?;
1028        self.create_fibex_element_ref_unchecked(set.element())?;
1029
1030        Ok(set)
1031    }
1032
1033    /// Create a `SoAdRoutingGroup` in the SYSTEM
1034    ///
1035    /// `SoAdRoutingGroup` are part of the old ethernet modeling that was used prior to Autosar 4.5.0 (`AUTOSAR_00048`).
1036    /// The elements are still present (but obsolete) in newer versions of the standard.
1037    /// Old and new elements may not be mixed in the same model.
1038    pub fn create_so_ad_routing_group(
1039        &self,
1040        name: &str,
1041        package: &ArPackage,
1042        control_type: Option<EventGroupControlType>,
1043    ) -> Result<SoAdRoutingGroup, AutosarAbstractionError> {
1044        let group = SoAdRoutingGroup::new(name, package, control_type)?;
1045        self.create_fibex_element_ref_unchecked(group.element())?;
1046
1047        Ok(group)
1048    }
1049
1050    /// Create a `ServiceInstanceCollectionSet` in the SYSTEM
1051    ///
1052    /// `ServiceInstanceCollectionSet`s are part of the new ethernet modeling that was introduced in Autosar 4.5.0 (`AUTOSAR_00048`).
1053    pub fn create_service_instance_collection_set(
1054        &self,
1055        name: &str,
1056        package: &ArPackage,
1057    ) -> Result<ServiceInstanceCollectionSet, AutosarAbstractionError> {
1058        let set = ServiceInstanceCollectionSet::new(name, package)?;
1059        self.create_fibex_element_ref_unchecked(set.element())?;
1060
1061        Ok(set)
1062    }
1063
1064    /// Create a `SomeipTpConfig` in the SYSTEM
1065    ///
1066    /// `SomeipTpConfig`s contain the configuration how to segment or reassemble large `SomeipTp` PDUs.
1067    pub fn create_someip_tp_config<T: Into<Cluster> + Clone>(
1068        &self,
1069        name: &str,
1070        package: &ArPackage,
1071        cluster: &T,
1072    ) -> Result<SomeipTpConfig, AutosarAbstractionError> {
1073        let config = SomeipTpConfig::new(name, package, &cluster.clone().into())?;
1074        self.create_fibex_element_ref_unchecked(config.element())?;
1075
1076        Ok(config)
1077    }
1078
1079    /// Create a `CanTpConfig` in the SYSTEM
1080    ///
1081    /// `CanTpConfig`s contain the configuration how to segment or reassemble diagnostic messages on a CAN bus.
1082    pub fn create_can_tp_config(
1083        &self,
1084        name: &str,
1085        package: &ArPackage,
1086        can_cluster: &CanCluster,
1087    ) -> Result<CanTpConfig, AutosarAbstractionError> {
1088        let config = CanTpConfig::new(name, package, can_cluster)?;
1089        self.create_fibex_element_ref_unchecked(config.element())?;
1090
1091        Ok(config)
1092    }
1093
1094    /// Create a `DoIpTpConfig` in the SYSTEM
1095    ///
1096    /// `DoIpTpConfig`s contain the configuration how to transmit diagnostic messages over IP networks.
1097    pub fn create_doip_tp_config(
1098        &self,
1099        name: &str,
1100        package: &ArPackage,
1101        eth_cluster: &EthernetCluster,
1102    ) -> Result<DoIpTpConfig, AutosarAbstractionError> {
1103        let config = DoIpTpConfig::new(name, package, eth_cluster)?;
1104        self.create_fibex_element_ref_unchecked(config.element())?;
1105
1106        Ok(config)
1107    }
1108
1109    /// Create a `FlexRayTpConfig` in the SYSTEM
1110    ///
1111    /// `FlexRayTpConfig`s describe how to segment or reassemble diagnostic messages on a `FlexRay` bus.
1112    /// This configuration type is used for Flexray ISO TP communication.
1113    pub fn create_flexray_tp_config(
1114        &self,
1115        name: &str,
1116        package: &ArPackage,
1117        flexray_cluster: &FlexrayCluster,
1118    ) -> Result<FlexrayTpConfig, AutosarAbstractionError> {
1119        let config = FlexrayTpConfig::new(name, package, flexray_cluster)?;
1120        self.create_fibex_element_ref_unchecked(config.element())?;
1121
1122        Ok(config)
1123    }
1124
1125    /// Create a `FlexrayArTpConfig` in the SYSTEM
1126    ///
1127    /// `FlexrayArTpConfig`s describe how to segment or reassemble diagnostic messages on a `FlexRay` bus.
1128    /// This configuration type is used for Flexray AUTOSAR TP communication.
1129    pub fn create_flexray_ar_tp_config(
1130        &self,
1131        name: &str,
1132        package: &ArPackage,
1133        flexray_cluster: &FlexrayCluster,
1134    ) -> Result<FlexrayArTpConfig, AutosarAbstractionError> {
1135        let config = FlexrayArTpConfig::new(name, package, flexray_cluster)?;
1136        self.create_fibex_element_ref_unchecked(config.element())?;
1137
1138        Ok(config)
1139    }
1140
1141    /// Create a new `NmConfig` in the SYSTEM
1142    ///
1143    /// `NmConfig`s contain the configuration for network management.
1144    /// The System may contain zero or one `NmConfig`s.
1145    pub fn create_nm_config(&self, name: &str, package: &ArPackage) -> Result<NmConfig, AutosarAbstractionError> {
1146        let config = NmConfig::new(name, package)?;
1147        self.create_fibex_element_ref_unchecked(config.element())?;
1148
1149        Ok(config)
1150    }
1151
1152    /// Get the `NmConfig` of the SYSTEM, if any
1153    ///
1154    /// The System may contain zero or one `NmConfig`s.
1155    #[must_use]
1156    pub fn nm_config(&self) -> Option<NmConfig> {
1157        self.0
1158            .get_sub_element(ElementName::FibexElements)
1159            .into_iter()
1160            .flat_map(|fibexelems| fibexelems.sub_elements())
1161            .find_map(|ferc| {
1162                ferc.get_sub_element(ElementName::FibexElementRef)
1163                    .and_then(|fer| fer.get_reference_target().ok())
1164                    .and_then(|elem| NmConfig::try_from(elem).ok())
1165            })
1166    }
1167
1168    /// connect an element to the SYSTEM by creating a FIBEX-ELEMENT-REF
1169    ///
1170    /// If there is already a FIBEX-ELEMENT-REF, this function does nothing, successfully.
1171    ///
1172    /// # Example
1173    ///
1174    /// ```
1175    /// # use autosar_data::*;
1176    /// # use autosar_data_abstraction::*;
1177    /// # use autosar_data_abstraction::communication::*;
1178    /// # fn main() -> Result<(), AutosarAbstractionError> {
1179    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1180    /// # let package = model.get_or_create_package("/pkg1")?;
1181    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
1182    /// # let pkg_elements = package.element().get_sub_element(ElementName::Elements).unwrap();
1183    /// let can_cluster = pkg_elements.create_named_sub_element(ElementName::CanCluster, "Cluster")?;
1184    /// system.create_fibex_element_ref(&can_cluster)?;
1185    /// # Ok(())}
1186    /// ```
1187    ///
1188    /// # Errors
1189    ///
1190    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model
1191    pub fn create_fibex_element_ref(&self, elem: &Element) -> Result<(), AutosarAbstractionError> {
1192        let model = elem.model()?;
1193        let refs = model.get_references_to(&elem.path()?);
1194        for reference in refs.iter().filter_map(WeakElement::upgrade) {
1195            if reference.element_name() == ElementName::FibexElementRef {
1196                // a FIBEX-ELEMENT-REF for this elem already exists.
1197                return Ok(());
1198            }
1199        }
1200        self.create_fibex_element_ref_unchecked(elem)
1201    }
1202
1203    fn create_fibex_element_ref_unchecked(&self, elem: &Element) -> Result<(), AutosarAbstractionError> {
1204        let fibex_elements = self.0.get_or_create_sub_element(ElementName::FibexElements)?;
1205        let fibex_element_ref = fibex_elements
1206            .create_sub_element(ElementName::FibexElementRefConditional)?
1207            .create_sub_element(ElementName::FibexElementRef)?;
1208        fibex_element_ref.set_reference_target(elem)?;
1209        Ok(())
1210    }
1211
1212    /// set the root software composition of the system
1213    ///
1214    /// When the root software composition is set, a root sw composition prototype is created for it.
1215    /// This function will remove any existing root sw composition prototype
1216    pub fn set_root_sw_composition(
1217        &self,
1218        name: &str,
1219        composition_type: &CompositionSwComponentType,
1220    ) -> Result<RootSwCompositionPrototype, AutosarAbstractionError> {
1221        let root_compositions = self
1222            .0
1223            .get_or_create_sub_element(ElementName::RootSoftwareCompositions)?;
1224
1225        if let Some(existing_composition) = root_compositions.get_sub_element(ElementName::RootSwCompositionPrototype) {
1226            root_compositions.remove_sub_element(existing_composition)?;
1227        }
1228        RootSwCompositionPrototype::new(name, &root_compositions, composition_type)
1229    }
1230
1231    /// get the root software composition of the system
1232    #[must_use]
1233    pub fn root_sw_composition(&self) -> Option<RootSwCompositionPrototype> {
1234        let root_compositions = self.element().get_sub_element(ElementName::RootSoftwareCompositions)?;
1235        let root_composition = root_compositions.get_sub_element(ElementName::RootSwCompositionPrototype)?;
1236        RootSwCompositionPrototype::try_from(root_composition).ok()
1237    }
1238
1239    /// get or create a mapping for this system
1240    ///
1241    /// There does not seem to be any benefit to having multiple mappings for a single system, so this function
1242    /// will return the first mapping if it exists. Otherwise a new mapping will be created with the provided name.
1243    pub fn get_or_create_mapping(&self, name: &str) -> Result<SystemMapping, AutosarAbstractionError> {
1244        if let Some(mapping) = self.0.get_sub_element(ElementName::Mappings)
1245            && let Some(mapping) = mapping.get_sub_element(ElementName::SystemMapping)
1246        {
1247            return SystemMapping::try_from(mapping);
1248        }
1249        SystemMapping::new(name, self)
1250    }
1251}
1252
1253//#########################################################
1254
1255/// The category of a System
1256#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1257pub enum SystemCategory {
1258    /// The `System` is used to describe system constraints
1259    SystemConstraints,
1260    /// The `System` is used to describe the system configuration of a complete AUTOSAR system
1261    SystemDescription,
1262    /// The `System` is used to describe a subsystem specific view on the complete system description
1263    SystemExtract,
1264    /// The `System` is used to describe the ECU specific view on the complete system description
1265    EcuExtract,
1266    /// The `System` is used to describe a functional (solution-independent/abstract) system design
1267    AbstractSystemDescription,
1268    /// The `System` is used to describe the closed view on one ECU
1269    EcuSystemDescription,
1270    /// The `System` describes the content of one `CpSoftwareCluster`
1271    SwClusterSystemDescription,
1272    /// `System` which describes the rapid prototyping algorithm in the format of AUTOSAR Software Components
1273    RptSystem,
1274}
1275
1276impl std::fmt::Display for SystemCategory {
1277    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1278        match self {
1279            SystemCategory::SystemConstraints => f.write_str("SYSTEM_CONSTRAINTS"),
1280            SystemCategory::SystemDescription => f.write_str("SYSTEM_DESCRIPTION"),
1281            SystemCategory::SystemExtract => f.write_str("SYSTEM_EXTRACT"),
1282            SystemCategory::EcuExtract => f.write_str("ECU_EXTRACT"),
1283            SystemCategory::AbstractSystemDescription => f.write_str("ABSTRACT_SYSTEM_DESCRIPTION"),
1284            SystemCategory::EcuSystemDescription => f.write_str("ECU_SYSTEM_DESCRIPTION"),
1285            SystemCategory::SwClusterSystemDescription => f.write_str("SW_CLUSTER_SYSTEM_DESCRIPTION"),
1286            SystemCategory::RptSystem => f.write_str("RPT_SYSTEM"),
1287        }
1288    }
1289}
1290
1291impl std::str::FromStr for SystemCategory {
1292    type Err = AutosarAbstractionError;
1293
1294    fn from_str(s: &str) -> Result<Self, Self::Err> {
1295        match s {
1296            "SYSTEM_CONSTRAINTS" => Ok(SystemCategory::SystemConstraints),
1297            "SYSTEM_DESCRIPTION" => Ok(SystemCategory::SystemDescription),
1298            "SYSTEM_EXTRACT" => Ok(SystemCategory::SystemExtract),
1299            "ECU_EXTRACT" => Ok(SystemCategory::EcuExtract),
1300            "ABSTRACT_SYSTEM_DESCRIPTION" => Ok(SystemCategory::AbstractSystemDescription),
1301            "ECU_SYSTEM_DESCRIPTION" => Ok(SystemCategory::EcuSystemDescription),
1302            "SW_CLUSTER_SYSTEM_DESCRIPTION" => Ok(SystemCategory::SwClusterSystemDescription),
1303            "RPT_SYSTEM" => Ok(SystemCategory::RptSystem),
1304            _ => Err(AutosarAbstractionError::InvalidParameter(s.to_string())),
1305        }
1306    }
1307}
1308
1309//#########################################################
1310
1311/// check if the system element is used anywhere
1312pub(crate) fn is_used_system_element(element: &Element) -> bool {
1313    let Ok(model) = element.model() else {
1314        // not connected to model -> unused
1315        return false;
1316    };
1317    let Ok(path) = element.path() else {
1318        // not connected to model any more -> unused
1319        // this case is only reachable through a race condition (parallel deletion)
1320        return false;
1321    };
1322    let references = model.get_references_to(&path);
1323
1324    // it is unused if there is either a single FIBEX-ELEMENT-REF (typical), or no reference at all (edge case)
1325    if let [weak_elem] = references.as_slice()
1326        && weak_elem
1327            .upgrade()
1328            .is_none_or(|elem| elem.element_name() == ElementName::FibexElementRef)
1329    {
1330        false
1331    } else {
1332        !references.is_empty()
1333    }
1334}
1335
1336//#########################################################
1337
1338#[cfg(test)]
1339mod test {
1340    use crate::{
1341        AbstractionElement, AutosarModelAbstraction, IdentifiableAbstractionElement, System,
1342        communication::{
1343            ContainerIPduHeaderType, DiagPduType, FlexrayClusterSettings, GeneralPurposeIPduCategory,
1344            GeneralPurposePduCategory, RxAcceptContainedIPdu, SecureCommunicationProps,
1345        },
1346        software_component::CompositionSwComponentType,
1347        system::SystemCategory,
1348    };
1349    use autosar_data::{AutosarVersion, ElementName};
1350
1351    #[test]
1352    fn system() {
1353        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1354
1355        // try to find a system in the empty model
1356        let result = model.find_system();
1357        assert!(result.is_none());
1358
1359        // create a System
1360        let package = model.get_or_create_package("/SYSTEM").unwrap();
1361        let system = package.create_system("System", SystemCategory::SystemExtract).unwrap();
1362
1363        // find the newly created system
1364        let system_2 = model.find_system().unwrap();
1365        assert_eq!(system, system_2);
1366
1367        // name
1368        assert_eq!(system.name().unwrap(), "System");
1369        system.set_name("NewName").unwrap();
1370        assert_eq!(system.name().unwrap(), "NewName");
1371
1372        // category
1373        assert_eq!(system.category().unwrap(), SystemCategory::SystemExtract);
1374        system.set_category(SystemCategory::EcuExtract).unwrap();
1375        assert_eq!(system.category().unwrap(), SystemCategory::EcuExtract);
1376
1377        // pnc vector length
1378        assert!(system.pnc_vector_length().is_none());
1379        system.set_pnc_vector_length(Some(42)).unwrap();
1380        assert_eq!(system.pnc_vector_length().unwrap(), 42);
1381        system.set_pnc_vector_length(None).unwrap();
1382        assert!(system.pnc_vector_length().is_none());
1383
1384        // pnc vector offset
1385        assert!(system.pnc_vector_offset().is_none());
1386        system.set_pnc_vector_offset(Some(42)).unwrap();
1387        assert_eq!(system.pnc_vector_offset().unwrap(), 42);
1388        system.set_pnc_vector_offset(None).unwrap();
1389        assert!(system.pnc_vector_offset().is_none());
1390    }
1391
1392    #[test]
1393    fn system_category() {
1394        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1395        let package = model.get_or_create_package("/SYSTEM").unwrap();
1396        System::new("System", &package, SystemCategory::AbstractSystemDescription).unwrap();
1397
1398        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1399        let package = model.get_or_create_package("/SYSTEM").unwrap();
1400        System::new("System", &package, SystemCategory::EcuExtract).unwrap();
1401
1402        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1403        let package = model.get_or_create_package("/SYSTEM").unwrap();
1404        System::new("System", &package, SystemCategory::EcuSystemDescription).unwrap();
1405
1406        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1407        let package = model.get_or_create_package("/SYSTEM").unwrap();
1408        System::new("System", &package, SystemCategory::RptSystem).unwrap();
1409
1410        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1411        let package = model.get_or_create_package("/SYSTEM").unwrap();
1412        System::new("System", &package, SystemCategory::SwClusterSystemDescription).unwrap();
1413
1414        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1415        let package = model.get_or_create_package("/SYSTEM").unwrap();
1416        System::new("System", &package, SystemCategory::SystemConstraints).unwrap();
1417
1418        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1419        let package = model.get_or_create_package("/SYSTEM").unwrap();
1420        System::new("System", &package, SystemCategory::SystemDescription).unwrap();
1421
1422        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1423        let package = model.get_or_create_package("/SYSTEM").unwrap();
1424        System::new("System", &package, SystemCategory::SystemExtract).unwrap();
1425    }
1426
1427    #[test]
1428    fn fibex_ref() {
1429        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1430        let package = model.get_or_create_package("/SYSTEM").unwrap();
1431        let system = package
1432            .create_system("System", SystemCategory::SystemDescription)
1433            .unwrap();
1434
1435        let el_elements = package
1436            .element()
1437            .get_or_create_sub_element(ElementName::Elements)
1438            .unwrap();
1439        let el_ecuinst = el_elements
1440            .create_named_sub_element(ElementName::EcuInstance, "Ecu")
1441            .unwrap();
1442
1443        let el_fibex_elements = system
1444            .element()
1445            .get_or_create_sub_element(ElementName::FibexElements)
1446            .unwrap();
1447        assert_eq!(el_fibex_elements.sub_elements().count(), 0);
1448
1449        // create one reference
1450        system.create_fibex_element_ref(&el_ecuinst).unwrap();
1451        assert_eq!(el_fibex_elements.sub_elements().count(), 1);
1452        // find the existing reference and do nothing
1453        system.create_fibex_element_ref(&el_ecuinst).unwrap();
1454        assert_eq!(el_fibex_elements.sub_elements().count(), 1);
1455    }
1456
1457    #[test]
1458    fn ecu_instance_iterator() {
1459        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1460        let package_1 = model.get_or_create_package("/SYSTEM").unwrap();
1461        let system = package_1
1462            .create_system("System", SystemCategory::SystemExtract)
1463            .unwrap();
1464        let package_2 = model.get_or_create_package("/ECU").unwrap();
1465        system.create_ecu_instance("Ecu_1", &package_2).unwrap();
1466        system.create_ecu_instance("Ecu_2", &package_2).unwrap();
1467        system.create_ecu_instance("Ecu_3", &package_2).unwrap();
1468
1469        let mut iter = system.ecu_instances();
1470        let item = iter.next().unwrap();
1471        assert_eq!(item.name().unwrap(), "Ecu_1");
1472        assert_eq!(model.get_element_by_path("/ECU/Ecu_1").unwrap(), *item.element());
1473        let item = iter.next().unwrap();
1474        assert_eq!(item.name().unwrap(), "Ecu_2");
1475        assert_eq!(model.get_element_by_path("/ECU/Ecu_2").unwrap(), *item.element());
1476        let item = iter.next().unwrap();
1477        assert_eq!(item.name().unwrap(), "Ecu_3");
1478        assert_eq!(model.get_element_by_path("/ECU/Ecu_3").unwrap(), *item.element());
1479
1480        assert!(iter.next().is_none());
1481        // after returning none the iterator continues to return none
1482        assert!(iter.next().is_none());
1483    }
1484
1485    #[test]
1486    fn cluster_iterator() {
1487        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1488        let package_1 = model.get_or_create_package("/SYSTEM").unwrap();
1489        let system = package_1
1490            .create_system("System", SystemCategory::SystemExtract)
1491            .unwrap();
1492        let package_2 = model.get_or_create_package("/Clusters").unwrap();
1493
1494        system.create_can_cluster("CanCluster", &package_2, None).unwrap();
1495
1496        let settings = FlexrayClusterSettings::new();
1497        system
1498            .create_flexray_cluster("FlexrayCluster", &package_2, &settings)
1499            .unwrap();
1500
1501        system.create_ethernet_cluster("EthernetCluster", &package_2).unwrap();
1502        system.create_lin_cluster("LinCluster", &package_2).unwrap();
1503
1504        // the ecu-instance is a fourth item in the FIBEX-ELEMENTS of the system, which should not be picked up by the iterator
1505        let package_3 = model.get_or_create_package("/ECU").unwrap();
1506        system.create_ecu_instance("Ecu_1", &package_3).unwrap();
1507
1508        assert_eq!(system.clusters().count(), 4);
1509    }
1510
1511    #[test]
1512    fn frames_iterator() {
1513        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1514        let package_1 = model.get_or_create_package("/SYSTEM").unwrap();
1515        let system = package_1
1516            .create_system("System", SystemCategory::SystemExtract)
1517            .unwrap();
1518        let package_2 = model.get_or_create_package("/Frames").unwrap();
1519
1520        system.create_can_frame("CanFrame", &package_2, 8).unwrap();
1521        system.create_flexray_frame("FlexrayFrame", &package_2, 8).unwrap();
1522        system
1523            .create_lin_event_triggered_frame("LinEventTriggeredFrame", &package_2, 8)
1524            .unwrap();
1525        system
1526            .create_lin_unconditional_frame("LinUnconditionalFrame", &package_2, 8)
1527            .unwrap();
1528        system
1529            .create_lin_sporadic_frame("LinSporadicFrame", &package_2, 8)
1530            .unwrap();
1531
1532        // the ecu-instance is a third item in the FIBEX-ELEMENTS of the system, which should not be picked up by the iterator
1533        let package_3 = model.get_or_create_package("/ECU").unwrap();
1534        system.create_ecu_instance("Ecu_1", &package_3).unwrap();
1535
1536        assert_eq!(system.frames().count(), 5);
1537    }
1538
1539    #[test]
1540    fn signals_iterator() {
1541        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1542        let package_1 = model.get_or_create_package("/SYSTEM").unwrap();
1543        let system = package_1
1544            .create_system("System", SystemCategory::SystemExtract)
1545            .unwrap();
1546        let package_2 = model.get_or_create_package("/Signals").unwrap();
1547
1548        let syssig1 = package_2.create_system_signal("syssig1").unwrap();
1549        system.create_isignal("Sig1", &package_2, 8, &syssig1, None).unwrap();
1550        let syssig2 = package_2.create_system_signal("syssig2").unwrap();
1551        system.create_isignal("Sig2", &package_2, 8, &syssig2, None).unwrap();
1552
1553        // the ecu-instance is a third item in the FIBEX-ELEMENTS of the system, which should not be picked up by the iterator
1554        let package_3 = model.get_or_create_package("/ECU").unwrap();
1555        system.create_ecu_instance("Ecu_1", &package_3).unwrap();
1556
1557        assert_eq!(system.isignals().count(), 2);
1558    }
1559
1560    #[test]
1561    fn isignal_groups_iterator() {
1562        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1563        let package_1 = model.get_or_create_package("/SYSTEM").unwrap();
1564        let system = package_1
1565            .create_system("System", SystemCategory::SystemExtract)
1566            .unwrap();
1567        let package_2 = model.get_or_create_package("/SignalGroups").unwrap();
1568
1569        let sysgroup1 = package_2.create_system_signal_group("sysgroup1").unwrap();
1570        system
1571            .create_isignal_group("siggroup1", &package_2, &sysgroup1)
1572            .unwrap();
1573        let sysgroup2 = package_2.create_system_signal_group("sysgroup2").unwrap();
1574        system
1575            .create_isignal_group("siggroup2", &package_2, &sysgroup2)
1576            .unwrap();
1577
1578        // the ecu-instance is a third item in the FIBEX-ELEMENTS of the system, which should not be picked up by the iterator
1579        let package_3 = model.get_or_create_package("/ECU").unwrap();
1580        system.create_ecu_instance("Ecu_1", &package_3).unwrap();
1581
1582        assert_eq!(system.isignal_groups().count(), 2);
1583    }
1584
1585    #[test]
1586    fn pdus_iterator() {
1587        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1588        let package_1 = model.get_or_create_package("/SYSTEM").unwrap();
1589        let system = package_1
1590            .create_system("System", SystemCategory::SystemExtract)
1591            .unwrap();
1592        let package_2 = model.get_or_create_package("/Pdus").unwrap();
1593
1594        system
1595            .create_dcm_ipdu("DcmIpdu", &package_2, 8, DiagPduType::DiagRequest)
1596            .unwrap();
1597        system
1598            .create_general_purpose_pdu("GeneralPurposePdu", &package_2, 8, GeneralPurposePduCategory::DoIp)
1599            .unwrap();
1600        system
1601            .create_general_purpose_ipdu("GeneralPurposeIpdu", &package_2, 8, GeneralPurposeIPduCategory::Xcp)
1602            .unwrap();
1603        system
1604            .create_container_ipdu(
1605                "ContainerIpdu",
1606                &package_2,
1607                8,
1608                ContainerIPduHeaderType::NoHeader,
1609                RxAcceptContainedIPdu::AcceptAll,
1610            )
1611            .unwrap();
1612        system
1613            .create_secured_ipdu("SecuredIpdu", &package_2, 8, &SecureCommunicationProps::default())
1614            .unwrap();
1615        system
1616            .create_multiplexed_ipdu("MultiplexedIpdu", &package_2, 8)
1617            .unwrap();
1618
1619        // the EcuInstance is a seventh item in the FIBEX-ELEMENTS of the system, which should not be picked up by the iterator
1620        let package_3 = model.get_or_create_package("/ECU").unwrap();
1621        system.create_ecu_instance("Ecu_1", &package_3).unwrap();
1622
1623        assert_eq!(system.pdus().count(), 6);
1624    }
1625
1626    #[test]
1627    fn nm_config() {
1628        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1629        let sys_package = model.get_or_create_package("/SYSTEM").unwrap();
1630        let system = sys_package
1631            .create_system("System", SystemCategory::SystemExtract)
1632            .unwrap();
1633
1634        assert!(system.nm_config().is_none());
1635
1636        let nm_package = model.get_or_create_package("/Nm").unwrap();
1637        let nm_config = system.create_nm_config("NmConfig", &nm_package).unwrap();
1638
1639        assert!(system.nm_config().is_some());
1640        assert_eq!(system.nm_config().unwrap(), nm_config);
1641    }
1642
1643    #[test]
1644    fn sw_mapping() {
1645        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1646        let package_1 = model.get_or_create_package("/SYSTEM").unwrap();
1647        let system = package_1
1648            .create_system("System", SystemCategory::SystemExtract)
1649            .unwrap();
1650        let package_2 = model.get_or_create_package("/SWC").unwrap();
1651        let package_3 = model.get_or_create_package("/ECU").unwrap();
1652
1653        let root_composition = CompositionSwComponentType::new("RootComposition", &package_2).unwrap();
1654        let context_composition = CompositionSwComponentType::new("ContextComposition", &package_2).unwrap();
1655        let ecu_composition = CompositionSwComponentType::new("EcuComposition", &package_2).unwrap();
1656        let _root_proto = system
1657            .set_root_sw_composition("RootComposition", &root_composition)
1658            .unwrap();
1659        assert_eq!(system.root_sw_composition().unwrap(), _root_proto);
1660
1661        let context_proto = root_composition
1662            .create_component("ContextComposition", &context_composition.clone())
1663            .unwrap();
1664        let ecu_proto = context_composition
1665            .create_component("EcuComposition", &ecu_composition)
1666            .unwrap();
1667        let ecu = system.create_ecu_instance("Ecu", &package_3).unwrap();
1668
1669        let mapping = system.get_or_create_mapping("Mapping").unwrap();
1670        mapping.map_swc_to_ecu("SwcToEcu1", &context_proto, &ecu).unwrap();
1671        let swc_to_ecu = mapping.map_swc_to_ecu("SwcToEcu2", &ecu_proto, &ecu).unwrap();
1672
1673        assert_eq!(swc_to_ecu.target_component().unwrap(), ecu_proto);
1674        assert_eq!(swc_to_ecu.ecu_instance().unwrap(), ecu);
1675
1676        // println!("{}", _file.serialize().unwrap());
1677    }
1678}