use alloc::string::String;
use alloc::vec::Vec;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct TypeLibrary {
pub name: String,
pub types: Vec<TypeDef>,
}
impl TypeLibrary {
#[must_use]
pub fn find(&self, name: &str) -> Option<&TypeDef> {
self.types.iter().find(|t| t.name() == name)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TypeDef {
Struct(StructType),
Enum(EnumType),
Union(UnionType),
Typedef(TypedefType),
Bitmask(BitmaskType),
Bitset(BitsetType),
Module(ModuleEntry),
Include(IncludeEntry),
ForwardDcl(ForwardDeclEntry),
Const(ConstEntry),
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct IncludeEntry {
pub file: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ForwardDeclEntry {
pub name: String,
pub kind: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ConstEntry {
pub name: String,
pub type_name: String,
pub value: String,
}
impl TypeDef {
#[must_use]
pub fn name(&self) -> &str {
match self {
Self::Struct(s) => &s.name,
Self::Enum(e) => &e.name,
Self::Union(u) => &u.name,
Self::Typedef(t) => &t.name,
Self::Bitmask(b) => &b.name,
Self::Bitset(b) => &b.name,
Self::Module(m) => &m.name,
Self::Include(i) => &i.file,
Self::ForwardDcl(f) => &f.name,
Self::Const(c) => &c.name,
}
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ModuleEntry {
pub name: String,
pub types: Vec<TypeDef>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Extensibility {
Final,
Appendable,
Mutable,
}
impl Default for Extensibility {
fn default() -> Self {
Self::Appendable
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PrimitiveType {
Boolean,
Octet,
Char,
WChar,
Short,
UShort,
Long,
ULong,
LongLong,
ULongLong,
Float,
Double,
LongDouble,
String,
WString,
}
impl PrimitiveType {
#[must_use]
pub fn from_xml(s: &str) -> Option<Self> {
match s {
"boolean" => Some(Self::Boolean),
"octet" | "byte" => Some(Self::Octet),
"char" => Some(Self::Char),
"wchar" => Some(Self::WChar),
"short" | "int16" => Some(Self::Short),
"ushort" | "uint16" => Some(Self::UShort),
"long" | "int32" => Some(Self::Long),
"ulong" | "uint32" => Some(Self::ULong),
"longlong" | "int64" => Some(Self::LongLong),
"ulonglong" | "uint64" => Some(Self::ULongLong),
"float" | "float32" => Some(Self::Float),
"double" | "float64" => Some(Self::Double),
"longdouble" | "float128" => Some(Self::LongDouble),
"string" => Some(Self::String),
"wstring" => Some(Self::WString),
_ => None,
}
}
#[must_use]
pub fn as_xml(self) -> &'static str {
match self {
Self::Boolean => "boolean",
Self::Octet => "octet",
Self::Char => "char",
Self::WChar => "wchar",
Self::Short => "short",
Self::UShort => "ushort",
Self::Long => "long",
Self::ULong => "ulong",
Self::LongLong => "longlong",
Self::ULongLong => "ulonglong",
Self::Float => "float",
Self::Double => "double",
Self::LongDouble => "longdouble",
Self::String => "string",
Self::WString => "wstring",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TypeRef {
Primitive(PrimitiveType),
Named(String),
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct StructType {
pub name: String,
pub extensibility: Option<Extensibility>,
pub base_type: Option<String>,
pub members: Vec<StructMember>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StructMember {
pub name: String,
pub type_ref: TypeRef,
pub key: bool,
pub optional: bool,
pub must_understand: bool,
pub id: Option<u32>,
pub string_max_length: Option<u32>,
pub sequence_max_length: Option<u32>,
pub array_dimensions: Vec<u32>,
}
impl Default for StructMember {
fn default() -> Self {
Self {
name: String::new(),
type_ref: TypeRef::Primitive(PrimitiveType::Long),
key: false,
optional: false,
must_understand: false,
id: None,
string_max_length: None,
sequence_max_length: None,
array_dimensions: Vec::new(),
}
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct EnumType {
pub name: String,
pub bit_bound: Option<u32>,
pub enumerators: Vec<EnumLiteral>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct EnumLiteral {
pub name: String,
pub value: Option<i32>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnionType {
pub name: String,
pub discriminator: TypeRef,
pub cases: Vec<UnionCase>,
}
impl Default for UnionType {
fn default() -> Self {
Self {
name: String::new(),
discriminator: TypeRef::Primitive(PrimitiveType::Long),
cases: Vec::new(),
}
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct UnionCase {
pub discriminators: Vec<UnionDiscriminator>,
pub member: StructMember,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UnionDiscriminator {
Value(String),
Default,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypedefType {
pub name: String,
pub type_ref: TypeRef,
pub array_dimensions: Vec<u32>,
pub sequence_max_length: Option<u32>,
pub string_max_length: Option<u32>,
}
impl Default for TypedefType {
fn default() -> Self {
Self {
name: String::new(),
type_ref: TypeRef::Primitive(PrimitiveType::Long),
array_dimensions: Vec::new(),
sequence_max_length: None,
string_max_length: None,
}
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct BitmaskType {
pub name: String,
pub bit_bound: Option<u32>,
pub bit_values: Vec<BitValue>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct BitValue {
pub name: String,
pub position: Option<u32>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct BitsetType {
pub name: String,
pub bit_fields: Vec<BitField>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BitField {
pub name: String,
pub type_ref: TypeRef,
pub mask: String,
}
impl Default for BitField {
fn default() -> Self {
Self {
name: String::new(),
type_ref: TypeRef::Primitive(PrimitiveType::ULong),
mask: String::new(),
}
}
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn primitive_type_roundtrip() {
for p in [
PrimitiveType::Boolean,
PrimitiveType::Octet,
PrimitiveType::Char,
PrimitiveType::WChar,
PrimitiveType::Short,
PrimitiveType::UShort,
PrimitiveType::Long,
PrimitiveType::ULong,
PrimitiveType::LongLong,
PrimitiveType::ULongLong,
PrimitiveType::Float,
PrimitiveType::Double,
PrimitiveType::LongDouble,
PrimitiveType::String,
PrimitiveType::WString,
] {
let s = p.as_xml();
assert_eq!(PrimitiveType::from_xml(s), Some(p));
}
}
#[test]
fn primitive_aliases() {
assert_eq!(PrimitiveType::from_xml("int32"), Some(PrimitiveType::Long));
assert_eq!(PrimitiveType::from_xml("byte"), Some(PrimitiveType::Octet));
assert_eq!(
PrimitiveType::from_xml("uint16"),
Some(PrimitiveType::UShort)
);
}
#[test]
fn extensibility_default_appendable() {
assert_eq!(Extensibility::default(), Extensibility::Appendable);
}
#[test]
fn typedef_name_lookup() {
let lib = TypeLibrary {
name: "L".into(),
types: alloc::vec![TypeDef::Typedef(TypedefType {
name: "Velocity".into(),
..Default::default()
})],
};
assert!(lib.find("Velocity").is_some());
assert!(lib.find("Missing").is_none());
}
}