autosar_data_abstraction/
lib.rs1#![warn(missing_docs)]
80
81use std::path::Path;
82
83use autosar_data::{ArxmlFile, AutosarDataError, AutosarModel, AutosarVersion, Element, ElementName, EnumItem};
84use thiserror::Error;
85
86pub mod communication;
88pub mod datatype;
89pub mod ecu_configuration;
90pub mod software_component;
91
92mod arpackage;
94mod ecuinstance;
95mod system;
96
97pub use arpackage::ArPackage;
99pub use ecuinstance::*;
100pub use system::*;
101
102#[derive(Error, Debug)]
104#[non_exhaustive]
105pub enum AutosarAbstractionError {
106 #[error("conversion error: could not convert {} to {}", .element.element_name(), dest)]
108 ConversionError {
109 element: Element,
111 dest: String,
113 },
114
115 #[error("value conversion error: could not convert {} to {}", .value, .dest)]
117 ValueConversionError {
118 value: String,
120 dest: String,
122 },
123
124 #[error("model error: {}", .0)]
127 ModelError(AutosarDataError),
128
129 #[error("invalid path: {}", .0)]
131 InvalidPath(String),
132
133 #[error("the item already exists")]
135 ItemAlreadyExists,
136
137 #[error("invalid parameter: {}", .0)]
139 InvalidParameter(String),
140}
141
142impl From<AutosarDataError> for AutosarAbstractionError {
143 fn from(err: AutosarDataError) -> Self {
144 AutosarAbstractionError::ModelError(err)
145 }
146}
147
148pub trait AbstractionElement: Clone + PartialEq + TryFrom<autosar_data::Element> {
152 #[must_use]
154 fn element(&self) -> ∈
155
156 }
160
161pub trait IdentifiableAbstractionElement: AbstractionElement {
163 #[must_use]
165 fn name(&self) -> Option<String> {
166 self.element().item_name()
167 }
168
169 fn set_name(&self, name: &str) -> Result<(), AutosarAbstractionError> {
171 self.element().set_item_name(name)?;
172 Ok(())
173 }
174}
175
176macro_rules! abstraction_element {
177 ($name: ident, $base_elem: ident) => {
178 impl TryFrom<autosar_data::Element> for $name {
179 type Error = AutosarAbstractionError;
180
181 fn try_from(element: autosar_data::Element) -> Result<Self, Self::Error> {
182 if element.element_name() == autosar_data::ElementName::$base_elem {
183 Ok($name(element))
184 } else {
185 Err(AutosarAbstractionError::ConversionError {
186 element,
187 dest: stringify!($name).to_string(),
188 })
189 }
190 }
191 }
192
193 impl AbstractionElement for $name {
194 fn element(&self) -> &autosar_data::Element {
195 &self.0
196 }
197 }
198
199 impl From<$name> for autosar_data::Element {
200 fn from(val: $name) -> Self {
201 val.0
202 }
203 }
204 };
205}
206
207pub(crate) use abstraction_element;
208
209#[derive(Debug, Clone, PartialEq, Eq)]
213pub struct AutosarModelAbstraction(AutosarModel);
214
215impl AutosarModelAbstraction {
216 #[must_use]
218 pub fn new(model: AutosarModel) -> Self {
219 Self(model)
220 }
221
222 pub fn create<P: AsRef<Path>>(file_name: P, version: AutosarVersion) -> Self {
227 let model = AutosarModel::new();
228 model.create_file(file_name, version).unwrap();
231 Self(model)
232 }
233
234 pub fn from_file<P: AsRef<Path>>(file_name: P) -> Result<Self, AutosarAbstractionError> {
236 let model = AutosarModel::new();
237 model.load_file(file_name, true)?;
238 Ok(Self(model))
239 }
240
241 #[must_use]
243 pub fn model(&self) -> &AutosarModel {
244 &self.0
245 }
246
247 #[must_use]
249 pub fn root_element(&self) -> Element {
250 self.0.root_element()
251 }
252
253 pub fn packages(&self) -> impl Iterator<Item = ArPackage> + Send + 'static {
255 self.0
256 .root_element()
257 .get_sub_element(ElementName::ArPackages)
258 .into_iter()
259 .flat_map(|elem| elem.sub_elements())
260 .filter_map(|elem| ArPackage::try_from(elem).ok())
261 }
262
263 pub fn get_or_create_package(&self, path: &str) -> Result<ArPackage, AutosarAbstractionError> {
265 ArPackage::get_or_create(&self.0, path)
266 }
267
268 pub fn create_file(&self, file_name: &str, version: AutosarVersion) -> Result<ArxmlFile, AutosarAbstractionError> {
270 let arxml_file = self.0.create_file(file_name, version)?;
271 Ok(arxml_file)
272 }
273
274 pub fn load_file<P: AsRef<Path>>(
276 &self,
277 file_name: P,
278 strict: bool,
279 ) -> Result<(ArxmlFile, Vec<AutosarDataError>), AutosarAbstractionError> {
280 let value = self.0.load_file(file_name, strict)?;
281 Ok(value)
282 }
283
284 pub fn files(&self) -> impl Iterator<Item = ArxmlFile> + Send + 'static {
286 self.0.files()
287 }
288
289 pub fn write(&self) -> Result<(), AutosarAbstractionError> {
291 self.0.write()?;
292 Ok(())
293 }
294
295 #[must_use]
297 pub fn get_element_by_path(&self, path: &str) -> Option<Element> {
298 self.0.get_element_by_path(path)
299 }
300
301 #[must_use]
318 pub fn find_system(&self) -> Option<System> {
319 System::find(&self.0)
320 }
321}
322
323#[derive(Debug, Clone, Copy, PartialEq, Eq)]
327pub enum ByteOrder {
328 MostSignificantByteFirst,
330 MostSignificantByteLast,
332 Opaque,
334}
335
336impl TryFrom<EnumItem> for ByteOrder {
337 type Error = AutosarAbstractionError;
338
339 fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
340 match value {
341 EnumItem::MostSignificantByteFirst => Ok(ByteOrder::MostSignificantByteFirst),
342 EnumItem::MostSignificantByteLast => Ok(ByteOrder::MostSignificantByteLast),
343 EnumItem::Opaque => Ok(ByteOrder::Opaque),
344 _ => Err(AutosarAbstractionError::ValueConversionError {
345 value: value.to_string(),
346 dest: "ByteOrder".to_string(),
347 }),
348 }
349 }
350}
351
352impl From<ByteOrder> for EnumItem {
353 fn from(value: ByteOrder) -> Self {
354 match value {
355 ByteOrder::MostSignificantByteFirst => EnumItem::MostSignificantByteFirst,
356 ByteOrder::MostSignificantByteLast => EnumItem::MostSignificantByteLast,
357 ByteOrder::Opaque => EnumItem::Opaque,
358 }
359 }
360}
361
362pub(crate) fn make_unique_name(model: &AutosarModel, base_path: &str, initial_name: &str) -> String {
365 let mut full_path = format!("{base_path}/{initial_name}");
366 let mut name = initial_name.to_string();
367 let mut counter = 0;
368 while model.get_element_by_path(&full_path).is_some() {
369 counter += 1;
370 name = format!("{initial_name}_{counter}");
371 full_path = format!("{base_path}/{name}");
372 }
373
374 name
375}
376
377#[cfg(test)]
380mod test {
381 use super::*;
382 use autosar_data::AutosarModel;
383
384 #[test]
385 fn create_model() {
386 let raw_model = AutosarModel::new();
388 let model = AutosarModelAbstraction::new(raw_model.clone());
389 assert_eq!(model.model(), &raw_model);
390
391 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00049);
393 let root = model.root_element();
394 assert_eq!(root.element_name(), ElementName::Autosar);
395 }
396
397 #[test]
398 fn create_model_from_file() {
399 let tempdir = tempfile::tempdir().unwrap();
400 let filename = tempdir.path().join("test.arxml");
401
402 let model1 = AutosarModelAbstraction::create(filename.clone(), AutosarVersion::LATEST);
404 model1.write().unwrap();
405
406 let model2 = AutosarModelAbstraction::from_file(filename).unwrap();
408 let root = model2.root_element();
409 assert_eq!(root.element_name(), ElementName::Autosar);
410 }
411
412 #[test]
413 fn model_files() {
414 let model = AutosarModelAbstraction::create("file1.arxml", AutosarVersion::Autosar_00049);
415 let file = model.create_file("file2.arxml", AutosarVersion::Autosar_00049).unwrap();
416 let files: Vec<_> = model.files().collect();
417 assert_eq!(files.len(), 2);
418 assert_eq!(files[1], file);
419 }
420
421 #[test]
422 fn model_load_file() {
423 let tempdir = tempfile::tempdir().unwrap();
424 let filename = tempdir.path().join("test.arxml");
425
426 let model = AutosarModelAbstraction::create(filename.clone(), AutosarVersion::LATEST);
428 model.write().unwrap();
429
430 let model = AutosarModelAbstraction::new(AutosarModel::new());
432 let (_file, errors) = model.load_file(filename, true).unwrap();
433 assert!(errors.is_empty());
434 }
435
436 #[test]
437 fn model_packages() {
438 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00049);
439 let package = model.get_or_create_package("/package").unwrap();
440 let package2 = model.get_or_create_package("/other_package").unwrap();
441 model.get_or_create_package("/other_package/sub_package").unwrap();
442 let packages: Vec<_> = model.packages().collect();
443 assert_eq!(packages.len(), 2);
444 assert_eq!(packages[0], package);
445 assert_eq!(packages[1], package2);
446 }
447
448 #[test]
449 fn errors() {
450 let model = AutosarModel::new();
451
452 let err = AutosarAbstractionError::ConversionError {
453 element: model.root_element(),
454 dest: "TEST".to_string(),
455 };
456 let string = format!("{err}");
457 assert!(!string.is_empty());
458
459 let err = AutosarAbstractionError::InvalidPath("lorem ipsum".to_string());
460 let string = format!("{err}");
461 assert!(!string.is_empty());
462
463 let err = AutosarAbstractionError::ItemAlreadyExists;
464 let string = format!("{err}");
465 assert!(!string.is_empty());
466 }
467}