mod builder;
pub use builder::Builder;
use ltk_hash::{BinHash, ReadBytesExt as _, WriteBytesExt as _};
use std::io;
use indexmap::IndexMap;
use ltk_io_ext::{measure, window_at};
use crate::{
property::NoMeta,
traits::{ReaderExt as _, WriterExt as _},
};
use super::super::{Error, PropertyValueEnum};
use byteorder::{ReadBytesExt as _, WriteBytesExt as _, LE};
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
serde(bound = "for <'dee> M: serde::Serialize + serde::Deserialize<'dee>")
)]
#[derive(Debug, Clone, PartialEq, Default)]
pub struct BinObject<M = NoMeta> {
pub path_hash: BinHash,
pub class_hash: BinHash,
pub properties: IndexMap<BinHash, PropertyValueEnum<M>>,
}
impl<M> BinObject<M> {
pub fn new(path_hash: impl Into<BinHash>, class_hash: impl Into<BinHash>) -> Self {
Self {
path_hash: path_hash.into(),
class_hash: class_hash.into(),
properties: IndexMap::default(),
}
}
pub fn builder(
path_hash: impl Into<BinHash>,
class_hash: impl Into<BinHash>,
) -> builder::Builder<M> {
builder::Builder::<M>::new(path_hash, class_hash)
}
pub fn from_reader<R: io::Read + io::Seek + ?Sized>(
reader: &mut R,
class_hash: BinHash,
legacy: bool,
) -> Result<Self, Error>
where
M: Default,
{
let size = reader.read_u32::<LE>()?;
let (real_size, value) = measure(reader, |reader| {
let path_hash = reader.read_bin_hash::<LE>()?;
let prop_count = reader.read_u16::<LE>()? as usize;
let mut properties = IndexMap::with_capacity(prop_count);
for _ in 0..prop_count {
let (name_hash, value) = reader.read_property::<M>(legacy)?;
properties.insert(name_hash, value);
}
Ok::<_, Error>(Self {
path_hash,
class_hash,
properties,
})
})?;
if size as u64 != real_size {
return Err(Error::InvalidSize(size as _, real_size));
}
Ok(value)
}
pub fn to_writer<W: io::Write + io::Seek + ?Sized>(&self, writer: &mut W) -> io::Result<()>
where
M: Clone,
{
let size_pos = writer.stream_position()?;
writer.write_u32::<LE>(0)?;
let (size, _) = measure(writer, |writer| {
writer.write_bin_hash::<LE>(self.path_hash)?;
writer.write_u16::<LE>(self.properties.len() as _)?;
for (name_hash, value) in self.properties.iter() {
writer.write_property(*name_hash, value)?;
}
Ok::<_, io::Error>(())
})?;
window_at(writer, size_pos, |writer| writer.write_u32::<LE>(size as _))?;
Ok(())
}
#[must_use]
#[inline(always)]
pub fn len(&self) -> usize {
self.properties.len()
}
#[must_use]
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.properties.is_empty()
}
#[must_use]
#[inline(always)]
pub fn get_property(&self, name_hash: BinHash) -> Option<&PropertyValueEnum<M>> {
self.properties.get(&name_hash)
}
#[must_use]
#[inline(always)]
pub fn get_property_mut(&mut self, name_hash: BinHash) -> Option<&mut PropertyValueEnum<M>> {
self.properties.get_mut(&name_hash)
}
#[must_use]
#[inline(always)]
pub fn contains_property(&self, name_hash: BinHash) -> bool {
self.properties.contains_key(&name_hash)
}
#[inline(always)]
pub fn insert(
&mut self,
name_hash: BinHash,
value: impl Into<PropertyValueEnum<M>>,
) -> Option<PropertyValueEnum<M>> {
self.properties.insert(name_hash, value.into())
}
pub fn remove_property(&mut self, name_hash: BinHash) -> Option<PropertyValueEnum<M>> {
self.properties.shift_remove(&name_hash)
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = (&BinHash, &PropertyValueEnum<M>)> {
self.properties.iter()
}
#[inline]
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&BinHash, &mut PropertyValueEnum<M>)> {
self.properties.iter_mut()
}
}
impl<'a, M> IntoIterator for &'a BinObject<M> {
type Item = (&'a BinHash, &'a PropertyValueEnum<M>);
type IntoIter = indexmap::map::Iter<'a, BinHash, PropertyValueEnum<M>>;
fn into_iter(self) -> Self::IntoIter {
self.properties.iter()
}
}
impl<'a, M> IntoIterator for &'a mut BinObject<M> {
type Item = (&'a BinHash, &'a mut PropertyValueEnum<M>);
type IntoIter = indexmap::map::IterMut<'a, BinHash, PropertyValueEnum<M>>;
fn into_iter(self) -> Self::IntoIter {
self.properties.iter_mut()
}
}
impl<M> IntoIterator for BinObject<M> {
type Item = (BinHash, PropertyValueEnum<M>);
type IntoIter = indexmap::map::IntoIter<BinHash, PropertyValueEnum<M>>;
fn into_iter(self) -> Self::IntoIter {
self.properties.into_iter()
}
}