#![no_std]
#[macro_use]
extern crate alloc;
use alloc::vec::Vec;
use core::ops::BitXor;
mod attributename;
mod autosarversion;
mod elementname;
mod enumitem;
mod regex;
mod specification;
pub use attributename::{AttributeName, ParseAttributeNameError};
pub use autosarversion::{AutosarVersion, ParseAutosarVersionError};
pub use elementname::{ElementName, ParseElementNameError};
pub use enumitem::{EnumItem, ParseEnumItemError};
use specification::{
ATTRIBUTES, AUTOSAR_ELEMENT, CHARACTER_DATA, DATATYPES, ELEMENTS, REF_ITEMS, REFERENCE_TYPE_IDX, SUBELEMENTS,
VERSION_INFO,
};
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ElementMultiplicity {
ZeroOrOne,
One,
Any,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum StdRestrict {
NotRestricted,
ClassicPlatform,
AdaptivePlatform,
}
#[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,
Float,
}
pub struct AttributeSpec {
pub spec: &'static CharacterDataSpec,
pub required: bool,
pub version: u32,
}
#[derive(Eq, PartialEq, Clone, Copy, Hash)]
pub struct ElementType {
def: u16,
typ: u16,
}
#[derive(Debug, Clone, Copy)]
pub struct GroupType(u16);
#[derive(Debug)]
enum SubElement {
Element(u16),
Group(u16),
}
struct ElementDefinition {
name: ElementName,
elemtype: u16,
multiplicity: ElementMultiplicity,
ordered: bool,
splittable: u32,
restrict_std: StdRestrict,
#[cfg(feature = "docstrings")]
docstring: Option<u16>,
}
struct ElementSpec {
sub_elements: (u16, u16),
sub_element_ver: u16,
attributes: (u16, u16),
attributes_ver: u16,
character_data: Option<u16>,
mode: ContentMode,
ref_info: (u16, u16),
}
impl AutosarVersion {
#[must_use]
pub fn compatible(&self, version_mask: u32) -> bool {
version_mask & *self as u32 != 0
}
}
impl ElementType {
#[must_use]
const fn new(def: u16) -> Self {
let typ = ELEMENTS[def as usize].elemtype;
Self { def, typ }
}
fn get_sub_elements(etype: u16) -> &'static [SubElement] {
let (idx_start, idx_end) = ElementType::get_sub_element_idx(etype);
&SUBELEMENTS[idx_start..idx_end]
}
const fn get_sub_element_idx(etype: u16) -> (usize, usize) {
let (start, end) = DATATYPES[etype as usize].sub_elements;
(start as usize, end as usize)
}
const fn get_sub_element_ver(etype: u16) -> usize {
DATATYPES[etype as usize].sub_element_ver as usize
}
const fn get_attributes_idx(etype: u16) -> (usize, usize) {
let (start, end) = DATATYPES[etype as usize].attributes;
(start as usize, end as usize)
}
const fn get_attributes_ver(etype: u16) -> usize {
DATATYPES[etype as usize].attributes_ver as usize
}
fn get_sub_element_spec<'a>(self, element_indices: &[usize]) -> Option<(&'a SubElement, u32)> {
if element_indices.is_empty() {
return None;
}
let spec = ElementType::get_sub_elements(self.typ);
let ver_list_start = ElementType::get_sub_element_ver(self.typ);
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::get_sub_elements(*groupid);
current_ver_list_start = ElementType::get_sub_element_ver(*groupid);
}
}
}
let last_idx = *element_indices.last().unwrap();
Some((¤t_spec[last_idx], VERSION_INFO[current_ver_list_start + last_idx]))
}
#[must_use]
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,
}
}
#[must_use]
pub fn get_sub_element_multiplicity(&self, element_indices: &[usize]) -> Option<ElementMultiplicity> {
match self.get_sub_element_spec(element_indices) {
Some((SubElement::Element(definiton_id), _)) => Some(ELEMENTS[*definiton_id as usize].multiplicity),
_ => None,
}
}
#[must_use]
pub fn get_sub_element_container_mode(&self, element_indices: &[usize]) -> ContentMode {
if element_indices.len() < 2 {
DATATYPES[self.typ as usize].mode
} else {
let len = element_indices.len() - 1;
if let Some((SubElement::Group(groupid), _)) = self.get_sub_element_spec(&element_indices[..len]) {
DATATYPES[*groupid as usize].mode
} else {
unreachable!("impossible: element container is not a group");
}
}
}
#[must_use]
pub fn find_sub_element(&self, target_name: ElementName, version: u32) -> Option<(ElementType, Vec<usize>)> {
ElementType::find_sub_element_internal(self.typ, target_name, version)
}
fn find_sub_element_internal(
etype: u16,
target_name: ElementName,
version: u32,
) -> Option<(ElementType, Vec<usize>)> {
let spec = ElementType::get_sub_elements(etype);
for (cur_pos, sub_element) in spec.iter().enumerate() {
match sub_element {
SubElement::Element(definiton_id) => {
let name = ELEMENTS[*definiton_id as usize].name;
let ver_info_start = ElementType::get_sub_element_ver(etype);
let version_mask = VERSION_INFO[ver_info_start + cur_pos];
if (name == target_name) && (version & version_mask != 0) {
return Some((ElementType::new(*definiton_id), vec![cur_pos]));
}
}
SubElement::Group(groupid) => {
if let Some((elemtype, mut indices)) =
ElementType::find_sub_element_internal(*groupid, target_name, version)
{
indices.insert(0, cur_pos);
return Some((elemtype, indices));
}
}
}
}
None
}
#[must_use]
pub fn find_common_group(&self, element_indices: &[usize], element_indices2: &[usize]) -> GroupType {
let mut result = self.typ;
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::get_sub_elements(result)[element_indices[prefix_len]];
match sub_elem {
SubElement::Element(_) => return GroupType(result),
SubElement::Group(groupid) => {
result = *groupid;
}
}
prefix_len += 1;
}
GroupType(result)
}
#[must_use]
pub fn is_named(&self) -> bool {
self.short_name_version_mask().is_some()
}
pub(crate) fn short_name_version_mask(self) -> Option<u32> {
let sub_elements = ElementType::get_sub_elements(self.typ);
if !sub_elements.is_empty()
&& let SubElement::Element(idx) = sub_elements[0]
&& ELEMENTS[idx as usize].name == ElementName::ShortName
{
let ver_idx = ElementType::get_sub_element_ver(self.typ);
return Some(VERSION_INFO[ver_idx]);
}
None
}
#[must_use]
pub fn is_named_in_version(&self, version: AutosarVersion) -> bool {
self.short_name_version_mask()
.is_some_and(|ver_mask| version.compatible(ver_mask))
}
#[must_use]
pub fn is_ref(&self) -> bool {
if let Some(idx) = DATATYPES[self.typ as usize].character_data {
idx == REFERENCE_TYPE_IDX
} else {
false
}
}
#[must_use]
pub const fn content_mode(&self) -> ContentMode {
DATATYPES[self.typ as usize].mode
}
#[must_use]
pub const fn chardata_spec(&self) -> Option<&'static CharacterDataSpec> {
if let Some(chardata_id) = DATATYPES[self.typ as usize].character_data {
Some(&CHARACTER_DATA[chardata_id as usize])
} else {
None
}
}
#[must_use]
pub fn find_attribute_spec(&self, attrname: AttributeName) -> Option<AttributeSpec> {
let (idx_start, idx_end) = ElementType::get_attributes_idx(self.typ);
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 = ElementType::get_attributes_ver(self.typ);
let version = VERSION_INFO[idx_ver_start + find_pos];
Some(AttributeSpec {
spec: &CHARACTER_DATA[*chardata_id as usize],
required: *required,
version,
})
} else {
None
}
}
#[must_use]
pub const fn attribute_spec_iter(&self) -> AttrDefinitionsIter {
AttrDefinitionsIter {
type_id: self.typ,
pos: 0,
}
}
#[must_use]
pub fn sub_element_spec_iter(&self) -> SubelemDefinitionsIter {
SubelemDefinitionsIter {
type_id_stack: vec![self.typ],
indices: vec![0],
}
}
#[must_use]
pub const fn is_ordered(&self) -> bool {
ELEMENTS[self.def as usize].ordered
}
#[must_use]
pub const fn splittable(&self) -> u32 {
ELEMENTS[self.def as usize].splittable
}
#[must_use]
pub const fn splittable_in(&self, version: AutosarVersion) -> bool {
(ELEMENTS[self.def as usize].splittable & (version as u32)) != 0
}
#[must_use]
pub const fn std_restriction(&self) -> StdRestrict {
ELEMENTS[self.def as usize].restrict_std
}
#[must_use]
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 {
let (start, end) = DATATYPES[other.typ as usize].ref_info;
let ref_by = &REF_ITEMS[start as usize..end as usize];
for ref_target_value in ref_by {
for (enumitem, _) in *items {
if ref_target_value == enumitem {
return Some(*ref_target_value);
}
}
}
}
}
None
}
#[must_use]
pub fn verify_reference_dest(&self, dest_value: EnumItem) -> bool {
let (start, end) = DATATYPES[self.typ as usize].ref_info;
let values = &REF_ITEMS[start as usize..end as usize];
values.contains(&dest_value)
}
#[cfg(feature = "docstrings")]
#[must_use]
pub const fn docstring(&self) -> &str {
if let Some(docstring_id) = ELEMENTS[self.def as usize].docstring {
specification::ELEMENT_DOCSTRINGS[docstring_id as usize]
} else {
""
}
}
pub const ROOT: Self = ElementType::new(AUTOSAR_ELEMENT);
}
impl core::fmt::Debug for ElementType {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "ElementType({}, {})", self.def, self.typ)
}
}
impl GroupType {
#[must_use]
pub const fn content_mode(&self) -> ContentMode {
DATATYPES[self.0 as usize].mode
}
}
pub struct AttrDefinitionsIter {
type_id: u16,
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::get_attributes_idx(self.type_id);
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<u16>,
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() {
None
} else {
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::get_sub_element_idx(current_type);
if start_idx + cur_pos < end_idx {
match &SUBELEMENTS[start_idx + cur_pos] {
SubElement::Element(idx) => {
let name = ELEMENTS[*idx as usize].name;
self.indices[depth] += 1;
let ver_idx = ElementType::get_sub_element_ver(current_type);
let version_mask = VERSION_INFO[ver_idx + cur_pos];
let is_named = ElementType::new(*idx).short_name_version_mask().unwrap_or(0);
Some((name, ElementType::new(*idx), 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()
}
}
}
}
impl core::fmt::Debug for CharacterDataSpec {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::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::Float => write!(f, "Double"),
}
}
}
#[must_use]
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
&& 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 = 0x541C_69B2; const HASHCONST2: u32 = 0x3B17_161B;
let mut f1 = 0x3314_3C63_u32;
let mut f2 = 0x88B0_B21E_u32;
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 = u32::from(u16::from_ne_bytes(data[..2].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[2..];
}
if !data.is_empty() {
f1 = f1.rotate_left(5).bitxor(u32::from(data[0])).wrapping_mul(HASHCONST1);
f2 = f2.rotate_left(6).bitxor(u32::from(data[0])).wrapping_mul(HASHCONST2);
}
let g = f1.bitxor(f2);
(g, f1, f2)
}
#[cfg(test)]
mod test {
extern crate std;
use alloc::string::ToString;
use core::str::FromStr;
use num_traits::FromPrimitive;
use std::collections::HashSet;
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(idx) = sub_element {
let name = ELEMENTS[*idx as usize].name;
assert_eq!(name, ElementName::Abs);
assert_eq!(ElementType::new(*idx), 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(idx) = sub_elem_spec {
let multiplicity = ELEMENTS[*idx as usize].multiplicity;
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(), 692);
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_eq!(
AutosarVersion::from_str("AUTOSAR_00052.xsd").unwrap(),
AutosarVersion::Autosar_00052
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_00053.xsd").unwrap(),
AutosarVersion::Autosar_00053
);
assert_eq!(
AutosarVersion::from_str("AUTOSAR_00054.xsd").unwrap(),
AutosarVersion::Autosar_00054
);
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_00052.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_00053.describe().starts_with("AUTOSAR"));
assert!(AutosarVersion::Autosar_00054.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!(AutosarVersion::Autosar_00052.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_00053.filename().ends_with(".xsd"));
assert!(AutosarVersion::Autosar_00054.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 std_restriction() {
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 (machine_type, _) = elements_type.find_sub_element(ElementName::Machine, u32::MAX).unwrap();
let (defapp_timeout_type, _) = machine_type
.find_sub_element(ElementName::DefaultApplicationTimeout, u32::MAX)
.unwrap();
assert_eq!(ar_package_type.std_restriction(), StdRestrict::NotRestricted);
assert_eq!(defapp_timeout_type.std_restriction(), StdRestrict::AdaptivePlatform);
}
#[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);
assert!(ident_type.verify_reference_dest(ref_value));
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; assert_eq!(format!("{:#?}", mult), format!("{:#?}", m2));
let cm = ContentMode::Sequence;
let cm2 = cm; assert_eq!(format!("{:#?}", cm), format!("{:#?}", cm2));
let et = ElementType::ROOT;
let et2 = et; 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; 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; 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::Float;
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,
AutosarVersion::Autosar_00052,
AutosarVersion::Autosar_00053,
AutosarVersion::Autosar_00054,
],
&*expand_version_mask(version_mask)
);
}
#[test]
fn test_version_masks() {
assert_eq!(AutosarVersion::from_u64(0x1), Some(AutosarVersion::Autosar_4_0_1));
assert_eq!(AutosarVersion::from_u64(0x2), Some(AutosarVersion::Autosar_4_0_2));
assert_eq!(AutosarVersion::from_u64(0x4), Some(AutosarVersion::Autosar_4_0_3));
assert_eq!(AutosarVersion::from_u64(0x8), Some(AutosarVersion::Autosar_4_1_1));
assert_eq!(AutosarVersion::from_u64(0x10), Some(AutosarVersion::Autosar_4_1_2));
assert_eq!(AutosarVersion::from_u64(0x20), Some(AutosarVersion::Autosar_4_1_3));
assert_eq!(AutosarVersion::from_u64(0x40), Some(AutosarVersion::Autosar_4_2_1));
assert_eq!(AutosarVersion::from_u64(0x80), Some(AutosarVersion::Autosar_4_2_2));
assert_eq!(AutosarVersion::from_u64(0x100), Some(AutosarVersion::Autosar_4_3_0));
assert_eq!(AutosarVersion::from_u64(0x200), Some(AutosarVersion::Autosar_00042));
assert_eq!(AutosarVersion::from_u64(0x400), Some(AutosarVersion::Autosar_00043));
assert_eq!(AutosarVersion::from_u64(0x800), Some(AutosarVersion::Autosar_00044));
assert_eq!(AutosarVersion::from_u64(0x1000), Some(AutosarVersion::Autosar_00045));
assert_eq!(AutosarVersion::from_u64(0x2000), Some(AutosarVersion::Autosar_00046));
assert_eq!(AutosarVersion::from_u64(0x4000), Some(AutosarVersion::Autosar_00047));
assert_eq!(AutosarVersion::from_u64(0x8000), Some(AutosarVersion::Autosar_00048));
assert_eq!(AutosarVersion::from_u64(0x10000), Some(AutosarVersion::Autosar_00049));
assert_eq!(AutosarVersion::from_u64(0x20000), Some(AutosarVersion::Autosar_00050));
assert_eq!(AutosarVersion::from_u64(0x40000), Some(AutosarVersion::Autosar_00051));
assert_eq!(AutosarVersion::from_u64(0x80000), Some(AutosarVersion::Autosar_00052));
assert_eq!(AutosarVersion::from_u64(0x100000), Some(AutosarVersion::Autosar_00053));
assert_eq!(AutosarVersion::from_u64(0x200000), Some(AutosarVersion::Autosar_00054));
assert_eq!(AutosarVersion::from_u64(0xF), None);
assert_eq!(AutosarVersion::from_i64(0x1), Some(AutosarVersion::Autosar_4_0_1));
assert_eq!(AutosarVersion::from_i64(-1), None);
}
#[cfg(feature = "docstrings")]
#[test]
fn test_docstring() {
let (ar_packages_type, _) = ElementType::ROOT
.find_sub_element(ElementName::ArPackages, u32::MAX)
.unwrap();
let docstring = ar_packages_type.docstring();
assert_eq!(docstring, "This is the top level package in an AUTOSAR model.");
}
}