|
@@ -536,6 +536,10 @@ impl<'l> Iterator for LayoutChildIter<'l> {
|
|
|
}
|
|
|
|
|
|
/// Accessor trait for a struct that stores edge information for the layout tree.
|
|
|
+///
|
|
|
+/// This trait accepts a tag type parameter to allow a single struct to store multiple layout nodes
|
|
|
+/// with internal edges. Use a `Tag` type of `()` or similar to denote a struct that only
|
|
|
+/// stores a single layout node.
|
|
|
pub trait LayoutTreeNode<Tag: 'static> {
|
|
|
fn current_node(&self) -> &LayoutNode;
|
|
|
fn child_count(&self) -> usize;
|
|
@@ -562,6 +566,22 @@ fn child_dispatch<'l, Tag: 'static>(dynptr: DynPtr, ndx: usize) -> Option<Layout
|
|
|
///
|
|
|
/// Use this struct if you wish to accept arbitrary [`LayoutNode`]s and require information about
|
|
|
/// the layout tree as well.
|
|
|
+///
|
|
|
+/// <details><summary>Implementation details</summary>
|
|
|
+///
|
|
|
+/// `LayoutNodeAccess` is currently implemented with some unsafe code under the hood due to
|
|
|
+/// limitations of the Rust type system. Specifically, this type has three goals:
|
|
|
+/// 1. Avoid being a generic type for ease of use
|
|
|
+/// 2. Represent [`LayoutTreeNode`] instances with arbitrary tags
|
|
|
+/// 3. For performance reasons, avoid dynamic allocation: all storage should be interior to the type
|
|
|
+///
|
|
|
+/// The most obvious way to implement this type is by storing several functions as e.g. `Box<Fn() ->
|
|
|
+/// usize>` to proxy the methods in the tagged `LayoutTreeNode` instance, but this trivially fails
|
|
|
+/// goal #3. The current implementation stores a copy of the instance and the vtable pointer to
|
|
|
+/// perform dynamic dispatch directly, which maintains type-safety invariants because the only
|
|
|
+/// varying parameter is the tag type.
|
|
|
+/// </details>
|
|
|
+
|
|
|
#[derive(Clone, Copy)]
|
|
|
pub struct LayoutNodeAccess<'l> {
|
|
|
current_node_func: fn(DynPtr) -> &'l LayoutNode,
|