mod attributename;
mod autosarversion;
mod elementname;
mod enumitem;
mod regex;
mod specification;
use std::ops::BitXor;
pub use attributename::AttributeName;
pub use autosarversion::AutosarVersion;
pub use elementname::ElementName;
pub use enumitem::EnumItem;
use specification::*;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ElementMultiplicity {
ZeroOrOne,
One,
Any,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ContentMode {
Sequence,
Choice,
Bag,
Characters,
Mixed,
}
pub enum CharacterDataSpec {
Enum {
items: &'static [(EnumItem, u32)],
},
Pattern {
check_fn: fn(&[u8]) -> bool,
regex: &'static str,
max_length: Option<usize>,
},
String {
preserve_whitespace: bool,
max_length: Option<usize>,
},
UnsignedInteger,
Double,
}
pub struct AttributeSpec {
pub spec: &'static CharacterDataSpec,
pub required: bool,
pub version: u32,
}
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
pub struct ElementType(usize);
enum SubElement {
Element {
name: ElementName,
elemtype: usize,
multiplicity: ElementMultiplicity,
},
Group {
groupid: usize,
},
}
struct ElementSpec {
sub_elements: (u16, u16),
sub_element_ver: u16,
attributes: (u16, u16),
attributes_ver: u16,
character_data: Option<u16>,
mode: ContentMode,
ordered: bool,
splittable: u32,
ref_by: &'static [EnumItem],
}
impl AutosarVersion {
pub fn compatible(&self, version_mask: u32) -> bool {
version_mask & *self as u32 != 0
}
}
impl ElementType {
fn get_sub_elements(&self) -> &'static [SubElement] {
let (idx_start, idx_end) = self.get_sub_element_idx();
&SUBELEMENTS[idx_start..idx_end]
}
fn get_sub_element_idx(&self) -> (usize, usize) {
let (start, end) = DATATYPES[self.0].sub_elements;
(start as usize, end as usize)
}
fn get_sub_element_ver(&self) -> usize {
DATATYPES[self.0].sub_element_ver as usize
}
fn get_attributes_idx(&self) -> (usize, usize) {
let (start, end) = DATATYPES[self.0].attributes;
(start as usize, end as usize)
}
fn get_attributes_ver(&self) -> usize {
DATATYPES[self.0].attributes_ver as usize
}
fn get_sub_element_spec<'a>(&self, element_indices: &[usize]) -> Option<(&'a SubElement, u32)> {
let spec = self.get_sub_elements();
let ver_list_start = self.get_sub_element_ver();
if !element_indices.is_empty() {
let mut current_spec = spec;
let mut current_ver_list_start = ver_list_start;
for idx in 0..(element_indices.len() - 1) {
match ¤t_spec[element_indices[idx]] {
SubElement::Element { .. } => {
return None;
}
SubElement::Group { groupid } => {
current_spec = ElementType(*groupid).get_sub_elements();
current_ver_list_start = ElementType(*groupid).get_sub_element_ver();
}
}
}
let last_idx = *element_indices.last().unwrap();
Some((¤t_spec[last_idx], VERSION_INFO[current_ver_list_start + last_idx]))
} else {
None
}
}
pub fn get_sub_element_version_mask(&self, element_indices: &[usize]) -> Option<u32> {
match self.get_sub_element_spec(element_indices) {
Some((_, version_mask)) => Some(version_mask),
_ => None,
}
}
pub fn get_sub_element_multiplicity(&self, element_indices: &[usize]) -> Option<ElementMultiplicity> {
match self.get_sub_element_spec(element_indices) {
Some((SubElement::Element { multiplicity, .. }, _)) => Some(*multiplicity),
_ => None,
}
}
pub fn get_sub_element_container_mode(&self, element_indices: &[usize]) -> ContentMode {
if element_indices.len() < 2 {
DATATYPES[self.0].mode
} else {
let len = element_indices.len() - 1;
if let Some((SubElement::Group { groupid }, _)) = self.get_sub_element_spec(&element_indices[..len]) {
DATATYPES[*groupid].mode
} else {
panic!("impossible: element container is not a group");
}
}
}
pub fn find_sub_element(&self, target_name: ElementName, version: u32) -> Option<(ElementType, Vec<usize>)> {
let spec = self.get_sub_elements();
for (cur_pos, sub_element) in spec.iter().enumerate() {
match sub_element {
SubElement::Element { name, elemtype, .. } => {
let ver_info_start = self.get_sub_element_ver();
let version_mask = VERSION_INFO[ver_info_start + cur_pos];
if (*name == target_name) && (version & version_mask != 0) {
return Some((ElementType(*elemtype), vec![cur_pos]));
}
}
SubElement::Group { groupid } => {
let group = ElementType(*groupid);
if let Some((elemtype, mut indices)) = group.find_sub_element(target_name, version) {
indices.insert(0, cur_pos);
return Some((elemtype, indices));
}
}
}
}
None
}
pub fn find_common_group(&self, element_indices: &[usize], element_indices2: &[usize]) -> ElementType {
let mut result = self.0;
let mut prefix_len = 0;
while element_indices.len() > prefix_len
&& element_indices2.len() > prefix_len
&& element_indices[prefix_len] == element_indices2[prefix_len]
{
let sub_elem = &ElementType(result).get_sub_elements()[element_indices[prefix_len]];
match sub_elem {
SubElement::Element { .. } => return ElementType(result),
SubElement::Group { groupid } => {
result = *groupid;
}
}
prefix_len += 1;
}
ElementType(result)
}
pub fn is_named(&self) -> bool {
self.short_name_version_mask().is_some()
}
pub(crate) fn short_name_version_mask(&self) -> Option<u32> {
let (start_idx, end_idx) = DATATYPES[self.0].sub_elements;
if start_idx != end_idx {
if let SubElement::Element {
name: ElementName::ShortName,
..
} = SUBELEMENTS[start_idx as usize]
{
Some(VERSION_INFO[DATATYPES[self.0].sub_element_ver as usize])
} else {
None
}
} else {
None
}
}
pub fn is_named_in_version(&self, version: AutosarVersion) -> bool {
self.short_name_version_mask()
.map_or(false, |ver_mask| version.compatible(ver_mask))
}
pub fn is_ref(&self) -> bool {
if let Some(idx) = DATATYPES[self.0].character_data {
idx == REFERENCE_TYPE_IDX
} else {
false
}
}
pub fn content_mode(&self) -> ContentMode {
DATATYPES[self.0].mode
}
pub fn chardata_spec(&self) -> Option<&'static CharacterDataSpec> {
if let Some(chardata_id) = DATATYPES[self.0].character_data {
Some(&CHARACTER_DATA[chardata_id as usize])
} else {
None
}
}
pub fn find_attribute_spec(&self, attrname: AttributeName) -> Option<AttributeSpec> {
let (idx_start, idx_end) = self.get_attributes_idx();
let attributes = &ATTRIBUTES[idx_start..idx_end];
if let Some((find_pos, (_, chardata_id, required))) =
attributes.iter().enumerate().find(|(_, (name, ..))| *name == attrname)
{
let idx_ver_start = self.get_attributes_ver();
let version = VERSION_INFO[idx_ver_start + find_pos];
Some(AttributeSpec {
spec: &CHARACTER_DATA[*chardata_id as usize],
required: *required,
version,
})
} else {
None
}
}
pub fn attribute_spec_iter(&self) -> AttrDefinitionsIter {
AttrDefinitionsIter {
type_id: self.0,
pos: 0,
}
}
pub fn sub_element_spec_iter(&self) -> SubelemDefinitionsIter {
SubelemDefinitionsIter {
type_id_stack: vec![self.0],
indices: vec![0],
}
}
pub fn is_ordered(&self) -> bool {
DATATYPES[self.0].ordered
}
pub fn splittable(&self) -> u32 {
DATATYPES[self.0].splittable
}
pub fn splittable_in(&self, version: AutosarVersion) -> bool {
(DATATYPES[self.0].splittable & (version as u32)) != 0
}
pub fn reference_dest_value(&self, other: &ElementType) -> Option<EnumItem> {
if self.is_ref() && other.is_named() {
let dest_spec = self.find_attribute_spec(AttributeName::Dest)?.spec;
if let CharacterDataSpec::Enum { items } = dest_spec {
for ref_target_value in DATATYPES[other.0].ref_by {
for (enumitem, _) in *items {
if ref_target_value == enumitem {
return Some(*ref_target_value);
}
}
}
}
}
None
}
pub const ROOT: Self = ElementType(ROOT_DATATYPE);
}
pub struct AttrDefinitionsIter {
type_id: usize,
pos: usize,
}
impl Iterator for AttrDefinitionsIter {
type Item = (AttributeName, &'static CharacterDataSpec, bool);
fn next(&mut self) -> Option<Self::Item> {
let (idx_start, idx_end) = ElementType(self.type_id).get_attributes_idx();
let cur_pos = self.pos;
self.pos += 1;
if idx_start + cur_pos < idx_end {
let (name, chardata_id, required) = ATTRIBUTES[idx_start + cur_pos];
Some((name, &CHARACTER_DATA[chardata_id as usize], required))
} else {
None
}
}
}
pub struct SubelemDefinitionsIter {
type_id_stack: Vec<usize>,
indices: Vec<usize>,
}
impl Iterator for SubelemDefinitionsIter {
type Item = (ElementName, ElementType, u32, u32);
fn next(&mut self) -> Option<Self::Item> {
if !self.type_id_stack.is_empty() {
debug_assert_eq!(self.type_id_stack.len(), self.indices.len());
let depth = self.indices.len() - 1;
let current_type = self.type_id_stack[depth];
let cur_pos = self.indices[depth];
let (start_idx, end_idx) = ElementType(current_type).get_sub_element_idx();
if start_idx + cur_pos < end_idx {
match &SUBELEMENTS[start_idx + cur_pos] {
SubElement::Element { name, elemtype, .. } => {
self.indices[depth] += 1;
let ver_idx = ElementType(current_type).get_sub_element_ver();
let version_mask = VERSION_INFO[ver_idx + cur_pos];
let is_named = ElementType(*elemtype).short_name_version_mask().unwrap_or(0);
Some((*name, ElementType(*elemtype), version_mask, is_named))
}
SubElement::Group { groupid } => {
self.type_id_stack.push(*groupid);
self.indices.push(0);
self.next()
}
}
} else {
self.indices.pop();
self.type_id_stack.pop();
if !self.indices.is_empty() {
self.indices[depth - 1] += 1;
}
self.next()
}
} else {
None
}
}
}
impl std::fmt::Debug for CharacterDataSpec {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Enum { items } => f.debug_struct("Enum").field("items", items).finish(),
Self::Pattern { regex, max_length, .. } => f
.debug_struct("Pattern")
.field("regex", regex)
.field("max_length", max_length)
.finish(),
Self::String {
preserve_whitespace,
max_length,
} => f
.debug_struct("String")
.field("preserve_whitespace", preserve_whitespace)
.field("max_length", max_length)
.finish(),
Self::UnsignedInteger => write!(f, "UnsignedInteger"),
Self::Double => write!(f, "Double"),
}
}
}
pub fn expand_version_mask(version_mask: u32) -> Vec<AutosarVersion> {
let mut versions = vec![];
for i in 0..u32::BITS {
let val = 1u32 << i;
if version_mask & val != 0 {
if let Some(enum_value) = AutosarVersion::from_val(val) {
versions.push(enum_value);
}
}
}
versions
}
pub(crate) fn hashfunc(mut data: &[u8]) -> (u32, u32, u32) {
const HASHCONST1: u32 = 0x541C69B2; const HASHCONST2: u32 = 0x3B17161B;
let mut f1 = 0x33143C63u32;
let mut f2 = 0x88B0B21Eu32;
while data.len() >= 4 {
let val = u32::from_ne_bytes(data[..4].try_into().unwrap());
f1 = f1.rotate_left(5).bitxor(val).wrapping_mul(HASHCONST1);
f2 = f2.rotate_left(6).bitxor(val).wrapping_mul(HASHCONST2);
data = &data[4..];
}
if data.len() >= 2 {
let val = u16::from_ne_bytes(data[..2].try_into().unwrap()) as u32;
f1 = f1.rotate_left(5).bitxor(val).wrapping_mul(HASHCONST1);
f2 = f2.rotate_left(6).bitxor(val).wrapping_mul(HASHCONST2);
data = &data[2..];
}
if !data.is_empty() {
f1 = f1.rotate_left(5).bitxor(data[0] as u32).wrapping_mul(HASHCONST1);
f2 = f2.rotate_left(6).bitxor(data[0] as u32).wrapping_mul(HASHCONST2);
}
let g = f1.bitxor(f2);
(g, f1, f2)
}
#[cfg(test)]
mod test {
use std::{collections::HashSet, str::FromStr};
use super::*;
fn get_prm_char_element_type() -> ElementType {
let (ar_packages_type, _) = ElementType::ROOT
.find_sub_element(ElementName::ArPackages, u32::MAX)
.unwrap();
let (ar_package_type, _) = ar_packages_type
.find_sub_element(ElementName::ArPackage, u32::MAX)
.unwrap();
let (elements_type, _) = ar_package_type
.find_sub_element(ElementName::Elements, u32::MAX)
.unwrap();
let (documentation_type, _) = elements_type
.find_sub_element(ElementName::Documentation, u32::MAX)
.unwrap();
let (documentation_content_type, _) = documentation_type
.find_sub_element(ElementName::DocumentationContent, u32::MAX)
.unwrap();
let (prms_type, _) = documentation_content_type
.find_sub_element(ElementName::Prms, u32::MAX)
.unwrap();
let (prm_type, _) = prms_type.find_sub_element(ElementName::Prm, u32::MAX).unwrap();
let (prm_char_type, _) = prm_type.find_sub_element(ElementName::PrmChar, u32::MAX).unwrap();
prm_char_type
}
#[test]
fn find_sub_element() {
let prm_char_type = get_prm_char_element_type();
let (_, indices) = prm_char_type.find_sub_element(ElementName::Tol, 0xffffffff).unwrap();
assert_eq!(indices, vec![1, 0, 0, 0, 1]);
}
#[test]
fn find_sub_element_version_dependent() {
let (ar_packages_type, _) = ElementType::ROOT
.find_sub_element(ElementName::ArPackages, u32::MAX)
.unwrap();
let (ar_package_type, _) = ar_packages_type
.find_sub_element(ElementName::ArPackage, u32::MAX)
.unwrap();
let (elements_type, _) = ar_package_type
.find_sub_element(ElementName::Elements, u32::MAX)
.unwrap();
let (sw_base_type_type, _) = elements_type
.find_sub_element(ElementName::SwBaseType, u32::MAX)
.unwrap();
let (_, indices) = sw_base_type_type
.find_sub_element(ElementName::BaseTypeSize, AutosarVersion::Autosar_4_0_1 as u32)
.unwrap();
assert_eq!(indices, vec![11, 0]);
let (_, indices) = sw_base_type_type
.find_sub_element(ElementName::BaseTypeSize, AutosarVersion::Autosar_4_1_1 as u32)
.unwrap();
assert_eq!(indices, vec![13]);
}
#[test]
fn get_sub_element_spec() {
let prm_char_type = get_prm_char_element_type();
let (abs_type, indices) = prm_char_type.find_sub_element(ElementName::Abs, u32::MAX).unwrap();
let sub_elem_spec = prm_char_type.get_sub_element_spec(&indices);
let (sub_element, _) = sub_elem_spec.unwrap();
if let SubElement::Element { name, elemtype, .. } = sub_element {
assert_eq!(*name, ElementName::Abs);
assert_eq!(ElementType(*elemtype), abs_type);
}
let sub_elem_spec2 = prm_char_type.get_sub_element_spec(&[]);
assert!(sub_elem_spec2.is_none());
let sub_elem_spec2 = prm_char_type.get_sub_element_spec(&[0, 0, 0, 0, 0, 0, 0, 0, 0]);
assert!(sub_elem_spec2.is_none());
}
#[test]
fn get_sub_element_version_mask() {
let prm_char_type = get_prm_char_element_type();
let (_, indices) = prm_char_type.find_sub_element(ElementName::Abs, u32::MAX).unwrap();
let sub_elem_spec = prm_char_type.get_sub_element_spec(&indices).unwrap();
let version_mask2 = prm_char_type.get_sub_element_version_mask(&indices).unwrap();
let (_, version_mask) = sub_elem_spec;
assert_eq!(version_mask, version_mask2);
let no_result = prm_char_type.get_sub_element_version_mask(&[]);
assert!(no_result.is_none());
}
#[test]
fn get_sub_element_multiplicity() {
let prm_char_type = get_prm_char_element_type();
let (_, indices) = prm_char_type.find_sub_element(ElementName::Abs, u32::MAX).unwrap();
let sub_elem_spec = prm_char_type.get_sub_element_spec(&indices).unwrap().0;
let multiplicity2 = prm_char_type.get_sub_element_multiplicity(&indices).unwrap();
if let SubElement::Element { multiplicity, .. } = sub_elem_spec {
assert_eq!(*multiplicity, multiplicity2);
}
let no_result = prm_char_type.get_sub_element_multiplicity(&[]);
assert!(no_result.is_none());
}
#[test]
fn get_sub_element_container_mode() {
let prm_char_type = get_prm_char_element_type();
let (_, indices) = prm_char_type.find_sub_element(ElementName::Abs, u32::MAX).unwrap();
let mode = prm_char_type.get_sub_element_container_mode(&indices);
assert_eq!(mode, ContentMode::Sequence);
}
#[test]
fn find_common_group() {
let prm_char_type = get_prm_char_element_type();
let (_, indices_abs) = prm_char_type.find_sub_element(ElementName::Abs, u32::MAX).unwrap();
let (_, indices_tol) = prm_char_type.find_sub_element(ElementName::Tol, u32::MAX).unwrap();
let (_, indices_min) = prm_char_type.find_sub_element(ElementName::Min, u32::MAX).unwrap();
let group1 = prm_char_type.find_common_group(&indices_abs, &indices_tol);
assert_eq!(group1.content_mode(), ContentMode::Sequence);
let group2 = prm_char_type.find_common_group(&indices_abs, &indices_min);
assert_eq!(group2.content_mode(), ContentMode::Choice);
}
#[test]
fn find_attribute_spec() {
let AttributeSpec {
spec,
required,
version,
} = ElementType::ROOT.find_attribute_spec(AttributeName::xmlns).unwrap();
let spec_dbgstr = format!("{:#?}", spec);
assert!(!spec_dbgstr.is_empty());
assert!(required);
assert_ne!(version & AutosarVersion::Autosar_00050 as u32, 0);
assert_ne!(version & AutosarVersion::Autosar_4_0_1 as u32, 0);
}
#[test]
fn subelement_definition_iterator() {
let (ar_packages_type, _) = ElementType::ROOT
.find_sub_element(ElementName::ArPackages, u32::MAX)
.unwrap();
let (ar_package_type, _) = ar_packages_type
.find_sub_element(ElementName::ArPackage, u32::MAX)
.unwrap();
let (elements_type, _) = ar_package_type
.find_sub_element(ElementName::Elements, u32::MAX)
.unwrap();
let se_iter = elements_type.sub_element_spec_iter();
assert_eq!(se_iter.count(), 586); let prm_char_type = get_prm_char_element_type();
let pc_iter = prm_char_type.sub_element_spec_iter();
let compatible_count = pc_iter
.filter(|(_, _, version_mask, _)| AutosarVersion::Autosar_00050.compatible(*version_mask))
.count();
assert_eq!(compatible_count, 9);
}
#[test]
fn autosar_version() {
assert_eq!(
AutosarVersion::from_str("AUTOSAR_4-0-1.xsd").unwrap(),
AutosarVersion::Autosar_4_0_1
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_4-0-2.xsd").unwrap(),
AutosarVersion::Autosar_4_0_2
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_4-0-3.xsd").unwrap(),
AutosarVersion::Autosar_4_0_3
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_4-1-1.xsd").unwrap(),
AutosarVersion::Autosar_4_1_1
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_4-1-2.xsd").unwrap(),
AutosarVersion::Autosar_4_1_2
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_4-1-3.xsd").unwrap(),
AutosarVersion::Autosar_4_1_3
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_4-2-1.xsd").unwrap(),
AutosarVersion::Autosar_4_2_1
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_4-2-2.xsd").unwrap(),
AutosarVersion::Autosar_4_2_2
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_4-3-0.xsd").unwrap(),
AutosarVersion::Autosar_4_3_0
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_00042.xsd").unwrap(),
AutosarVersion::Autosar_00042
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_00043.xsd").unwrap(),
AutosarVersion::Autosar_00043
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_00044.xsd").unwrap(),
AutosarVersion::Autosar_00044
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_00045.xsd").unwrap(),
AutosarVersion::Autosar_00045
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_00046.xsd").unwrap(),
AutosarVersion::Autosar_00046
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_00047.xsd").unwrap(),
AutosarVersion::Autosar_00047
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_00048.xsd").unwrap(),
AutosarVersion::Autosar_00048
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_00049.xsd").unwrap(),
AutosarVersion::Autosar_00049
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_00050.xsd").unwrap(),
AutosarVersion::Autosar_00050
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_00051.xsd").unwrap(),
AutosarVersion::Autosar_00051
);
assert!(AutosarVersion::Autosar_4_0_1.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_4_0_2.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_4_0_3.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_4_1_1.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_4_1_2.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_4_1_3.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_4_2_1.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_4_2_2.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_4_3_0.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_00042.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_00043.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_00044.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_00045.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_00046.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_00047.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_00048.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_00049.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_00050.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_00051.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_4_0_1.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_4_0_2.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_4_0_3.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_4_1_1.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_4_1_2.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_4_1_3.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_4_2_1.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_4_2_2.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_4_3_0.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_00042.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_00043.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_00044.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_00045.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_00046.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_00047.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_00048.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_00049.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_00050.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_00051.filename().ends_with(".xsd"));
assert_eq!(
AutosarVersion::Autosar_4_0_1.to_string(),
AutosarVersion::Autosar_4_0_1.describe()
);
let cloned = AutosarVersion::Autosar_00050;
assert_eq!(cloned, AutosarVersion::Autosar_00050);
let error = AutosarVersion::from_str("something else");
assert_eq!(format!("{:#?}", error.unwrap_err()), "ParseAutosarVersionError");
let mut hashset = HashSet::<AutosarVersion>::new();
hashset.insert(AutosarVersion::Autosar_00050);
}
#[test]
fn attribute_name_basics() {
assert_eq!(
AttributeName::Uuid,
AttributeName::from_str(AttributeName::Uuid.to_str()).unwrap()
);
assert_eq!(AttributeName::Uuid.to_string(), "UUID");
let cloned = AttributeName::Uuid;
assert_eq!(cloned, AttributeName::Uuid);
let error = AttributeName::from_str("unknown attribute name");
assert_eq!(format!("{:#?}", error.unwrap_err()), "ParseAttributeNameError");
let mut hashset = HashSet::<AttributeName>::new();
hashset.insert(AttributeName::Dest);
}
#[test]
fn element_name_basics() {
assert_eq!(
ElementName::Autosar,
ElementName::from_str(ElementName::Autosar.to_str()).unwrap()
);
assert_eq!(ElementName::Autosar.to_string(), "AUTOSAR");
let cloned = ElementName::Autosar;
assert_eq!(cloned, ElementName::Autosar);
let error = ElementName::from_str("unknown element name");
assert_eq!(format!("{:#?}", error.unwrap_err()), "ParseElementNameError");
let mut hashset = HashSet::<ElementName>::new();
hashset.insert(ElementName::Autosar);
}
#[test]
fn enum_item_basics() {
assert_eq!(
EnumItem::Default,
EnumItem::from_str(EnumItem::Default.to_str()).unwrap()
);
assert_eq!(EnumItem::Default.to_string(), "DEFAULT");
let cloned = EnumItem::Abstract;
assert_eq!(cloned, EnumItem::Abstract);
let error = EnumItem::from_str("unknown enum item");
assert_eq!(format!("{:#?}", error.unwrap_err()), "ParseEnumItemError");
let mut hashset = HashSet::<EnumItem>::new();
hashset.insert(EnumItem::Abstract);
}
#[test]
fn ordered() {
let (ar_packages_type, _) = ElementType::ROOT
.find_sub_element(ElementName::ArPackages, u32::MAX)
.unwrap();
let (ar_package_type, _) = ar_packages_type
.find_sub_element(ElementName::ArPackage, u32::MAX)
.unwrap();
let (elements_type, _) = ar_package_type
.find_sub_element(ElementName::Elements, u32::MAX)
.unwrap();
let (bsw_module_entry, _) = elements_type
.find_sub_element(ElementName::BswModuleEntry, u32::MAX)
.unwrap();
let (arguments, _) = bsw_module_entry
.find_sub_element(ElementName::Arguments, u32::MAX)
.unwrap();
assert!(!bsw_module_entry.is_ordered());
assert!(arguments.is_ordered());
}
#[test]
fn splittable() {
let (ar_packages_type, _) = ElementType::ROOT
.find_sub_element(ElementName::ArPackages, u32::MAX)
.unwrap();
let (ar_package_type, _) = ar_packages_type
.find_sub_element(ElementName::ArPackage, u32::MAX)
.unwrap();
let (elements_type, _) = ar_package_type
.find_sub_element(ElementName::Elements, u32::MAX)
.unwrap();
assert!(!ar_package_type.splittable_in(AutosarVersion::Autosar_00051));
assert_ne!(ar_packages_type.splittable() & AutosarVersion::Autosar_00051 as u32, 0);
assert!(ar_packages_type.splittable_in(AutosarVersion::Autosar_00051));
assert_ne!(elements_type.splittable() & AutosarVersion::Autosar_00051 as u32, 0);
}
#[test]
fn reference_dest() {
let (ar_packages_type, _) = ElementType::ROOT
.find_sub_element(ElementName::ArPackages, u32::MAX)
.unwrap();
let (ar_package_type, _) = ar_packages_type
.find_sub_element(ElementName::ArPackage, u32::MAX)
.unwrap();
let (elements_type, _) = ar_package_type
.find_sub_element(ElementName::Elements, u32::MAX)
.unwrap();
let (can_tp_config_type, _) = elements_type
.find_sub_element(ElementName::CanTpConfig, u32::MAX)
.unwrap();
let (tp_connections_type, _) = can_tp_config_type
.find_sub_element(ElementName::TpConnections, u32::MAX)
.unwrap();
let (can_tp_connection_type, _) = tp_connections_type
.find_sub_element(ElementName::CanTpConnection, u32::MAX)
.unwrap();
let (ident_type, _) = can_tp_connection_type
.find_sub_element(ElementName::Ident, u32::MAX)
.unwrap();
let (diagnostic_connection_type, _) = elements_type
.find_sub_element(ElementName::DiagnosticConnection, u32::MAX)
.unwrap();
let (physical_request_ref_type, _) = diagnostic_connection_type
.find_sub_element(ElementName::PhysicalRequestRef, u32::MAX)
.unwrap();
let ref_value = physical_request_ref_type.reference_dest_value(&ident_type).unwrap();
assert_eq!(ref_value, EnumItem::TpConnectionIdent);
let invalid_ref = physical_request_ref_type.reference_dest_value(&tp_connections_type);
assert!(invalid_ref.is_none());
}
#[test]
fn traits() {
let mult = ElementMultiplicity::Any;
let m2 = mult.clone(); assert_eq!(format!("{:#?}", mult), format!("{:#?}", m2));
let cm = ContentMode::Sequence;
let cm2 = cm.clone(); assert_eq!(format!("{:#?}", cm), format!("{:#?}", cm2));
let et = ElementType::ROOT;
let et2 = et.clone(); assert_eq!(format!("{:#?}", et), format!("{:#?}", et2));
let mut hashset = HashSet::<ElementType>::new();
hashset.insert(et);
let inserted = hashset.insert(et2);
assert!(!inserted);
let ver = AutosarVersion::LATEST;
let ver2 = ver.clone(); assert_eq!(format!("{ver:#?}"), format!("{ver2:#?}"));
let mut hashset = HashSet::<AutosarVersion>::new();
hashset.insert(ver);
let inserted = hashset.insert(ver2);
assert!(!inserted);
let en = ElementName::Autosar;
let en2 = en.clone(); assert_eq!(format!("{en:#?}"), format!("{en2:#?}"));
let mut hashset = HashSet::<ElementName>::new();
hashset.insert(en);
let inserted = hashset.insert(en2);
assert!(!inserted);
let cdata_spec = CharacterDataSpec::String {
preserve_whitespace: true,
max_length: None,
};
let txt = format!("{cdata_spec:#?}");
assert!(txt.starts_with("String"));
let cdata_spec = CharacterDataSpec::Pattern {
check_fn: crate::regex::validate_regex_1,
regex: r"0x[0-9a-z]*",
max_length: None,
};
let txt = format!("{cdata_spec:#?}");
assert!(txt.starts_with("Pattern"));
let cdata_spec = CharacterDataSpec::Enum {
items: &[(EnumItem::Custom, 0x7e000)],
};
let txt = format!("{cdata_spec:#?}");
assert!(txt.starts_with("Enum"));
let cdata_spec = CharacterDataSpec::Double;
let txt = format!("{cdata_spec:#?}");
assert!(txt.starts_with("Double"));
let cdata_spec = CharacterDataSpec::UnsignedInteger;
let txt = format!("{cdata_spec:#?}");
assert!(txt.starts_with("UnsignedInteger"));
}
#[test]
fn test_expand_version_mask() {
let (ar_packages_type, _) = ElementType::ROOT
.find_sub_element(ElementName::ArPackages, u32::MAX)
.unwrap();
let (ar_package_type, _) = ar_packages_type
.find_sub_element(ElementName::ArPackage, u32::MAX)
.unwrap();
let (elements_type, _) = ar_package_type
.find_sub_element(ElementName::Elements, u32::MAX)
.unwrap();
let (_, element_indices) = elements_type
.find_sub_element(ElementName::AdaptiveApplicationSwComponentType, u32::MAX)
.unwrap();
let version_mask = elements_type.get_sub_element_version_mask(&element_indices).unwrap();
assert_eq!(
&[
AutosarVersion::Autosar_00042,
AutosarVersion::Autosar_00043,
AutosarVersion::Autosar_00044,
AutosarVersion::Autosar_00045,
AutosarVersion::Autosar_00046,
AutosarVersion::Autosar_00047,
AutosarVersion::Autosar_00048,
AutosarVersion::Autosar_00049,
AutosarVersion::Autosar_00050,
AutosarVersion::Autosar_00051,
],
&*expand_version_mask(version_mask)
);
}
}