use crate::format::messages::datatype::{
ByteOrder, CompoundField, CompoundFields as RawCompoundFields, DatatypeClass, DatatypeMessage,
EnumMembers as RawEnumMembers, FloatFields,
};
use std::borrow::Cow;
pub type TypeDescriptor = crate::format::messages::datatype::DatatypeMessage;
#[derive(Debug, Clone)]
pub struct Datatype {
msg: DatatypeMessage,
}
#[derive(Debug, Clone)]
pub struct CompoundFieldView<'a> {
pub raw_name: &'a [u8],
pub name: Cow<'a, str>,
pub byte_offset: usize,
pub size: usize,
pub class: DatatypeClass,
pub byte_order: Option<ByteOrder>,
pub datatype: Datatype,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EnumMemberView<'a> {
pub name: &'a str,
pub value: u64,
}
pub struct CompoundFields<'a> {
inner: RawCompoundFields<'a>,
}
pub struct EnumMembers<'a> {
inner: RawEnumMembers<'a>,
}
impl Datatype {
pub(crate) fn from_message(msg: DatatypeMessage) -> Self {
Self { msg }
}
pub fn enum_create(base: &Datatype) -> crate::Result<Self> {
Ok(Self {
msg: DatatypeMessage::enum_create(base.msg.clone())?,
})
}
pub fn enum_insert(&mut self, name: &str, value: u64) -> crate::Result<()> {
self.msg.enum_insert(name, value)
}
pub fn raw_message_ref(&self) -> &DatatypeMessage {
&self.msg
}
pub fn raw_message(&self) -> DatatypeMessage {
self.msg.clone()
}
pub fn from_descriptor(desc: &TypeDescriptor) -> crate::Result<Self> {
Ok(Self::from_message(desc.clone()))
}
pub fn from_descriptor_owned(desc: TypeDescriptor) -> crate::Result<Self> {
Ok(Self::from_message(desc))
}
pub fn to_descriptor(&self) -> crate::Result<TypeDescriptor> {
Ok(self.raw_message())
}
pub fn to_descriptor_ref(&self) -> &TypeDescriptor {
self.raw_message_ref()
}
pub fn create_plist(&self) -> crate::hl::plist::datatype_create::DatatypeCreate {
crate::hl::plist::datatype_create::DatatypeCreate::from_datatype(self)
}
pub fn native_type(&self) -> Datatype {
self.clone()
}
pub fn pad(&self) -> Option<(u8, u8)> {
match self.msg.class {
DatatypeClass::FixedPoint | DatatypeClass::BitField | DatatypeClass::FloatingPoint => {
let plist = self.create_plist();
Some((plist.low_pad(), plist.high_pad()))
}
_ => None,
}
}
pub fn size(&self) -> usize {
usize::try_from(self.msg.size).unwrap_or(usize::MAX)
}
pub fn class(&self) -> DatatypeClass {
self.msg.class
}
pub fn byte_order(&self) -> Option<ByteOrder> {
self.msg.byte_order()
}
pub fn is_signed(&self) -> Option<bool> {
self.msg.is_signed()
}
pub fn bit_offset(&self) -> Option<u16> {
self.msg.bit_offset()
}
pub fn precision(&self) -> Option<u16> {
self.msg.precision()
}
pub fn is_float(&self) -> bool {
self.msg.class == DatatypeClass::FloatingPoint
}
pub fn float_fields(&self) -> Option<FloatFields> {
self.msg.float_fields()
}
pub fn exponent_bias(&self) -> Option<u32> {
self.msg.exponent_bias()
}
pub fn mantissa_normalization(&self) -> Option<u8> {
self.msg.mantissa_normalization()
}
pub fn internal_padding(&self) -> Option<u8> {
self.msg.internal_padding()
}
pub fn is_integer(&self) -> bool {
self.msg.class == DatatypeClass::FixedPoint
}
pub fn is_string(&self) -> bool {
self.msg.class == DatatypeClass::String
}
pub fn char_set(&self) -> Option<u8> {
self.msg.char_set()
}
pub fn string_padding(&self) -> Option<u8> {
self.msg.string_padding()
}
pub fn is_compound(&self) -> bool {
self.msg.class == DatatypeClass::Compound
}
pub fn is_enum(&self) -> bool {
self.msg.class == DatatypeClass::Enum
}
pub fn is_vlen(&self) -> bool {
self.msg.class == DatatypeClass::VarLen
}
pub fn opaque_tag_str(&self) -> Option<&str> {
self.msg.opaque_tag_str()
}
pub fn opaque_tag(&self) -> Option<String> {
self.opaque_tag_str().map(str::to_string)
}
pub fn reference_type(&self) -> Option<u8> {
self.msg.reference_type()
}
pub fn compound_fields_iter(&self) -> crate::Result<CompoundFields<'_>> {
Ok(CompoundFields {
inner: self.msg.compound_fields_iter()?,
})
}
pub fn compound_fields(&self) -> Option<Vec<CompoundField>> {
let mut fields = Vec::new();
self.compound_fields_into(&mut fields).ok()?;
Some(fields)
}
pub fn compound_fields_into(&self, out: &mut Vec<CompoundField>) -> crate::Result<()> {
let fields = self.msg.compound_fields_iter()?;
out.clear();
out.reserve(fields.len());
for field in fields {
let field = field?;
out.push(CompoundField {
name: field.name.into_owned(),
byte_offset: field.byte_offset,
size: field.size,
class: field.class,
byte_order: field.byte_order,
datatype: Box::new(field.datatype),
});
}
Ok(())
}
pub fn compound_nmembers(&self) -> Option<u16> {
self.msg.compound_nmembers()
}
pub fn member_index(&self, name: &str) -> Option<usize> {
self.compound_fields_iter().ok().and_then(|fields| {
fields.enumerate().find_map(|(index, field)| match field {
Ok(field) if field.name == name => Some(index),
_ => None,
})
})
}
pub fn member_offset(&self, index: usize) -> Option<usize> {
self.compound_fields_iter()
.ok()?
.nth(index)?
.ok()
.map(|field| field.byte_offset)
}
pub fn member_class(&self, index: usize) -> Option<DatatypeClass> {
self.compound_fields_iter()
.ok()?
.nth(index)?
.ok()
.map(|field| field.class)
}
pub fn member_type(&self, index: usize) -> Option<Datatype> {
self.compound_fields_iter()
.ok()?
.nth(index)?
.ok()
.map(|field| field.datatype)
}
pub fn enum_members_iter(&self) -> crate::Result<EnumMembers<'_>> {
Ok(EnumMembers {
inner: self.msg.enum_members_iter()?,
})
}
pub fn enum_members(&self) -> Option<Vec<(String, u64)>> {
let mut members = Vec::new();
self.enum_members_into(&mut members).ok()?;
Some(members)
}
pub fn enum_members_into(&self, out: &mut Vec<(String, u64)>) -> crate::Result<()> {
let members = self.msg.enum_members_iter()?;
out.clear();
out.reserve(members.len());
for member in members {
let member = member?;
out.push((member.name.to_string(), member.value));
}
Ok(())
}
pub fn enum_nameof_ref(&self, value: u64) -> crate::Result<Option<&str>> {
for member in self.msg.enum_members_iter()? {
let member = member?;
if member.value == value {
return Ok(Some(member.name));
}
}
Ok(None)
}
pub fn enum_nameof(&self, value: u64) -> crate::Result<Option<String>> {
self.enum_nameof_ref(value)
.map(|name| name.map(str::to_string))
}
pub fn enum_valueof(&self, name: &str) -> crate::Result<Option<u64>> {
self.msg.enum_valueof(name)
}
pub fn array_dims_iter(
&self,
) -> crate::Result<impl ExactSizeIterator<Item = crate::Result<u64>> + '_> {
self.msg.array_dims_iter()
}
pub fn array_base(&self) -> Option<Datatype> {
self.msg.array_base().ok().map(Datatype::from_message)
}
pub fn array_dims_base(&self) -> Option<(Vec<u64>, Datatype)> {
let mut dims = Vec::new();
self.array_dims_into(&mut dims).ok()?;
let base = self.array_base()?;
Some((dims, base))
}
pub fn array_dims_into(&self, out: &mut Vec<u64>) -> crate::Result<()> {
let dims = self.array_dims_iter()?;
out.clear();
out.reserve(dims.len());
for dim in dims {
out.push(dim?);
}
Ok(())
}
pub fn vlen_base(&self) -> Option<Datatype> {
self.msg
.vlen_base()
.ok()
.flatten()
.map(Datatype::from_message)
}
}
impl<'a> Iterator for CompoundFields<'a> {
type Item = crate::Result<CompoundFieldView<'a>>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|field| {
field.map(|field| CompoundFieldView {
raw_name: field.raw_name,
name: field.name,
byte_offset: field.byte_offset,
size: field.size,
class: field.class,
byte_order: field.byte_order,
datatype: Datatype::from_message(field.datatype),
})
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl ExactSizeIterator for CompoundFields<'_> {}
impl<'a> Iterator for EnumMembers<'a> {
type Item = crate::Result<EnumMemberView<'a>>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|member| {
member.map(|member| EnumMemberView {
name: member.name,
value: member.value,
})
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl ExactSizeIterator for EnumMembers<'_> {}