Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions .scratch/value-walk/issues/01-walk.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ pub trait TreeValue<'a>: Copy + sealed::Sealed {
}

/// A node the walk can visit: a class and properties. Sealed: implemented for the owned
/// tree's node, for `StructView<'a, M>`, and for `ObjectView<'a, M>` as a root.
/// tree's node and for `StructView<'a, M>`. An object's root is walked as a `StructView`
/// over the same bytes.
pub trait TreeNode<'a>: Copy + sealed::Sealed {
type Value: TreeValue<'a, Node = Self>;
type Properties: Iterator<Item = Result<(BinHash, Self::Value), Error>>;
Expand Down Expand Up @@ -97,7 +98,6 @@ impl<'a, M> TreeValue<'a> for &'a PropertyValueEnum<M> { type Node = OwnedNode<'
impl<'a, M: Default> TreeValue<'a> for ValueView<'a, M> { type Node = StructView<'a, M>; /* ... */ }
impl<'a, M> TreeNode<'a> for OwnedNode<'a, M> { type Value = &'a PropertyValueEnum<M>; /* ... */ }
impl<'a, M: Default> TreeNode<'a> for StructView<'a, M> { type Value = ValueView<'a, M>; /* ... */ }
impl<'a, M: Default> TreeNode<'a> for ObjectView<'a, M> { type Value = ValueView<'a, M>; /* ... */ }

/// What a callback answers. `ltk_ritobin::cst::visitor::Visit`'s shape (W21).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
Expand Down Expand Up @@ -132,7 +132,8 @@ pub trait Visitor<'a, V: TreeValue<'a>> {
/// descended on `Continue`.
fn enter_property(&mut self, field: BinHash, value: V, node: &Node<'_, 'a, V>)
-> Result<Visit, Self::Error> { Ok(Visit::Continue) }
/// Once per property descended. Not called for a leaf. Never after an `Abort`.
/// Once per property that holds a node and was entered. Not called for a leaf. Never
/// after an `Abort`.
fn exit_property(&mut self, field: BinHash, value: V, node: &Node<'_, 'a, V>)
-> Result<Visit, Self::Error> { Ok(Visit::Continue) }
}
Expand Down Expand Up @@ -208,14 +209,14 @@ impl<'a, M: Default> ObjectView<'a, M> {
}
impl<R: io::Read + io::Seek, M: Default> ObjectStream<'_, R, M> {
/// `view()?` then `walk`.
pub fn walk<W>(&mut self, visitor: &mut W) -> Result<WalkOutcome, W::Error>
where W: for<'a> Visitor<'a, ValueView<'a, M>>;
pub fn walk<E, W>(&mut self, visitor: &mut W) -> Result<WalkOutcome, E>
where E: From<Error>, W: for<'a> Visitor<'a, ValueView<'a, M>, Error = E>;
}
impl<R: io::Read + io::Seek, M: Default> BinStream<R, M> {
/// Walks every object in file order, one buffered object at a time. Holds one object's
/// bytes at any moment and nothing of the tree.
pub fn walk<W>(&mut self, visitor: &mut W) -> Result<WalkOutcome, W::Error>
where W: for<'a> Visitor<'a, ValueView<'a, M>>;
pub fn walk<E, W>(&mut self, visitor: &mut W) -> Result<WalkOutcome, E>
where E: From<Error>, W: for<'a> Visitor<'a, ValueView<'a, M>, Error = E>;
}
```

Expand Down
2 changes: 2 additions & 0 deletions crates/ltk_meta/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,5 @@ mod error;
pub use error::*;

pub mod traits;

pub mod walk;
36 changes: 36 additions & 0 deletions crates/ltk_meta/src/property/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,42 @@ macro_rules! create_enum {

variants!(create_enum);

impl<M> PropertyValueEnum<M> {
/// Whether entering this value can reach a node.
///
/// True for a `Struct` or `Embedded` whose class hash is not 0, and for a container,
/// optional or map whose item kind [`Kind::is_node`]. An empty optional or container of a
/// node kind answers true: it *can* hold one. A `Struct` or `Embedded` with class 0 is the
/// client's null pointer and holds nothing.
///
/// # Examples
///
/// ```
/// use ltk_meta::{property::values, PropertyKind, PropertyValueEnum};
///
/// let leaf: PropertyValueEnum = values::I32::new(1).into();
/// let null: PropertyValueEnum = values::Struct::default().into();
/// let empty: PropertyValueEnum = values::Optional::empty(PropertyKind::Embedded)?.into();
///
/// assert!(!leaf.holds_node());
/// assert!(!null.holds_node());
/// assert!(empty.holds_node());
/// # Ok::<(), ltk_meta::Error>(())
/// ```
#[must_use]
pub fn holds_node(&self) -> bool {
Comment thread
Crauzer marked this conversation as resolved.
Outdated
match self {
Self::Struct(s) => *s.class_hash != 0,
Self::Embedded(e) => *e.0.class_hash != 0,
Self::Container(c) => c.item_kind().is_node(),
Self::UnorderedContainer(c) => c.0.item_kind().is_node(),
Self::Optional(o) => o.item_kind().is_node(),
Self::Map(m) => m.value_kind().is_node(),
_ => false,
}
}
}

/// A value type that can be borrowed out of a [`PropertyValueEnum`].
///
/// Implemented for every type in [`values`]. It exists so [`PropertyValueEnum::get`] and
Expand Down
22 changes: 22 additions & 0 deletions crates/ltk_meta/src/property/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,28 @@ impl Kind {
)
}

/// Whether a value of this kind is a node: [`Kind::Struct`] or [`Kind::Embedded`].
///
/// The other question - which kinds a value model treats as leaves - is
/// [`Kind::is_primitive`], and the two are not complements: [`Kind::ObjectLink`] and
/// [`Kind::BitBool`] are neither primitive nor a node.
///
/// # Examples
///
/// ```
/// use ltk_meta::PropertyKind;
///
/// assert!(PropertyKind::Struct.is_node());
/// assert!(PropertyKind::Embedded.is_node());
/// assert!(!PropertyKind::ObjectLink.is_node());
/// assert!(!PropertyKind::Container.is_node());
/// ```
#[inline(always)]
#[must_use]
pub fn is_node(self) -> bool {
matches!(self, Kind::Struct | Kind::Embedded)
}

/// Whether this property kind is a container type (container, unordered container, optional, map).
#[inline(always)]
#[must_use]
Expand Down
5 changes: 5 additions & 0 deletions crates/ltk_meta/src/stream/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ impl<'a, M> ObjectView<'a, M> {
find_property(self.properties(), name_hash.into())
}

/// The object as a struct: its class hash and its properties, the path hash left behind.
pub(crate) fn as_struct(&self) -> StructView<'a, M> {
StructView::from_parts(self.class_hash, self.property_count, self.properties)
}

/// The object's raw bytes — its whole declared range, size field included.
///
/// This is the range a byte-exact copy of the object covers, which is what the delta
Expand Down
11 changes: 11 additions & 0 deletions crates/ltk_meta/src/stream/view/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,17 @@ impl<'a, M> StructView<'a, M> {
})
}

/// A view over `count` properties at `properties`, carrying `class_hash`. An object's
/// root as a struct.
pub(crate) fn from_parts(class_hash: BinHash, count: u16, properties: Cursor<'a>) -> Self {
Self {
class_hash,
property_count: count,
properties,
meta: PhantomData,
}
}

/// The class this is an instance of, or `0` for a null pointer.
#[must_use]
pub fn class_hash(&self) -> BinHash {
Expand Down
Loading
Loading