autosar_data_abstraction/software_component/interface/
clientserver.rs1use crate::{
2 AbstractionElement, ArPackage, AutosarAbstractionError, Element, EnumItem, IdentifiableAbstractionElement,
3 abstraction_element,
4 datatype::{self, AbstractAutosarDataType},
5 software_component::AbstractPortInterface,
6};
7use autosar_data::ElementName;
8use datatype::AutosarDataType;
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
16pub struct ClientServerInterface(pub(crate) Element);
17abstraction_element!(ClientServerInterface, ClientServerInterface);
18impl IdentifiableAbstractionElement for ClientServerInterface {}
19impl AbstractPortInterface for ClientServerInterface {}
20
21impl ClientServerInterface {
22 pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
24 let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
25 let client_server_interface = elements.create_named_sub_element(ElementName::ClientServerInterface, name)?;
26
27 Ok(Self(client_server_interface))
28 }
29
30 pub fn create_possible_error(
32 &self,
33 name: &str,
34 error_code: u64,
35 ) -> Result<ApplicationError, AutosarAbstractionError> {
36 let possible_errors = self.element().get_or_create_sub_element(ElementName::PossibleErrors)?;
37 ApplicationError::new(name, error_code, &possible_errors)
38 }
39
40 pub fn create_operation(&self, name: &str) -> Result<ClientServerOperation, AutosarAbstractionError> {
42 let operations = self.element().get_or_create_sub_element(ElementName::Operations)?;
43 ClientServerOperation::new(name, &operations)
44 }
45
46 pub fn operations(&self) -> impl Iterator<Item = ClientServerOperation> + Send + 'static {
48 self.element()
49 .get_sub_element(ElementName::Operations)
50 .into_iter()
51 .flat_map(|operations| operations.sub_elements())
52 .filter_map(|elem| ClientServerOperation::try_from(elem).ok())
53 }
54
55 pub fn possible_errors(&self) -> impl Iterator<Item = ApplicationError> + Send + 'static {
57 self.element()
58 .get_sub_element(ElementName::PossibleErrors)
59 .into_iter()
60 .flat_map(|errors| errors.sub_elements())
61 .filter_map(|elem| ApplicationError::try_from(elem).ok())
62 }
63}
64
65#[derive(Debug, Clone, PartialEq, Eq, Hash)]
69pub struct ApplicationError(Element);
70abstraction_element!(ApplicationError, ApplicationError);
71impl IdentifiableAbstractionElement for ApplicationError {}
72
73impl ApplicationError {
74 fn new(name: &str, error_code: u64, parent_element: &Element) -> Result<Self, AutosarAbstractionError> {
76 let application_error = parent_element.create_named_sub_element(ElementName::ApplicationError, name)?;
77 let application_error = Self(application_error);
78 application_error.set_error_code(error_code)?;
79
80 Ok(application_error)
81 }
82
83 pub fn set_error_code(&self, error_code: u64) -> Result<(), AutosarAbstractionError> {
85 self.element()
86 .get_or_create_sub_element(ElementName::ErrorCode)?
87 .set_character_data(error_code)?;
88 Ok(())
89 }
90
91 #[must_use]
93 pub fn error_code(&self) -> Option<u64> {
94 self.element()
95 .get_sub_element(ElementName::ErrorCode)?
96 .character_data()?
97 .parse_integer()
98 }
99}
100
101#[derive(Debug, Clone, PartialEq, Eq, Hash)]
105pub struct ClientServerOperation(Element);
106abstraction_element!(ClientServerOperation, ClientServerOperation);
107impl IdentifiableAbstractionElement for ClientServerOperation {}
108
109impl ClientServerOperation {
110 fn new(name: &str, parent_element: &Element) -> Result<Self, AutosarAbstractionError> {
112 let operation = parent_element.create_named_sub_element(ElementName::ClientServerOperation, name)?;
113 Ok(Self(operation))
114 }
115
116 pub fn create_argument<T: AbstractAutosarDataType>(
118 &self,
119 name: &str,
120 data_type: &T,
121 direction: ArgumentDirection,
122 ) -> Result<ArgumentDataPrototype, AutosarAbstractionError> {
123 let arguments = self.element().get_or_create_sub_element(ElementName::Arguments)?;
124 ArgumentDataPrototype::new(name, &arguments, data_type, direction)
125 }
126
127 pub fn arguments(&self) -> impl Iterator<Item = ArgumentDataPrototype> + Send + 'static {
129 self.element()
130 .get_sub_element(ElementName::Arguments)
131 .into_iter()
132 .flat_map(|arguments| arguments.sub_elements())
133 .filter_map(|elem| ArgumentDataPrototype::try_from(elem).ok())
134 }
135
136 pub fn add_possible_error(&self, error: &ApplicationError) -> Result<(), AutosarAbstractionError> {
138 if self.element().named_parent()? != error.element().named_parent()? {
139 return Err(AutosarAbstractionError::InvalidParameter(
140 "Error and operation must be in the same ClientServerInterface".to_string(),
141 ));
142 }
143
144 let possible_errors = self
145 .element()
146 .get_or_create_sub_element(ElementName::PossibleErrorRefs)?;
147 possible_errors
148 .create_sub_element(ElementName::PossibleErrorRef)?
149 .set_reference_target(error.element())?;
150 Ok(())
151 }
152
153 pub fn possible_errors(&self) -> impl Iterator<Item = ApplicationError> + Send + 'static {
155 self.element()
156 .get_sub_element(ElementName::PossibleErrorRefs)
157 .into_iter()
158 .flat_map(|errors| errors.sub_elements())
159 .filter_map(|refelem| {
160 refelem
161 .get_reference_target()
162 .ok()
163 .and_then(|elem| ApplicationError::try_from(elem).ok())
164 })
165 }
166}
167
168#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
176pub enum ArgumentDirection {
177 In,
179 Out,
181 InOut,
183}
184
185impl TryFrom<EnumItem> for ArgumentDirection {
186 type Error = AutosarAbstractionError;
187
188 fn try_from(item: EnumItem) -> Result<Self, Self::Error> {
189 match item {
190 EnumItem::In => Ok(ArgumentDirection::In),
191 EnumItem::Out => Ok(ArgumentDirection::Out),
192 EnumItem::Inout => Ok(ArgumentDirection::InOut),
193 _ => Err(AutosarAbstractionError::ValueConversionError {
194 value: item.to_string(),
195 dest: "ArgumentDirection".to_string(),
196 }),
197 }
198 }
199}
200
201impl From<ArgumentDirection> for EnumItem {
202 fn from(direction: ArgumentDirection) -> Self {
203 match direction {
204 ArgumentDirection::In => EnumItem::In,
205 ArgumentDirection::Out => EnumItem::Out,
206 ArgumentDirection::InOut => EnumItem::Inout,
207 }
208 }
209}
210
211#[derive(Debug, Clone, PartialEq, Eq, Hash)]
215pub struct ArgumentDataPrototype(Element);
216abstraction_element!(ArgumentDataPrototype, ArgumentDataPrototype);
217impl IdentifiableAbstractionElement for ArgumentDataPrototype {}
218
219impl ArgumentDataPrototype {
220 fn new<T: AbstractAutosarDataType>(
222 name: &str,
223 parent_element: &Element,
224 data_type: &T,
225 direction: ArgumentDirection,
226 ) -> Result<Self, AutosarAbstractionError> {
227 let argument = parent_element.create_named_sub_element(ElementName::ArgumentDataPrototype, name)?;
228 let argument = Self(argument);
229 argument.set_data_type(data_type)?;
230 argument.set_direction(direction)?;
231
232 Ok(argument)
233 }
234
235 pub fn set_data_type<T: AbstractAutosarDataType>(&self, data_type: &T) -> Result<(), AutosarAbstractionError> {
237 self.element()
238 .get_or_create_sub_element(ElementName::TypeTref)?
239 .set_reference_target(data_type.element())?;
240 Ok(())
241 }
242
243 #[must_use]
245 pub fn data_type(&self) -> Option<AutosarDataType> {
246 let data_type_elem = self
247 .element()
248 .get_sub_element(ElementName::TypeTref)?
249 .get_reference_target()
250 .ok()?;
251 AutosarDataType::try_from(data_type_elem).ok()
252 }
253
254 pub fn set_direction(&self, direction: ArgumentDirection) -> Result<(), AutosarAbstractionError> {
256 self.element()
257 .get_or_create_sub_element(ElementName::Direction)?
258 .set_character_data::<EnumItem>(direction.into())?;
259 Ok(())
260 }
261
262 #[must_use]
264 pub fn direction(&self) -> Option<ArgumentDirection> {
265 let value = self
266 .element()
267 .get_sub_element(ElementName::Direction)?
268 .character_data()?
269 .enum_value()?;
270
271 ArgumentDirection::try_from(value).ok()
272 }
273}
274
275#[cfg(test)]
278mod test {
279 use super::*;
280 use crate::AutosarModelAbstraction;
281 use autosar_data::AutosarVersion;
282 use datatype::{BaseTypeEncoding, ImplementationDataTypeSettings};
283
284 #[test]
285 fn test_client_server_interface() {
286 let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
287 let package = model.get_or_create_package("/package").unwrap();
288 let client_server_interface = ClientServerInterface::new("TestInterface", &package).unwrap();
289
290 assert_eq!(client_server_interface.name().unwrap(), "TestInterface");
291 assert_eq!(client_server_interface.operations().count(), 0);
292 assert_eq!(client_server_interface.possible_errors().count(), 0);
293
294 let error = client_server_interface.create_possible_error("TestError", 42).unwrap();
295 assert_eq!(client_server_interface.possible_errors().count(), 1);
296 assert_eq!(error.name().unwrap(), "TestError");
297 assert_eq!(error.error_code().unwrap(), 42);
298
299 let operation = client_server_interface.create_operation("TestOperation").unwrap();
300 assert_eq!(client_server_interface.operations().count(), 1);
301 assert_eq!(operation.name().unwrap(), "TestOperation");
302 assert_eq!(operation.arguments().count(), 0);
303
304 operation.add_possible_error(&error).unwrap();
305 assert_eq!(operation.possible_errors().count(), 1);
306
307 let base_type = package
308 .create_sw_base_type("base", 32, BaseTypeEncoding::None, None, None, None)
309 .unwrap();
310 let impl_settings = ImplementationDataTypeSettings::Value {
311 name: "ImplementationValue".to_string(),
312 base_type,
313 compu_method: None,
314 data_constraint: None,
315 };
316 let datatype = package.create_implementation_data_type(&impl_settings).unwrap();
317 let argument = operation
318 .create_argument("TestArgument", &datatype, ArgumentDirection::In)
319 .unwrap();
320 assert_eq!(argument.name().unwrap(), "TestArgument");
321 assert_eq!(argument.data_type().unwrap().name().unwrap(), "ImplementationValue");
322 assert_eq!(argument.direction().unwrap(), ArgumentDirection::In);
323 assert_eq!(operation.arguments().count(), 1);
324
325 client_server_interface.set_is_service(Some(true)).unwrap();
326 assert!(client_server_interface.is_service().unwrap());
327 client_server_interface.set_is_service(Some(false)).unwrap();
328 assert!(!client_server_interface.is_service().unwrap());
329 client_server_interface.set_is_service(None).unwrap();
330 assert_eq!(client_server_interface.is_service(), None);
331 }
332}