use super::traits::{ReaderExt as _, WriterExt as _};
use super::Error;
use byteorder::{ReadBytesExt as _, WriteBytesExt as _, LE};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::io;
pub mod value;
pub use value::PropertyValueEnum;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(
Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IntoPrimitive, TryFromPrimitive,
)]
#[repr(u8)]
pub enum BinPropertyKind {
None = 0,
Bool = 1,
I8 = 2,
U8 = 3,
I16 = 4,
U16 = 5,
I32 = 6,
U32 = 7,
I64 = 8,
U64 = 9,
F32 = 10,
Vector2 = 11,
Vector3 = 12,
Vector4 = 13,
Matrix44 = 14,
Color = 15,
String = 16,
Hash = 17,
WadChunkLink = 18,
Container = 128,
UnorderedContainer = 128 | 1,
Struct = 128 | 2,
Embedded = 128 | 3,
ObjectLink = 128 | 4,
Optional = 128 | 5,
Map = 128 | 6,
BitBool = 128 | 7,
}
impl BinPropertyKind {
pub fn unpack(raw: u8, legacy: bool) -> Result<BinPropertyKind, Error> {
use BinPropertyKind as BPK;
if !legacy {
return Ok(BPK::try_from_primitive(raw)?);
}
let mut fudged = raw;
if fudged >= BPK::WadChunkLink.into() && fudged < BPK::Container.into() {
fudged -= Into::<u8>::into(BPK::WadChunkLink);
fudged |= Into::<u8>::into(BPK::Container);
}
if fudged >= BPK::UnorderedContainer.into() {
fudged += 1;
}
Ok(BinPropertyKind::try_from_primitive(fudged)?)
}
pub fn is_primitive(&self) -> bool {
use BinPropertyKind::*;
matches!(
self,
None | Bool
| I8
| U8
| I16
| U16
| I32
| U32
| I64
| U64
| F32
| Vector2
| Vector3
| Vector4
| Matrix44
| Color
| String
| Hash
| WadChunkLink
)
}
pub fn is_container(&self) -> bool {
use BinPropertyKind::*;
matches!(self, Container | UnorderedContainer | Optional | Map)
}
pub fn read<R: io::Read + std::io::Seek + ?Sized>(
self,
reader: &mut R,
legacy: bool,
) -> Result<PropertyValueEnum, super::Error> {
PropertyValueEnum::from_reader(reader, self, legacy)
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, PartialEq, Debug)]
pub struct BinProperty {
pub name_hash: u32,
#[cfg_attr(feature = "serde", serde(flatten))]
pub value: PropertyValueEnum,
}
use super::traits::PropertyValue as _;
impl BinProperty {
pub fn from_reader<R: io::Read + std::io::Seek + ?Sized>(
reader: &mut R,
legacy: bool,
) -> Result<Self, Error> {
let name_hash = reader.read_u32::<LE>()?;
let kind = reader.read_property_kind(legacy)?;
Ok(Self {
name_hash,
value: PropertyValueEnum::from_reader(reader, kind, legacy)?,
})
}
pub fn to_writer<W: io::Write + std::io::Seek + ?Sized>(
&self,
writer: &mut W,
) -> Result<(), io::Error> {
writer.write_u32::<LE>(self.name_hash)?;
writer.write_property_kind(self.value.kind())?;
self.value.to_writer(writer)?;
Ok(())
}
pub fn size(&self) -> usize {
5 + self.value.size_no_header()
}
}