Skip to content

Commit

Permalink
Support mapping of software components to ECUs
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielT committed Jul 29, 2024
1 parent 3348098 commit cfbdf03
Show file tree
Hide file tree
Showing 2 changed files with 356 additions and 24 deletions.
159 changes: 146 additions & 13 deletions autosar-data-abstraction/src/software_component/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ use autosar_data::ElementName;

pub trait AbstractSwComponentType: AbstractionElement {
/// iterator over the instances of the component type
fn instances(&self) -> SwComponentPrototypeIterator {
fn instances(&self) -> ComponentPrototypeIterator {
let model_result = self.element().model();
let path_result = self.element().path();
if let (Ok(model), Ok(path)) = (model_result, path_result) {
let reflist = model.get_references_to(&path);
SwComponentPrototypeIterator::new(reflist)
ComponentPrototypeIterator::new(reflist)
} else {
SwComponentPrototypeIterator::new(vec![])
ComponentPrototypeIterator::new(vec![])
}
}

/// iterator over all compositions containing instances of the component type
fn compositions(&self) -> impl Iterator<Item = CompositionSwComponentType> {
fn parent_compositions(&self) -> impl Iterator<Item = CompositionSwComponentType> {
self.instances()
.filter_map(|swcp| swcp.element().named_parent().ok().flatten())
.filter_map(|elem| CompositionSwComponentType::try_from(elem).ok())
Expand All @@ -40,7 +40,7 @@ impl CompositionSwComponentType {
pub fn is_parent_of<T: AbstractSwComponentType>(&self, other: &T) -> bool {
// the expectation is that in normal cases each component has only one parent
// additionally there should never be any cycles in the composition hierarchy
let mut work_items = other.compositions().collect::<Vec<_>>();
let mut work_items = other.parent_compositions().collect::<Vec<_>>();
let mut counter = 1000; // just to prevent infinite loops, since I don't trust files generated by other tools
while !work_items.is_empty() && counter > 0 {
counter -= 1;
Expand All @@ -49,7 +49,7 @@ impl CompositionSwComponentType {
}
// the uses of pop here makes this a depth-first search in the case where there are multiple parents
let item = work_items.pop().unwrap();
work_items.extend(item.compositions());
work_items.extend(item.parent_compositions());
}

false
Expand All @@ -58,7 +58,11 @@ impl CompositionSwComponentType {
/// add a component of type component_type to the composition
///
/// It is not allowed to form cycles in the composition hierarchy, and this will return an error
pub fn add_component(&self, name: &str, component_type: &SwComponentType) -> Result<(), AutosarAbstractionError> {
pub fn add_component(
&self,
name: &str,
component_type: &SwComponentType,
) -> Result<SwComponentPrototype, AutosarAbstractionError> {
if let SwComponentType::Composition(composition_component) = component_type {
if composition_component.is_parent_of(self) {
return Err(AutosarAbstractionError::InvalidParameter(
Expand All @@ -68,11 +72,7 @@ impl CompositionSwComponentType {
}

let components = self.element().get_or_create_sub_element(ElementName::Components)?;
let component = components.create_named_sub_element(ElementName::SwComponentPrototype, name)?;
component
.create_sub_element(ElementName::TypeTref)?
.set_reference_target(&component_type.element())?;
Ok(())
SwComponentPrototype::new(name, &components, component_type)
}

/// get an iterator over the components of the composition
Expand Down Expand Up @@ -257,13 +257,129 @@ impl AbstractSwComponentType for SwComponentType {}
pub struct SwComponentPrototype(Element);
abstraction_element!(SwComponentPrototype, SwComponentPrototype);

impl SwComponentPrototype {
fn new(
name: &str,
components: &Element,
component_type: &SwComponentType,
) -> Result<Self, AutosarAbstractionError> {
let component = components.create_named_sub_element(ElementName::SwComponentPrototype, name)?;
component
.create_sub_element(ElementName::TypeTref)?
.set_reference_target(component_type.element())?;

Ok(Self(component))
}

/// get the sw component type that this prototype is based on
pub fn component_type(&self) -> Option<SwComponentType> {
let component_elem = self
.element()
.get_sub_element(ElementName::TypeTref)?
.get_reference_target()
.ok()?;
SwComponentType::try_from(component_elem).ok()
}

/// get the composition containing this component
pub fn parent_composition(&self) -> Result<CompositionSwComponentType, AutosarAbstractionError> {
let parent = self.element().named_parent()?.unwrap();
CompositionSwComponentType::try_from(parent)
}
}

//##################################################################

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct RootSwCompositionPrototype(Element);
abstraction_element!(RootSwCompositionPrototype, RootSwCompositionPrototype);

impl RootSwCompositionPrototype {
pub(crate) fn new(
name: &str,
root_compositions: &Element,
composition_type: &CompositionSwComponentType,
) -> Result<Self, AutosarAbstractionError> {
let root_composition =
root_compositions.create_named_sub_element(ElementName::RootSwCompositionPrototype, name)?;
root_composition
.create_sub_element(ElementName::SoftwareCompositionTref)?
.set_reference_target(composition_type.element())?;

Ok(Self(root_composition))
}

/// get the composition that this root component is based on
pub fn composition(&self) -> Option<CompositionSwComponentType> {
let composition_elem = self
.element()
.get_sub_element(ElementName::SoftwareCompositionTref)?
.get_reference_target()
.ok()?;
CompositionSwComponentType::try_from(composition_elem).ok()
}
}

//##################################################################

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ComponentPrototype {
SwComponent(SwComponentPrototype),
RootComposition(RootSwCompositionPrototype),
}

impl AbstractionElement for ComponentPrototype {
fn element(&self) -> &Element {
match self {
ComponentPrototype::SwComponent(swcp) => swcp.element(),
ComponentPrototype::RootComposition(root) => root.element(),
}
}
}

impl TryFrom<Element> for ComponentPrototype {
type Error = AutosarAbstractionError;

fn try_from(element: Element) -> Result<Self, Self::Error> {
match element.element_name() {
ElementName::SwComponentPrototype => Ok(ComponentPrototype::SwComponent(SwComponentPrototype(element))),
ElementName::RootSwCompositionPrototype => {
Ok(ComponentPrototype::RootComposition(RootSwCompositionPrototype(element)))
}
_ => Err(AutosarAbstractionError::ConversionError {
element,
dest: "ComponentPrototype".to_string(),
}),
}
}
}

impl ComponentPrototype {
pub fn component_type(&self) -> Option<SwComponentType> {
match self {
ComponentPrototype::SwComponent(swcp) => swcp.component_type(),
ComponentPrototype::RootComposition(rc) => rc.composition().map(|composition| composition.into()),
}
}

/// get the composition containing this component
///
/// if the component is a root composition, this will always return None
pub fn parent_composition(&self) -> Result<Option<CompositionSwComponentType>, AutosarAbstractionError> {
match self {
ComponentPrototype::SwComponent(swcp) => swcp.parent_composition().map(Some),
ComponentPrototype::RootComposition(_) => Ok(None),
}
}
}

//##################################################################

element_iterator!(CompositionComponentsIter, SwComponentType, Some);

//##################################################################

reflist_iterator!(SwComponentPrototypeIterator, SwComponentPrototype);
reflist_iterator!(ComponentPrototypeIterator, ComponentPrototype);

//##################################################################

Expand Down Expand Up @@ -309,4 +425,21 @@ mod test {
assert!(!comp4.is_parent_of(&comp2));
assert!(!comp4.is_parent_of(&comp3));
}

#[test]
fn root_composition() {
let model = AutosarModel::new();
let _file = model.create_file("filename", AutosarVersion::LATEST).unwrap();
let package = ArPackage::get_or_create(&model, "/package").unwrap();

let system = System::new("system", &package, SystemCategory::EcuExtract).unwrap();
let comp = CompositionSwComponentType::new("comp", &package).unwrap();
let root_sw_component_prototype = system.set_root_sw_composition("root", &comp).unwrap();

assert_eq!(
ComponentPrototype::RootComposition(root_sw_component_prototype),
comp.instances().next().unwrap()
);
assert_eq!(comp.instances().count(), 1);
}
}
Loading

0 comments on commit cfbdf03

Please sign in to comment.