use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TypeKind {
Enum,
Record,
Module,
Interface,
Dispatch,
CoClass,
Alias,
Union,
Unknown(u8),
}
impl TypeKind {
pub fn from_raw(raw: u8) -> Self {
match raw {
0 => TypeKind::Enum,
1 => TypeKind::Record,
2 => TypeKind::Module,
3 => TypeKind::Interface,
4 => TypeKind::Dispatch,
5 => TypeKind::CoClass,
6 => TypeKind::Alias,
7 => TypeKind::Union,
n => TypeKind::Unknown(n),
}
}
}
impl fmt::Display for TypeKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TypeKind::Enum => write!(f, "ENUM"),
TypeKind::Record => write!(f, "RECORD"),
TypeKind::Module => write!(f, "MODULE"),
TypeKind::Interface => write!(f, "INTERFACE"),
TypeKind::Dispatch => write!(f, "DISPATCH"),
TypeKind::CoClass => write!(f, "COCLASS"),
TypeKind::Alias => write!(f, "ALIAS"),
TypeKind::Union => write!(f, "UNION"),
TypeKind::Unknown(n) => write!(f, "UNKNOWN({n})"),
}
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum ConstValue<'a> {
Empty,
Null,
I2(i16),
I4(i32),
R4(f32),
R8(f64),
Cy(i64),
Date(f64),
Bstr(&'a [u8]),
Error(i32),
Bool(bool),
I1(i8),
UI1(u8),
UI2(u16),
UI4(u32),
I8(i64),
UI8(u64),
Int(i32),
UInt(u32),
Void,
Hresult(i32),
Decimal(&'a [u8]),
Filetime(u64),
Raw {
vt: u16,
bits: i32,
},
}
impl fmt::Display for ConstValue<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ConstValue::Empty => write!(f, "<empty>"),
ConstValue::Null => write!(f, "<null>"),
ConstValue::I2(v) => write!(f, "{v}"),
ConstValue::I4(v) => write!(f, "{v}"),
ConstValue::R4(v) => write!(f, "{v}"),
ConstValue::R8(v) => write!(f, "{v}"),
ConstValue::Cy(v) => {
let whole = v / 10000;
let frac = (v % 10000).unsigned_abs();
write!(f, "{whole}.{frac:04}")
}
ConstValue::Date(v) => write!(f, "DATE({v})"),
ConstValue::Bstr(v) => write!(f, "\"{}\"", String::from_utf8_lossy(v)),
ConstValue::Error(v) => write!(f, "ERROR(0x{v:08X})"),
ConstValue::Bool(true) => write!(f, "True"),
ConstValue::Bool(false) => write!(f, "False"),
ConstValue::I1(v) => write!(f, "{v}"),
ConstValue::UI1(v) => write!(f, "{v}"),
ConstValue::UI2(v) => write!(f, "{v}"),
ConstValue::UI4(v) => write!(f, "{v}"),
ConstValue::I8(v) => write!(f, "{v}"),
ConstValue::UI8(v) => write!(f, "{v}"),
ConstValue::Int(v) => write!(f, "{v}"),
ConstValue::UInt(v) => write!(f, "{v}"),
ConstValue::Void => write!(f, "<void>"),
ConstValue::Hresult(v) => write!(f, "0x{v:08X}"),
ConstValue::Decimal(v) => {
write!(f, "DECIMAL(")?;
for (i, b) in v.iter().enumerate() {
if i > 0 {
write!(f, " ")?;
}
write!(f, "{b:02X}")?;
}
write!(f, ")")
}
ConstValue::Filetime(v) => write!(f, "FILETIME(0x{v:016X})"),
ConstValue::Raw { vt, bits } => write!(f, "raw(vt={vt}, 0x{bits:08X})"),
}
}
}
pub fn vt_name(vt: u16) -> &'static str {
match vt {
0 => "void",
2 => "Integer",
3 => "Long",
4 => "Single",
5 => "Double",
6 => "Currency",
7 => "Date",
8 => "String",
9 => "Object",
10 => "SCODE",
11 => "Boolean",
12 => "Variant",
13 => "IUnknown",
16 => "SignedByte",
17 => "Byte",
18 => "UShort",
19 => "ULong",
20 => "LongLong",
21 => "ULongLong",
22 => "Int",
23 => "UInt",
24 => "void",
25 => "HRESULT",
26 => "Ptr",
27 => "SafeArray",
28 => "CArray",
29 => "UserDefined",
_ => "Unknown",
}
}