use crate::{abstraction_element, software_component, AbstractionElement, AutosarAbstractionError};
use autosar_data::{Element, ElementName};
use software_component::{PortInterface, PortPrototype, SwComponentPrototype};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct DelegationSwConnector(Element);
abstraction_element!(DelegationSwConnector, DelegationSwConnector);
impl DelegationSwConnector {
pub(crate) fn new(
name: &str,
parent_element: &Element,
inner_port: &PortPrototype,
inner_sw_prototype: &SwComponentPrototype,
outer_port: &PortPrototype,
) -> Result<Self, AutosarAbstractionError> {
let inner_port_interface = inner_port.port_interface()?;
match &inner_port_interface {
PortInterface::SenderReceiverInterface(_) | PortInterface::NvDataInterface(_) => {
if (matches!(inner_port, PortPrototype::R(_)) && matches!(outer_port, PortPrototype::P(_)))
|| (matches!(inner_port, PortPrototype::P(_)) && matches!(outer_port, PortPrototype::R(_)))
{
return Err(AutosarAbstractionError::InvalidParameter(
"Invalid combination of provide and require ports".to_string(),
));
}
}
PortInterface::ClientServerInterface(_)
| PortInterface::ModeSwitchInterface(_)
| PortInterface::TriggerInterface(_) => {
match (inner_port, outer_port) {
(PortPrototype::P(_) | PortPrototype::PR(_), PortPrototype::P(_))
| (PortPrototype::R(_), PortPrototype::R(_)) => {}
_ => {
return Err(AutosarAbstractionError::InvalidParameter(
"Invalid combination of provide and require ports".to_string(),
));
}
}
}
PortInterface::ParameterInterface(_) => { }
}
let delegation_sw_connector =
parent_element.create_named_sub_element(ElementName::DelegationSwConnector, name)?;
let inner_iref = delegation_sw_connector.create_sub_element(ElementName::InnerPortIref)?;
if matches!(inner_port, PortPrototype::R(_)) {
let r_port_in_instance = inner_iref.create_sub_element(ElementName::RPortInCompositionInstanceRef)?;
r_port_in_instance
.create_sub_element(ElementName::TargetRPortRef)?
.set_reference_target(inner_port.element())?;
r_port_in_instance
.create_sub_element(ElementName::ContextComponentRef)?
.set_reference_target(inner_sw_prototype.element())?;
} else {
let p_port_in_instance = inner_iref.create_sub_element(ElementName::PPortInCompositionInstanceRef)?;
p_port_in_instance
.create_sub_element(ElementName::TargetPPortRef)?
.set_reference_target(inner_port.element())?;
p_port_in_instance
.create_sub_element(ElementName::ContextComponentRef)?
.set_reference_target(inner_sw_prototype.element())?;
};
delegation_sw_connector
.create_sub_element(ElementName::OuterPortRef)?
.set_reference_target(outer_port.element())?;
Ok(Self(delegation_sw_connector))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct AssemblySwConnector(Element);
abstraction_element!(AssemblySwConnector, AssemblySwConnector);
impl AssemblySwConnector {
pub(crate) fn new(
name: &str,
parent_element: &Element,
port_1: &PortPrototype,
sw_prototype_1: &SwComponentPrototype,
port_2: &PortPrototype,
sw_prototype_2: &SwComponentPrototype,
) -> Result<Self, AutosarAbstractionError> {
let (provider, p_proto_swc, requester, r_proto_swc) = match (port_1, port_2) {
(PortPrototype::P(_), PortPrototype::R(_)) => (port_1, sw_prototype_1, port_2, sw_prototype_2),
(PortPrototype::R(_), PortPrototype::P(_)) => (port_2, sw_prototype_2, port_1, sw_prototype_1),
(PortPrototype::P(_), PortPrototype::PR(_)) => (port_1, sw_prototype_1, port_2, sw_prototype_2),
(PortPrototype::PR(_), PortPrototype::P(_)) => (port_2, sw_prototype_2, port_1, sw_prototype_1),
(PortPrototype::R(_), PortPrototype::PR(_)) => (port_2, sw_prototype_2, port_1, sw_prototype_1),
(PortPrototype::PR(_), PortPrototype::R(_)) => (port_1, sw_prototype_1, port_2, sw_prototype_2),
(PortPrototype::PR(_), PortPrototype::PR(_)) => (port_1, sw_prototype_1, port_2, sw_prototype_2),
_ => {
return Err(AutosarAbstractionError::InvalidParameter(
"Invalid port roles".to_string(),
))
}
};
let port_interface = provider.port_interface()?;
if matches!(
&port_interface,
PortInterface::ClientServerInterface(_)
| PortInterface::ModeSwitchInterface(_)
| PortInterface::TriggerInterface(_)
) {
if !matches!(requester, PortPrototype::R(_)) {
return Err(AutosarAbstractionError::InvalidParameter(
"Invalid combination of provide and require ports".to_string(),
));
}
}
let assembly_sw_connector = parent_element.create_named_sub_element(ElementName::AssemblySwConnector, name)?;
let provider_iref = assembly_sw_connector.create_sub_element(ElementName::ProviderIref)?;
provider_iref
.create_sub_element(ElementName::TargetPPortRef)?
.set_reference_target(provider.element())?;
provider_iref
.create_sub_element(ElementName::ContextComponentRef)?
.set_reference_target(p_proto_swc.element())?;
let requester_iref = assembly_sw_connector.create_sub_element(ElementName::RequesterIref)?;
requester_iref
.create_sub_element(ElementName::TargetRPortRef)?
.set_reference_target(requester.element())?;
requester_iref
.create_sub_element(ElementName::ContextComponentRef)?
.set_reference_target(r_proto_swc.element())?;
Ok(Self(assembly_sw_connector))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PassThroughSwConnector(Element);
abstraction_element!(PassThroughSwConnector, PassThroughSwConnector);
impl PassThroughSwConnector {
pub(crate) fn new(
name: &str,
parent_element: &Element,
port_1: &PortPrototype,
port_2: &PortPrototype,
) -> Result<Self, AutosarAbstractionError> {
let (provided_port, required_port) = match (&port_1, &port_2) {
(PortPrototype::P(_), PortPrototype::R(_)) => (port_1, port_2),
(PortPrototype::R(_), PortPrototype::P(_)) => (port_2, port_1),
(PortPrototype::P(_), PortPrototype::PR(_)) => (port_1, port_2),
(PortPrototype::PR(_), PortPrototype::P(_)) => (port_2, port_1),
(PortPrototype::R(_), PortPrototype::PR(_)) => (port_2, port_1),
(PortPrototype::PR(_), PortPrototype::R(_)) => (port_1, port_2),
(PortPrototype::PR(_), PortPrototype::PR(_)) => (port_1, port_2),
_ => {
return Err(AutosarAbstractionError::InvalidParameter(
"Invalid port roles".to_string(),
))
}
};
let pass_through_sw_connector =
parent_element.create_named_sub_element(ElementName::PassThroughSwConnector, name)?;
pass_through_sw_connector
.create_sub_element(ElementName::ProvidedOuterPortRef)?
.set_reference_target(provided_port.element())?;
pass_through_sw_connector
.create_sub_element(ElementName::RequiredOuterPortRef)?
.set_reference_target(required_port.element())?;
Ok(Self(pass_through_sw_connector))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SwConnector {
Delegation(DelegationSwConnector),
Assembly(AssemblySwConnector),
PassThrough(PassThroughSwConnector),
}
impl AbstractionElement for SwConnector {
fn element(&self) -> &Element {
match self {
SwConnector::Delegation(connector) => connector.element(),
SwConnector::Assembly(connector) => connector.element(),
SwConnector::PassThrough(connector) => connector.element(),
}
}
}
impl TryFrom<Element> for SwConnector {
type Error = AutosarAbstractionError;
fn try_from(element: Element) -> Result<Self, Self::Error> {
match element.element_name() {
ElementName::DelegationSwConnector => Ok(SwConnector::Delegation(DelegationSwConnector(element))),
ElementName::AssemblySwConnector => Ok(SwConnector::Assembly(AssemblySwConnector(element))),
ElementName::PassThroughSwConnector => Ok(SwConnector::PassThrough(PassThroughSwConnector(element))),
_ => Err(AutosarAbstractionError::ConversionError {
element: element.clone(),
dest: "SwConnector".to_string(),
}),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::ArPackage;
use autosar_data::{AutosarModel, AutosarVersion, ElementName};
use software_component::{
AbstractSwComponentType, ApplicationSwComponentType, ClientServerInterface, CompositionSwComponentType,
SenderReceiverInterface,
};
#[test]
fn test_delegation_sw_connector() {
let model = AutosarModel::new();
let _file = model.create_file("filename", AutosarVersion::LATEST).unwrap();
let package = ArPackage::get_or_create(&model, "/package").unwrap();
let sr_interface = package.create_sender_receiver_interface("sr_interface").unwrap();
let cs_interface = package.create_client_server_interface("cs_interface").unwrap();
let composition = package.create_composition_sw_component_type("composition").unwrap();
let swc_type = package.create_application_sw_component_type("app_type").unwrap();
let outer_sr_p_port = composition.create_p_port("outer_sr_p_port", &sr_interface).unwrap();
let inner_sr_p_port = swc_type.create_p_port("inner_sr_p_port", &sr_interface).unwrap();
let outer_sr_r_port = composition.create_r_port("outer_sr_r_port", &sr_interface).unwrap();
let inner_sr_r_port = swc_type.create_r_port("inner_sr_r_port", &sr_interface).unwrap();
let outer_sr_pr_port = composition.create_pr_port("outer_sr_pr_port", &sr_interface).unwrap();
let inner_sr_pr_port = swc_type.create_pr_port("inner_sr_pr_port", &sr_interface).unwrap();
let outer_cs_p_port = composition.create_p_port("outer_cs_p_port", &cs_interface).unwrap();
let inner_cs_p_port = swc_type.create_p_port("inner_cs_p_port", &cs_interface).unwrap();
let outer_cs_r_port = composition.create_r_port("outer_cs_r_port", &cs_interface).unwrap();
let inner_cs_r_port = swc_type.create_r_port("inner_cs_r_port", &cs_interface).unwrap();
let outer_cs_pr_port = composition.create_pr_port("outer_cs_pr_port", &cs_interface).unwrap();
let inner_cs_pr_port = swc_type.create_pr_port("inner_cs_pr_port", &cs_interface).unwrap();
let app_prototype = composition.create_component("app_prototype", &swc_type).unwrap();
let sr_p_connector = composition
.create_delegation_connector("sr_p_connector", &inner_sr_p_port, &app_prototype, &outer_sr_p_port)
.unwrap();
let _sr_r_connector = composition
.create_delegation_connector("sr_r_connector", &inner_sr_r_port, &app_prototype, &outer_sr_r_port)
.unwrap();
let _sr_pr_connector = composition
.create_delegation_connector("sr_pr_connector", &inner_sr_pr_port, &app_prototype, &outer_sr_pr_port)
.unwrap();
let _cs_p_connector = composition
.create_delegation_connector("cs_p_connector", &inner_cs_p_port, &app_prototype, &outer_cs_p_port)
.unwrap();
let _cs_r_connector = composition
.create_delegation_connector("cs_r_connector", &inner_cs_r_port, &app_prototype, &outer_cs_r_port)
.unwrap();
let cs_pr_connector_result = composition.create_delegation_connector(
"cs_pr_connector",
&inner_cs_pr_port,
&app_prototype,
&outer_cs_pr_port,
);
assert!(cs_pr_connector_result.is_err());
let result = composition.create_delegation_connector(
"invalid_connector",
&inner_sr_p_port,
&app_prototype,
&outer_cs_p_port,
);
assert!(result.is_err());
assert_eq!(sr_p_connector.name(), Some("sr_p_connector".to_string()));
assert_eq!(
sr_p_connector.element().element_name(),
ElementName::DelegationSwConnector
);
}
#[test]
fn test_assembly_sw_connector() {
let model = AutosarModel::new();
let _file = model.create_file("filename", AutosarVersion::LATEST).unwrap();
let package = ArPackage::get_or_create(&model, "/package").unwrap();
let sr_interface = SenderReceiverInterface::new("sr_interface", &package).unwrap();
let cs_interface = ClientServerInterface::new("cs_interface", &package).unwrap();
let composition = CompositionSwComponentType::new("composition", &package).unwrap();
let swc_type_1 = ApplicationSwComponentType::new("app_type_1", &package).unwrap();
let swc_type_2 = ApplicationSwComponentType::new("app_type_2", &package).unwrap();
let swc1_sr_p_port = swc_type_1.create_p_port("swc1_sr_p_port", &sr_interface).unwrap();
let swc2_sr_p_port = swc_type_2.create_p_port("swc2_sr_p_port", &sr_interface).unwrap();
let swc1_sr_r_port = swc_type_1.create_r_port("swc1_sr_r_port", &sr_interface).unwrap();
let swc2_sr_r_port = swc_type_2.create_r_port("swc2_sr_r_port", &sr_interface).unwrap();
let swc1_sr_pr_port = swc_type_1.create_pr_port("swc1_sr_pr_port", &sr_interface).unwrap();
let swc2_sr_pr_port = swc_type_2.create_pr_port("swc2_sr_pr_port", &sr_interface).unwrap();
let swc1_cs_p_port = swc_type_1.create_p_port("swc1_cs_p_port", &cs_interface).unwrap();
let swc2_cs_p_port = swc_type_2.create_p_port("swc2_cs_p_port", &cs_interface).unwrap();
let swc1_cs_r_port = swc_type_1.create_r_port("swc1_cs_r_port", &cs_interface).unwrap();
let swc2_cs_r_port = swc_type_2.create_r_port("swc2_cs_r_port", &cs_interface).unwrap();
let swc1_cs_pr_port = swc_type_1.create_pr_port("swc1_cs_pr_port", &cs_interface).unwrap();
let swc2_cs_pr_port = swc_type_2.create_pr_port("swc2_cs_pr_port", &cs_interface).unwrap();
let app_prototype_1 = composition.create_component("app_prototype_1", &swc_type_1).unwrap();
let app_prototype_2 = composition.create_component("app_prototype_2", &swc_type_2).unwrap();
let _sr_p_r_connector = composition
.create_assembly_connector(
"sr_p_r_connector",
&swc1_sr_p_port,
&app_prototype_1,
&swc2_sr_r_port,
&app_prototype_2,
)
.unwrap();
let _sr_r_p_connector = composition
.create_assembly_connector(
"sr_r_p_connector",
&swc1_sr_r_port,
&app_prototype_1,
&swc2_sr_p_port,
&app_prototype_2,
)
.unwrap();
let _sr_p_pr_connector = composition
.create_assembly_connector(
"sr_p_pr_connector",
&swc1_sr_p_port,
&app_prototype_1,
&swc2_sr_pr_port,
&app_prototype_2,
)
.unwrap();
let _sr_r_pr_connector = composition
.create_assembly_connector(
"sr_r_pr_connector",
&swc1_sr_r_port,
&app_prototype_1,
&swc2_sr_pr_port,
&app_prototype_2,
)
.unwrap();
let _sr_pr_p_connector = composition
.create_assembly_connector(
"sr_pr_p_connector",
&swc1_sr_pr_port,
&app_prototype_1,
&swc2_sr_p_port,
&app_prototype_2,
)
.unwrap();
let _sr_pr_r_connector = composition
.create_assembly_connector(
"sr_pr_r_connector",
&swc1_sr_pr_port,
&app_prototype_1,
&swc2_sr_r_port,
&app_prototype_2,
)
.unwrap();
let _cs_p_r_connector = composition
.create_assembly_connector(
"cs_p_r_connector",
&swc1_cs_p_port,
&app_prototype_1,
&swc2_cs_r_port,
&app_prototype_2,
)
.unwrap();
let _cs_r_p_connector = composition
.create_assembly_connector(
"cs_r_p_connector",
&swc1_cs_r_port,
&app_prototype_1,
&swc2_cs_p_port,
&app_prototype_2,
)
.unwrap();
let cs_p_pr_connector_result = composition.create_assembly_connector(
"cs_p_pr_connector",
&swc1_cs_p_port,
&app_prototype_1,
&swc2_cs_pr_port,
&app_prototype_2,
);
assert!(cs_p_pr_connector_result.is_err());
let _cs_r_pr_connector = composition
.create_assembly_connector(
"cs_r_pr_connector",
&swc1_cs_r_port,
&app_prototype_1,
&swc2_cs_pr_port,
&app_prototype_2,
)
.unwrap();
let cs_pr_p_connector_result = composition.create_assembly_connector(
"cs_pr_p_connector",
&swc1_cs_pr_port,
&app_prototype_1,
&swc2_cs_p_port,
&app_prototype_2,
);
assert!(cs_pr_p_connector_result.is_err());
let _cs_pr_r_connector = composition
.create_assembly_connector(
"cs_pr_r_connector",
&swc1_cs_pr_port,
&app_prototype_1,
&swc2_cs_r_port,
&app_prototype_2,
)
.unwrap();
let sr_p_p_connector_result = composition.create_assembly_connector(
"sr_p_p_connector",
&swc1_sr_p_port,
&app_prototype_1,
&swc2_sr_p_port,
&app_prototype_2,
);
assert!(sr_p_p_connector_result.is_err());
let sr_r_r_connector_result = composition.create_assembly_connector(
"sr_r_r_connector",
&swc1_sr_r_port,
&app_prototype_1,
&swc2_sr_r_port,
&app_prototype_2,
);
assert!(sr_r_r_connector_result.is_err());
let result = composition.create_assembly_connector(
"invalid_connector",
&swc1_sr_p_port,
&app_prototype_1,
&swc2_cs_r_port,
&app_prototype_2,
);
assert!(result.is_err());
}
#[test]
fn test_pass_through_sw_connector() {
let model = AutosarModel::new();
let _file = model.create_file("filename", AutosarVersion::LATEST).unwrap();
let package = ArPackage::get_or_create(&model, "/package").unwrap();
let sr_interface = SenderReceiverInterface::new("sr_interface", &package).unwrap();
let cs_interface = ClientServerInterface::new("cs_interface", &package).unwrap();
let composition = CompositionSwComponentType::new("composition", &package).unwrap();
let sr_p_port = composition.create_p_port("sr_p_port", &sr_interface).unwrap();
let sr_r_port = composition.create_r_port("sr_r_port", &sr_interface).unwrap();
let cs_p_port = composition.create_p_port("cs_p_port", &cs_interface).unwrap();
let cs_r_port = composition.create_r_port("cs_r_port", &cs_interface).unwrap();
let _sr_p_r_connector = composition
.create_pass_through_connector("sr_p_r_connector", &sr_p_port, &sr_r_port)
.unwrap();
let _cs_r_p_connector = composition
.create_pass_through_connector("cs_r_p_connector", &cs_r_port, &cs_p_port)
.unwrap();
let result = composition.create_pass_through_connector("invalid_connector", &sr_p_port, &cs_r_port);
assert!(result.is_err());
}
}