use std::fmt;
use glam::{Mat4, Vec2, Vec3, Vec4};
use ltk_hash::{BinHash, HashValue, WadHash};
use ltk_primitives::Color;
use crate::{
property::Kind,
stream::{
layout::Cursor,
view::{copy_views, find_property, Properties, PropertyView},
},
Error,
};
pub enum ValueView<'a> {
None,
Bool(bool),
I8(i8),
U8(u8),
I16(i16),
U16(u16),
I32(i32),
U32(u32),
I64(i64),
U64(u64),
F32(f32),
Vector2(Vec2),
Vector3(Vec3),
Vector4(Vec4),
Matrix44(Mat4),
Color(Color<u8>),
String(&'a str),
Hash(HashValue),
WadChunkLink(WadHash),
ObjectLink(BinHash),
BitBool(bool),
Container(ContainerView<'a>),
UnorderedContainer(ContainerView<'a>),
Optional(OptionalView<'a>),
Map(MapView<'a>),
Struct(StructView<'a>),
Embedded(StructView<'a>),
}
impl<'a> ValueView<'a> {
pub(crate) fn read(cur: &mut Cursor<'a>, kind: Kind) -> Result<Self, Error> {
use Kind as K;
Ok(match kind {
K::None => Self::None,
K::Bool => Self::Bool(cur.bool()?),
K::BitBool => Self::BitBool(cur.bool()?),
K::I8 => Self::I8(cur.i8()?),
K::U8 => Self::U8(cur.u8()?),
K::I16 => Self::I16(cur.i16()?),
K::U16 => Self::U16(cur.u16()?),
K::I32 => Self::I32(cur.i32()?),
K::U32 => Self::U32(cur.u32()?),
K::I64 => Self::I64(cur.i64()?),
K::U64 => Self::U64(cur.u64()?),
K::F32 => Self::F32(cur.f32()?),
K::Vector2 => Self::Vector2(cur.vec2()?),
K::Vector3 => Self::Vector3(cur.vec3()?),
K::Vector4 => Self::Vector4(cur.vec4()?),
K::Matrix44 => Self::Matrix44(cur.mat4_row_major()?),
K::Color => Self::Color(cur.color_u8()?),
K::String => Self::String(cur.str_u16()?),
K::Hash => Self::Hash(cur.hash_value()?),
K::WadChunkLink => Self::WadChunkLink(cur.wad_hash()?),
K::ObjectLink => Self::ObjectLink(cur.bin_hash()?),
K::Container => Self::Container(ContainerView::read(cur)?),
K::UnorderedContainer => Self::UnorderedContainer(ContainerView::read(cur)?),
K::Optional => Self::Optional(OptionalView::read(cur)?),
K::Map => Self::Map(MapView::read(cur)?),
K::Struct => Self::Struct(StructView::read(cur)?),
K::Embedded => Self::Embedded(StructView::read(cur)?),
})
}
#[must_use]
pub fn kind(&self) -> Kind {
match self {
Self::None => Kind::None,
Self::Bool(_) => Kind::Bool,
Self::I8(_) => Kind::I8,
Self::U8(_) => Kind::U8,
Self::I16(_) => Kind::I16,
Self::U16(_) => Kind::U16,
Self::I32(_) => Kind::I32,
Self::U32(_) => Kind::U32,
Self::I64(_) => Kind::I64,
Self::U64(_) => Kind::U64,
Self::F32(_) => Kind::F32,
Self::Vector2(_) => Kind::Vector2,
Self::Vector3(_) => Kind::Vector3,
Self::Vector4(_) => Kind::Vector4,
Self::Matrix44(_) => Kind::Matrix44,
Self::Color(_) => Kind::Color,
Self::String(_) => Kind::String,
Self::Hash(_) => Kind::Hash,
Self::WadChunkLink(_) => Kind::WadChunkLink,
Self::ObjectLink(_) => Kind::ObjectLink,
Self::BitBool(_) => Kind::BitBool,
Self::Container(_) => Kind::Container,
Self::UnorderedContainer(_) => Kind::UnorderedContainer,
Self::Optional(_) => Kind::Optional,
Self::Map(_) => Kind::Map,
Self::Struct(_) => Kind::Struct,
Self::Embedded(_) => Kind::Embedded,
}
}
}
impl fmt::Debug for ValueView<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
macro_rules! leaf {
($name:literal, $value:expr) => {
f.debug_tuple($name).field($value).finish()
};
}
match self {
Self::None => f.write_str("None"),
Self::Bool(v) => leaf!("Bool", v),
Self::I8(v) => leaf!("I8", v),
Self::U8(v) => leaf!("U8", v),
Self::I16(v) => leaf!("I16", v),
Self::U16(v) => leaf!("U16", v),
Self::I32(v) => leaf!("I32", v),
Self::U32(v) => leaf!("U32", v),
Self::I64(v) => leaf!("I64", v),
Self::U64(v) => leaf!("U64", v),
Self::F32(v) => leaf!("F32", v),
Self::Vector2(v) => leaf!("Vector2", v),
Self::Vector3(v) => leaf!("Vector3", v),
Self::Vector4(v) => leaf!("Vector4", v),
Self::Matrix44(v) => leaf!("Matrix44", v),
Self::Color(v) => leaf!("Color", v),
Self::String(v) => leaf!("String", v),
Self::Hash(v) => leaf!("Hash", v),
Self::WadChunkLink(v) => leaf!("WadChunkLink", v),
Self::ObjectLink(v) => leaf!("ObjectLink", v),
Self::BitBool(v) => leaf!("BitBool", v),
Self::Container(v) => leaf!("Container", v),
Self::UnorderedContainer(v) => leaf!("UnorderedContainer", v),
Self::Optional(v) => leaf!("Optional", v),
Self::Map(v) => leaf!("Map", v),
Self::Struct(v) => leaf!("Struct", v),
Self::Embedded(v) => leaf!("Embedded", v),
}
}
}
pub struct ContainerView<'a> {
item_kind: Kind,
len: u32,
items: Cursor<'a>,
}
impl<'a> ContainerView<'a> {
fn read(cur: &mut Cursor<'a>) -> Result<Self, Error> {
let item_kind = cur.item_kind()?;
let size = cur.u32()? as usize;
let mut items = cur.sub(size)?;
let len = items.u32()?;
Ok(Self {
item_kind,
len,
items,
})
}
#[must_use]
pub fn item_kind(&self) -> Kind {
self.item_kind
}
#[must_use]
pub fn len(&self) -> u32 {
self.len
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub(crate) fn cursors(&self) -> ItemCursors<'a> {
ItemCursors {
cur: self.items,
remaining: self.len,
item_kind: self.item_kind,
}
}
pub fn iter(&self) -> ContainerItems<'a> {
ContainerItems {
cur: self.items,
remaining: self.len,
item_kind: self.item_kind,
}
}
pub fn get(&self, index: u32) -> Result<Option<ValueView<'a>>, Error> {
if index >= self.len {
return Ok(None);
}
let mut cur = self.items;
let width = match self.item_kind {
Kind::Hash => Some(cur.hash_width().bytes()),
kind => kind.fixed_width(),
};
match width {
Some(width) => cur.skip(width.saturating_mul(index as usize))?,
None => {
for _ in 0..index {
cur.skip_value(self.item_kind)?;
}
}
}
ValueView::read(&mut cur, self.item_kind).map(Some)
}
}
impl<'a> IntoIterator for &ContainerView<'a> {
type Item = Result<ValueView<'a>, Error>;
type IntoIter = ContainerItems<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl fmt::Debug for ContainerView<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ContainerView")
.field("item_kind", &self.item_kind)
.field("len", &self.len)
.finish()
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Debug, Clone, Copy)]
pub(crate) struct ItemCursors<'a> {
cur: Cursor<'a>,
remaining: u32,
item_kind: Kind,
}
impl<'a> Iterator for ItemCursors<'a> {
type Item = Result<Cursor<'a>, Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
self.remaining -= 1;
let at = self.cur;
Some(match self.cur.skip_value(self.item_kind) {
Ok(()) => Ok(at),
Err(error) => {
self.remaining = 0;
Err(error)
}
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining as usize, Some(self.remaining as usize))
}
}
impl std::iter::FusedIterator for ItemCursors<'_> {}
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Debug, Clone, Copy)]
pub(crate) struct EntryCursors<'a> {
cur: Cursor<'a>,
remaining: u32,
key_kind: Kind,
value_kind: Kind,
}
impl<'a> EntryCursors<'a> {
fn skip_entry(&mut self) -> Result<(Cursor<'a>, Cursor<'a>), Error> {
let key = self.cur;
self.cur.skip_value(self.key_kind)?;
let value = self.cur;
self.cur.skip_value(self.value_kind)?;
Ok((key, value))
}
}
impl<'a> Iterator for EntryCursors<'a> {
type Item = Result<(Cursor<'a>, Cursor<'a>), Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
self.remaining -= 1;
Some(match self.skip_entry() {
Ok(entry) => Ok(entry),
Err(error) => {
self.remaining = 0;
Err(error)
}
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining as usize, Some(self.remaining as usize))
}
}
impl std::iter::FusedIterator for EntryCursors<'_> {}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ContainerItems<'a> {
cur: Cursor<'a>,
remaining: u32,
item_kind: Kind,
}
impl<'a> Iterator for ContainerItems<'a> {
type Item = Result<ValueView<'a>, Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
self.remaining -= 1;
Some(match ValueView::read(&mut self.cur, self.item_kind) {
Ok(value) => Ok(value),
Err(error) => {
self.remaining = 0;
Err(error)
}
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining as usize, Some(self.remaining as usize))
}
}
impl std::iter::FusedIterator for ContainerItems<'_> {}
impl Clone for ContainerItems<'_> {
fn clone(&self) -> Self {
Self {
cur: self.cur,
remaining: self.remaining,
item_kind: self.item_kind,
}
}
}
impl fmt::Debug for ContainerItems<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ContainerItems")
.field("item_kind", &self.item_kind)
.field("remaining", &self.remaining)
.finish()
}
}
pub struct MapView<'a> {
key_kind: Kind,
value_kind: Kind,
len: u32,
entries: Cursor<'a>,
}
impl<'a> MapView<'a> {
fn read(cur: &mut Cursor<'a>) -> Result<Self, Error> {
let key_kind = cur.key_kind()?;
let value_kind = cur.item_kind()?;
let size = cur.u32()? as usize;
let mut entries = cur.sub(size)?;
let len = entries.u32()?;
Ok(Self {
key_kind,
value_kind,
len,
entries,
})
}
#[must_use]
pub fn key_kind(&self) -> Kind {
self.key_kind
}
#[must_use]
pub fn value_kind(&self) -> Kind {
self.value_kind
}
#[must_use]
pub fn len(&self) -> u32 {
self.len
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub(crate) fn cursors(&self) -> EntryCursors<'a> {
EntryCursors {
cur: self.entries,
remaining: self.len,
key_kind: self.key_kind,
value_kind: self.value_kind,
}
}
pub fn iter(&self) -> MapEntries<'a> {
MapEntries {
cur: self.entries,
remaining: self.len,
key_kind: self.key_kind,
value_kind: self.value_kind,
}
}
}
impl<'a> IntoIterator for &MapView<'a> {
type Item = Result<(ValueView<'a>, ValueView<'a>), Error>;
type IntoIter = MapEntries<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl fmt::Debug for MapView<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MapView")
.field("key_kind", &self.key_kind)
.field("value_kind", &self.value_kind)
.field("len", &self.len)
.finish()
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct MapEntries<'a> {
cur: Cursor<'a>,
remaining: u32,
key_kind: Kind,
value_kind: Kind,
}
impl<'a> MapEntries<'a> {
fn read_entry(&mut self) -> Result<(ValueView<'a>, ValueView<'a>), Error> {
let key = ValueView::read(&mut self.cur, self.key_kind)?;
let value = ValueView::read(&mut self.cur, self.value_kind)?;
Ok((key, value))
}
}
impl<'a> Iterator for MapEntries<'a> {
type Item = Result<(ValueView<'a>, ValueView<'a>), Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
self.remaining -= 1;
Some(match self.read_entry() {
Ok(entry) => Ok(entry),
Err(error) => {
self.remaining = 0;
Err(error)
}
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining as usize, Some(self.remaining as usize))
}
}
impl std::iter::FusedIterator for MapEntries<'_> {}
impl Clone for MapEntries<'_> {
fn clone(&self) -> Self {
Self {
cur: self.cur,
remaining: self.remaining,
key_kind: self.key_kind,
value_kind: self.value_kind,
}
}
}
impl fmt::Debug for MapEntries<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MapEntries")
.field("key_kind", &self.key_kind)
.field("value_kind", &self.value_kind)
.field("remaining", &self.remaining)
.finish()
}
}
pub struct OptionalView<'a> {
item_kind: Kind,
value: Option<Cursor<'a>>,
}
impl<'a> OptionalView<'a> {
fn read(cur: &mut Cursor<'a>) -> Result<Self, Error> {
let item_kind = cur.item_kind()?;
let value = match cur.bool()? {
true => Some(cur.sub_value(item_kind)?),
false => None,
};
Ok(Self { item_kind, value })
}
#[must_use]
pub fn item_kind(&self) -> Kind {
self.item_kind
}
#[must_use]
pub fn is_some(&self) -> bool {
self.value.is_some()
}
#[must_use]
pub fn is_none(&self) -> bool {
self.value.is_none()
}
pub(crate) fn cursor(&self) -> Option<Cursor<'a>> {
self.value
}
pub fn get(&self) -> Result<Option<ValueView<'a>>, Error> {
match self.value {
Some(mut value) => ValueView::read(&mut value, self.item_kind).map(Some),
None => Ok(None),
}
}
}
impl fmt::Debug for OptionalView<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OptionalView")
.field("item_kind", &self.item_kind)
.field("is_some", &self.is_some())
.finish()
}
}
pub struct StructView<'a> {
class_hash: BinHash,
property_count: u16,
properties: Cursor<'a>,
}
impl<'a> StructView<'a> {
fn read(cur: &mut Cursor<'a>) -> Result<Self, Error> {
let class_hash = cur.bin_hash()?;
if *class_hash == 0 {
return Ok(Self {
class_hash,
property_count: 0,
properties: Cursor::new(&[], cur.numbering()),
});
}
let size = cur.u32()? as usize;
let mut properties = cur.sub(size)?;
let property_count = properties.u16()?;
Ok(Self {
class_hash,
property_count,
properties,
})
}
pub(crate) fn from_parts(class_hash: BinHash, count: u16, properties: Cursor<'a>) -> Self {
Self {
class_hash,
property_count: count,
properties,
}
}
#[must_use]
pub fn class_hash(&self) -> BinHash {
self.class_hash
}
#[must_use]
pub fn property_count(&self) -> u16 {
self.property_count
}
pub fn properties(&self) -> Properties<'a> {
Properties::new(self.properties, self.property_count)
}
pub fn property(
&self,
name_hash: impl Into<BinHash>,
) -> Result<Option<PropertyView<'a>>, Error> {
find_property(self.properties(), name_hash.into())
}
}
impl fmt::Debug for StructView<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StructView")
.field("class_hash", &self.class_hash)
.field("property_count", &self.property_count)
.finish()
}
}
copy_views!(ValueView, ContainerView, MapView, OptionalView, StructView,);