autosar_data_abstraction/software_component/interface/
clientserver.rs1use crate::{
2 AbstractionElement, ArPackage, AutosarAbstractionError, Element, EnumItem, IdentifiableAbstractionElement,
3 abstraction_element,
4 datatype::{self, AbstractAutosarDataType},
5 get_reference_parents,
6 software_component::{AbstractPortInterface, OperationInvokedEvent, PortPrototype},
7};
8use autosar_data::ElementName;
9use datatype::AutosarDataType;
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
17pub struct ClientServerInterface(pub(crate) Element);
18abstraction_element!(ClientServerInterface, ClientServerInterface);
19impl IdentifiableAbstractionElement for ClientServerInterface {}
20impl AbstractPortInterface for ClientServerInterface {}
21
22impl ClientServerInterface {
23 pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
25 let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
26 let client_server_interface = elements.create_named_sub_element(ElementName::ClientServerInterface, name)?;
27
28 Ok(Self(client_server_interface))
29 }
30
31 pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
33 for operation in self.operations() {
34 operation.remove(true)?;
35 }
36
37 let ref_parents = get_reference_parents(self.element())?;
38
39 AbstractionElement::remove(self, deep)?;
40
41 for (named_parent, _parent) in ref_parents {
42 match named_parent.element_name() {
43 ElementName::PPortPrototype | ElementName::RPortPrototype | ElementName::PrPortPrototype => {
44 if let Ok(port) = PortPrototype::try_from(named_parent) {
45 port.remove(deep)?;
46 }
47 }
48 _ => {}
49 }
50 }
51
52 Ok(())
53 }
54
55 pub fn create_possible_error(
57 &self,
58 name: &str,
59 error_code: u64,
60 ) -> Result<ApplicationError, AutosarAbstractionError> {
61 let possible_errors = self.element().get_or_create_sub_element(ElementName::PossibleErrors)?;
62 ApplicationError::new(name, error_code, &possible_errors)
63 }
64
65 pub fn create_operation(&self, name: &str) -> Result<ClientServerOperation, AutosarAbstractionError> {
67 let operations = self.element().get_or_create_sub_element(ElementName::Operations)?;
68 ClientServerOperation::new(name, &operations)
69 }
70
71 pub fn operations(&self) -> impl Iterator<Item = ClientServerOperation> + Send + use<> {
73 self.element()
74 .get_sub_element(ElementName::Operations)
75 .into_iter()
76 .flat_map(|operations| operations.sub_elements())
77 .filter_map(|elem| ClientServerOperation::try_from(elem).ok())
78 }
79
80 pub fn possible_errors(&self) -> impl Iterator<Item = ApplicationError> + Send + use<> {
82 self.element()
83 .get_sub_element(ElementName::PossibleErrors)
84 .into_iter()
85 .flat_map(|errors| errors.sub_elements())
86 .filter_map(|elem| ApplicationError::try_from(elem).ok())
87 }
88}
89
90#[derive(Debug, Clone, PartialEq, Eq, Hash)]
94pub struct ApplicationError(Element);
95abstraction_element!(ApplicationError, ApplicationError);
96impl IdentifiableAbstractionElement for ApplicationError {}
97
98impl ApplicationError {
99 fn new(name: &str, error_code: u64, parent_element: &Element) -> Result<Self, AutosarAbstractionError> {
101 let application_error = parent_element.create_named_sub_element(ElementName::ApplicationError, name)?;
102 let application_error = Self(application_error);
103 application_error.set_error_code(error_code)?;
104
105 Ok(application_error)
106 }
107
108 pub fn set_error_code(&self, error_code: u64) -> Result<(), AutosarAbstractionError> {
110 self.element()
111 .get_or_create_sub_element(ElementName::ErrorCode)?
112 .set_character_data(error_code)?;
113 Ok(())
114 }
115
116 #[must_use]
118 pub fn error_code(&self) -> Option<u64> {
119 self.element()
120 .get_sub_element(ElementName::ErrorCode)?
121 .character_data()?
122 .parse_integer()
123 }
124}
125
126#[derive(Debug, Clone, PartialEq, Eq, Hash)]
130pub struct ClientServerOperation(Element);
131abstraction_element!(ClientServerOperation, ClientServerOperation);
132impl IdentifiableAbstractionElement for ClientServerOperation {}
133
134impl ClientServerOperation {
135 fn new(name: &str, parent_element: &Element) -> Result<Self, AutosarAbstractionError> {
137 let operation = parent_element.create_named_sub_element(ElementName::ClientServerOperation, name)?;
138 Ok(Self(operation))
139 }
140
141 pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
143 let ref_parents = get_reference_parents(self.element())?;
144 AbstractionElement::remove(self, deep)?;
145
146 for (named_parent, _parent) in ref_parents {
147 if named_parent.element_name() == ElementName::OperationInvokedEvent
148 && let Ok(event) = OperationInvokedEvent::try_from(named_parent)
149 {
150 event.remove(deep)?;
151 }
152 }
153
154 Ok(())
155 }
156
157 pub fn create_argument<T: AbstractAutosarDataType>(
159 &self,
160 name: &str,
161 data_type: &T,
162 direction: ArgumentDirection,
163 ) -> Result<ArgumentDataPrototype, AutosarAbstractionError> {
164 let arguments = self.element().get_or_create_sub_element(ElementName::Arguments)?;
165 ArgumentDataPrototype::new(name, &arguments, data_type, direction)
166 }
167
168 pub fn arguments(&self) -> impl Iterator<Item = ArgumentDataPrototype> + Send + use<> {
170 self.element()
171 .get_sub_element(ElementName::Arguments)
172 .into_iter()
173 .flat_map(|arguments| arguments.sub_elements())
174 .filter_map(|elem| ArgumentDataPrototype::try_from(elem).ok())
175 }
176
177 pub fn add_possible_error(&self, error: &ApplicationError) -> Result<(), AutosarAbstractionError> {
179 if self.element().named_parent()? != error.element().named_parent()? {
180 return Err(AutosarAbstractionError::InvalidParameter(
181 "Error and operation must be in the same ClientServerInterface".to_string(),
182 ));
183 }
184
185 let possible_errors = self
186 .element()
187 .get_or_create_sub_element(ElementName::PossibleErrorRefs)?;
188 possible_errors
189 .create_sub_element(ElementName::PossibleErrorRef)?
190 .set_reference_target(error.element())?;
191 Ok(())
192 }
193
194 pub fn possible_errors(&self) -> impl Iterator<Item = ApplicationError> + Send + use<> {
196 self.element()
197 .get_sub_element(ElementName::PossibleErrorRefs)
198 .into_iter()
199 .flat_map(|errors| errors.sub_elements())
200 .filter_map(|refelem| {
201 refelem
202 .get_reference_target()
203 .ok()
204 .and_then(|elem| ApplicationError::try_from(elem).ok())
205 })
206 }
207}
208
209#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
217pub enum ArgumentDirection {
218 In,
220 Out,
222 InOut,
224}
225
226impl TryFrom<EnumItem> for ArgumentDirection {
227 type Error = AutosarAbstractionError;
228
229 fn try_from(item: EnumItem) -> Result<Self, Self::Error> {
230 match item {
231 EnumItem::In => Ok(ArgumentDirection::In),
232 EnumItem::Out => Ok(ArgumentDirection::Out),
233 EnumItem::Inout => Ok(ArgumentDirection::InOut),
234 _ => Err(AutosarAbstractionError::ValueConversionError {
235 value: item.to_string(),
236 dest: "ArgumentDirection".to_string(),
237 }),
238 }
239 }
240}
241
242impl From<ArgumentDirection> for EnumItem {
243 fn from(direction: ArgumentDirection) -> Self {
244 match direction {
245 ArgumentDirection::In => EnumItem::In,
246 ArgumentDirection::Out => EnumItem::Out,
247 ArgumentDirection::InOut => EnumItem::Inout,
248 }
249 }
250}
251
252#[derive(Debug, Clone, PartialEq, Eq, Hash)]
256pub struct ArgumentDataPrototype(Element);
257abstraction_element!(ArgumentDataPrototype, ArgumentDataPrototype);
258impl IdentifiableAbstractionElement for ArgumentDataPrototype {}
259
260impl ArgumentDataPrototype {
261 fn new<T: AbstractAutosarDataType>(
263 name: &str,
264 parent_element: &Element,
265 data_type: &T,
266 direction: ArgumentDirection,
267 ) -> Result<Self, AutosarAbstractionError> {
268 let argument = parent_element.create_named_sub_element(ElementName::ArgumentDataPrototype, name)?;
269 let argument = Self(argument);
270 argument.set_data_type(data_type)?;
271 argument.set_direction(direction)?;
272
273 Ok(argument)
274 }
275
276 pub fn set_data_type<T: AbstractAutosarDataType>(&self, data_type: &T) -> Result<(), AutosarAbstractionError> {
278 self.element()
279 .get_or_create_sub_element(ElementName::TypeTref)?
280 .set_reference_target(data_type.element())?;
281 Ok(())
282 }
283
284 #[must_use]
286 pub fn data_type(&self) -> Option<AutosarDataType> {
287 let data_type_elem = self
288 .element()
289 .get_sub_element(ElementName::TypeTref)?
290 .get_reference_target()
291 .ok()?;
292 AutosarDataType::try_from(data_type_elem).ok()
293 }
294
295 pub fn set_direction(&self, direction: ArgumentDirection) -> Result<(), AutosarAbstractionError> {
297 self.element()
298 .get_or_create_sub_element(ElementName::Direction)?
299 .set_character_data::<EnumItem>(direction.into())?;
300 Ok(())
301 }
302
303 #[must_use]
305 pub fn direction(&self) -> Option<ArgumentDirection> {
306 let value = self
307 .element()
308 .get_sub_element(ElementName::Direction)?
309 .character_data()?
310 .enum_value()?;
311
312 ArgumentDirection::try_from(value).ok()
313 }
314}
315
316#[cfg(test)]
319mod test {
320 use super::*;
321 use crate::{AutosarModelAbstraction, software_component::AbstractSwComponentType};
322 use autosar_data::AutosarVersion;
323 use datatype::{BaseTypeEncoding, ImplementationDataTypeSettings};
324
325 #[test]
326 fn test_client_server_interface() {
327 let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
328 let package = model.get_or_create_package("/package").unwrap();
329 let client_server_interface = ClientServerInterface::new("TestInterface", &package).unwrap();
330
331 assert_eq!(client_server_interface.name().unwrap(), "TestInterface");
332 assert_eq!(client_server_interface.operations().count(), 0);
333 assert_eq!(client_server_interface.possible_errors().count(), 0);
334
335 let error = client_server_interface.create_possible_error("TestError", 42).unwrap();
336 assert_eq!(client_server_interface.possible_errors().count(), 1);
337 assert_eq!(error.name().unwrap(), "TestError");
338 assert_eq!(error.error_code().unwrap(), 42);
339
340 let operation = client_server_interface.create_operation("TestOperation").unwrap();
341 assert_eq!(client_server_interface.operations().count(), 1);
342 assert_eq!(operation.name().unwrap(), "TestOperation");
343 assert_eq!(operation.arguments().count(), 0);
344
345 operation.add_possible_error(&error).unwrap();
346 assert_eq!(operation.possible_errors().count(), 1);
347
348 let base_type = package
349 .create_sw_base_type("base", 32, BaseTypeEncoding::None, None, None, None)
350 .unwrap();
351 let impl_settings = ImplementationDataTypeSettings::Value {
352 name: "ImplementationValue".to_string(),
353 base_type,
354 compu_method: None,
355 data_constraint: None,
356 };
357 let datatype = package.create_implementation_data_type(&impl_settings).unwrap();
358 let argument = operation
359 .create_argument("TestArgument", &datatype, ArgumentDirection::In)
360 .unwrap();
361 assert_eq!(argument.name().unwrap(), "TestArgument");
362 assert_eq!(argument.data_type().unwrap().name().unwrap(), "ImplementationValue");
363 assert_eq!(argument.direction().unwrap(), ArgumentDirection::In);
364 assert_eq!(operation.arguments().count(), 1);
365
366 client_server_interface.set_is_service(Some(true)).unwrap();
367 assert!(client_server_interface.is_service().unwrap());
368 client_server_interface.set_is_service(Some(false)).unwrap();
369 assert!(!client_server_interface.is_service().unwrap());
370 client_server_interface.set_is_service(None).unwrap();
371 assert_eq!(client_server_interface.is_service(), None);
372 }
373
374 #[test]
375 fn remove() {
376 let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
377 let package = model.get_or_create_package("/package").unwrap();
378 let client_server_interface = ClientServerInterface::new("TestInterface", &package).unwrap();
379
380 let composition_type = package.create_composition_sw_component_type("comp_parent").unwrap();
381 let _composition_r_port = composition_type
382 .create_r_port("port_r", &client_server_interface)
383 .unwrap();
384
385 assert_eq!(composition_type.ports().count(), 1);
386 client_server_interface.remove(true).unwrap();
387 assert_eq!(composition_type.ports().count(), 0);
388 }
389}