use std::fmt;
use ltk_hash::BinHash;
use super::{
tree::{sealed::Sealed, ChildSegment, Declaration, Leaf, TreeKind as _, TreeNode, TreeValue},
Error,
};
use crate::{
property::{values, Kind},
stream::{
layout::Cursor,
owned,
view::value::{EntryCursors, ItemCursors},
Properties, PropertyView, StructView, ValueView,
},
PropertyValueEnum,
};
impl Sealed for RawValue<'_> {}
impl Sealed for StructView<'_> {}
pub struct RawValue<'a> {
kind: Kind,
at: Cursor<'a>,
}
impl Copy for RawValue<'_> {}
impl Clone for RawValue<'_> {
fn clone(&self) -> Self {
*self
}
}
impl fmt::Debug for RawValue<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RawValue")
.field("kind", &self.kind)
.field("bytes", &self.at.rest().len())
.finish()
}
}
impl<'a> RawValue<'a> {
fn new(kind: Kind, at: Cursor<'a>) -> Self {
Self { kind, at }
}
fn property(property: PropertyView<'a>) -> Self {
Self::new(property.kind(), property.cursor())
}
pub fn value_view(&self) -> Result<ValueView<'a>, Error> {
let mut at = self.at;
ValueView::read(&mut at, self.kind)
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ViewProperties<'a> {
inner: Properties<'a>,
}
impl<'a> Iterator for ViewProperties<'a> {
type Item = Result<(BinHash, RawValue<'a>), Error>;
fn next(&mut self) -> Option<Self::Item> {
let property = self.inner.next()?;
Some(property.map(|p| (p.name_hash(), RawValue::property(p))))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl std::iter::FusedIterator for ViewProperties<'_> {}
impl fmt::Debug for ViewProperties<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ViewProperties")
.field("inner", &self.inner)
.finish()
}
}
impl<'a> TreeNode<'a> for StructView<'a> {
type Value = RawValue<'a>;
type Properties = ViewProperties<'a>;
fn class_hash(&self) -> BinHash {
StructView::class_hash(self)
}
fn properties(&self) -> Self::Properties {
ViewProperties {
inner: StructView::properties(self),
}
}
fn get(&self, field: BinHash) -> Result<Option<Self::Value>, Error> {
Ok(StructView::property(self, field)?.map(RawValue::property))
}
fn to_struct(&self) -> Result<values::Struct, Error> {
Ok(values::Struct {
class_hash: StructView::class_hash(self),
properties: TreeNode::properties(self)
.map(|property| {
let (field, value) = property?;
Ok((field, value.to_value()?))
})
.collect::<Result<_, Error>>()?,
})
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ViewChildren<'a> {
inner: ViewChildrenInner<'a>,
}
enum ViewChildrenInner<'a> {
Items {
items: ItemCursors<'a>,
item_kind: Kind,
index: usize,
},
Optional {
value: Option<Cursor<'a>>,
item_kind: Kind,
},
Entries {
entries: EntryCursors<'a>,
key_kind: Kind,
value_kind: Kind,
},
Empty,
}
impl<'a> Iterator for ViewChildren<'a> {
type Item = Result<(ChildSegment<RawValue<'a>>, RawValue<'a>), Error>;
fn next(&mut self) -> Option<Self::Item> {
match &mut self.inner {
ViewChildrenInner::Items {
items,
item_kind,
index,
} => {
let item = items.next()?;
let segment = ChildSegment::Index(*index);
*index += 1;
Some(item.map(|at| (segment, RawValue::new(*item_kind, at))))
}
ViewChildrenInner::Optional { value, item_kind } => value
.take()
.map(|at| Ok((ChildSegment::Index(0), RawValue::new(*item_kind, at)))),
ViewChildrenInner::Entries {
entries,
key_kind,
value_kind,
} => {
let entry = entries.next()?;
Some(entry.map(|(key, value)| {
(
ChildSegment::Key(RawValue::new(*key_kind, key)),
RawValue::new(*value_kind, value),
)
}))
}
ViewChildrenInner::Empty => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match &self.inner {
ViewChildrenInner::Items { items, .. } => items.size_hint(),
ViewChildrenInner::Optional { value, .. } => {
let n = usize::from(value.is_some());
(n, Some(n))
}
ViewChildrenInner::Entries { entries, .. } => entries.size_hint(),
ViewChildrenInner::Empty => (0, Some(0)),
}
}
}
impl std::iter::FusedIterator for ViewChildren<'_> {}
impl fmt::Debug for ViewChildren<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (kind, remaining) = match &self.inner {
ViewChildrenInner::Items { items, .. } => ("items", items.size_hint().0),
ViewChildrenInner::Optional { value, .. } => ("optional", usize::from(value.is_some())),
ViewChildrenInner::Entries { entries, .. } => ("entries", entries.size_hint().0),
ViewChildrenInner::Empty => ("empty", 0),
};
f.debug_struct("ViewChildren")
.field("kind", &kind)
.field("remaining", &remaining)
.finish()
}
}
impl<'a> TreeValue<'a> for RawValue<'a> {
type Node = StructView<'a>;
type Children = ViewChildren<'a>;
fn kind(&self) -> Kind {
self.kind
}
fn declaration(&self) -> Result<Declaration, Error> {
let mut declaration = Declaration::bare(self.kind());
if !declaration.kind.is_node() && !declaration.kind.is_container() {
return Ok(declaration);
}
match self.value_view()? {
ValueView::Struct(node) | ValueView::Embedded(node) => {
declaration.class = Some(node.class_hash());
}
ValueView::Container(items) | ValueView::UnorderedContainer(items) => {
declaration.item_kind = Some(items.item_kind());
declaration.count = Some(items.len() as usize);
}
ValueView::Optional(option) => {
declaration.item_kind = Some(option.item_kind());
declaration.count = Some(usize::from(option.is_some()));
}
ValueView::Map(map) => {
declaration.item_kind = Some(map.value_kind());
declaration.key_kind = Some(map.key_kind());
declaration.count = Some(map.len() as usize);
}
_ => {}
}
Ok(declaration)
}
fn as_node(&self) -> Result<Option<Self::Node>, Error> {
if !self.kind().is_node() {
return Ok(None);
}
Ok(match self.value_view()? {
ValueView::Struct(s) | ValueView::Embedded(s) if *s.class_hash() != 0 => Some(s),
_ => None,
})
}
fn children(&self) -> Result<Self::Children, Error> {
let children = |inner| ViewChildren { inner };
if !self.kind().is_container() {
return Ok(children(ViewChildrenInner::Empty));
}
let inner = match self.value_view()? {
ValueView::Container(c) | ValueView::UnorderedContainer(c) => {
ViewChildrenInner::Items {
items: c.cursors(),
item_kind: c.item_kind(),
index: 0,
}
}
ValueView::Optional(o) => ViewChildrenInner::Optional {
value: o.cursor(),
item_kind: o.item_kind(),
},
ValueView::Map(m) => ViewChildrenInner::Entries {
entries: m.cursors(),
key_kind: m.key_kind(),
value_kind: m.value_kind(),
},
_ => ViewChildrenInner::Empty,
};
Ok(children(inner))
}
fn as_leaf(&self) -> Result<Option<Leaf<'a>>, Error> {
Ok(Some(match self.value_view()? {
ValueView::None => Leaf::None,
ValueView::Bool(v) => Leaf::Bool(v),
ValueView::I8(v) => Leaf::I8(v),
ValueView::U8(v) => Leaf::U8(v),
ValueView::I16(v) => Leaf::I16(v),
ValueView::U16(v) => Leaf::U16(v),
ValueView::I32(v) => Leaf::I32(v),
ValueView::U32(v) => Leaf::U32(v),
ValueView::I64(v) => Leaf::I64(v),
ValueView::U64(v) => Leaf::U64(v),
ValueView::F32(v) => Leaf::F32(v),
ValueView::Vector2(v) => Leaf::Vector2(v),
ValueView::Vector3(v) => Leaf::Vector3(v),
ValueView::Vector4(v) => Leaf::Vector4(v),
ValueView::Matrix44(v) => Leaf::Matrix44(v),
ValueView::Color(v) => Leaf::Color(v),
ValueView::String(v) => Leaf::String(v),
ValueView::Hash(v) => Leaf::Hash(v),
ValueView::WadChunkLink(v) => Leaf::File(v),
ValueView::ObjectLink(v) => Leaf::Link(v),
ValueView::BitBool(v) => Leaf::Flag(v),
ValueView::Container(_)
| ValueView::UnorderedContainer(_)
| ValueView::Optional(_)
| ValueView::Map(_)
| ValueView::Struct(_)
| ValueView::Embedded(_) => return Ok(None),
}))
}
fn to_value(&self) -> Result<PropertyValueEnum, Error> {
let mut at = self.at;
owned::read_value(&mut at, self.kind)
}
}