|
@@ -512,14 +512,14 @@ pub fn dump_tree_json<W: ?Sized + std::io::Write>(
|
|
|
|
|
|
/// Iterator implementation to iterate across children of a LayoutNodeContainer
|
|
|
#[derive(Clone)]
|
|
|
-pub struct LayoutChildIter<'l> {
|
|
|
- lnc: &'l dyn LayoutNodeContainer,
|
|
|
+struct LayoutChildIter<'l> {
|
|
|
+ lna: &'l LayoutNodeAccess<'l>,
|
|
|
next_index: usize,
|
|
|
}
|
|
|
|
|
|
impl<'l> LayoutChildIter<'l> {
|
|
|
- fn new(lnc: &'l dyn LayoutNodeContainer) -> Self {
|
|
|
- Self { lnc, next_index: 0 }
|
|
|
+ fn new(lna: &'l LayoutNodeAccess) -> Self {
|
|
|
+ Self { lna, next_index: 0 }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -528,80 +528,98 @@ impl<'l> Iterator for LayoutChildIter<'l> {
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
let index = self.next_index;
|
|
|
- if index >= self.lnc.layout_child_count() {
|
|
|
+ if index >= self.lna.child_count() {
|
|
|
None
|
|
|
} else {
|
|
|
self.next_index += 1;
|
|
|
- self.lnc.layout_child(index)
|
|
|
+ self.lna.child(index)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/// Wrapper struct to access a [`LayoutNodeContainer`].
|
|
|
+pub trait LayoutTreeNode<Tag: 'static> {
|
|
|
+ fn current_node(&self) -> &LayoutNode;
|
|
|
+ fn child_count(&self) -> usize;
|
|
|
+ fn child(&self, ndx: usize) -> Option<LayoutNodeAccess<'_>>;
|
|
|
+}
|
|
|
+
|
|
|
+const DYNPTR_WIDTH: usize =
|
|
|
+ std::mem::size_of::<&'static dyn LayoutTreeNode<()>>() / std::mem::size_of::<*const ()>();
|
|
|
+type DynPtr = [*const (); DYNPTR_WIDTH];
|
|
|
+
|
|
|
+fn current_node_dispatch<'l, Tag: 'static>(dynptr: DynPtr) -> &'l LayoutNode {
|
|
|
+ unsafe { std::mem::transmute::<_, &'l dyn LayoutTreeNode<Tag>>(dynptr).current_node() }
|
|
|
+}
|
|
|
+
|
|
|
+fn child_count_dispatch<'l, Tag: 'static>(dynptr: DynPtr) -> usize {
|
|
|
+ unsafe { std::mem::transmute::<_, &'l dyn LayoutTreeNode<Tag>>(dynptr).child_count() }
|
|
|
+}
|
|
|
+
|
|
|
+fn child_dispatch<'l, Tag: 'static>(dynptr: DynPtr, ndx: usize) -> Option<LayoutNodeAccess<'l>> {
|
|
|
+ unsafe { std::mem::transmute::<_, &'l dyn LayoutTreeNode<Tag>>(dynptr).child(ndx) }
|
|
|
+}
|
|
|
+
|
|
|
#[derive(Clone, Copy)]
|
|
|
pub struct LayoutNodeAccess<'l> {
|
|
|
- // general problem here:
|
|
|
- // - this needs to be a reference to make the LNA clone/copy easily,
|
|
|
- // - the reference means there needs to be a persistent object,
|
|
|
- // - using the widget as a persistent object means only one level of heirarchy is supported,
|
|
|
- // - so either:
|
|
|
- // a) nodes are stored in some sort of container in the widget, which makes access annoying, or
|
|
|
- // b) LayoutNodeContainer is given a tag type parameter to allow multiple implementations on a single type? this somewhat complicates the LayoutNodeAccess type
|
|
|
- // this could *also* be changed to store a Box<dyn LayoutNodeContainer>, which would allow for a different set of ownership semantics; the result is significantly less efficient as it requires allocations to occur during tree traversal
|
|
|
- // could require each external node linkage source to return a slice of all child nodes?
|
|
|
- // - still runs into boxing requirements
|
|
|
- // could also accept closures that are passed reference to slice of child nodes
|
|
|
- //
|
|
|
- // another possible solution here is to simply return an iterator across children
|
|
|
- // - this does not require an object in quite the same way?
|
|
|
- // - ExactSizeIterator handles most of the functionality nicely
|
|
|
- // - and this way there need not be a single trait impl on the widget type; this allows for a
|
|
|
- // full hierarchy to be specified
|
|
|
- //
|
|
|
- // alternatively, simply provide better mechanism for tree storage / easy node access
|
|
|
- // - simple macro that generates types and impl automatically?
|
|
|
- lnc: &'l dyn LayoutNodeContainer,
|
|
|
+ current_node_func: fn(DynPtr) -> &'l LayoutNode,
|
|
|
+ child_count_func: fn(DynPtr) -> usize,
|
|
|
+ child_func: fn(DynPtr, ndx: usize) -> Option<LayoutNodeAccess<'l>>,
|
|
|
+ dynptr: DynPtr,
|
|
|
}
|
|
|
|
|
|
impl<'l> LayoutNodeAccess<'l> {
|
|
|
- pub fn new(lnc: &'l dyn LayoutNodeContainer) -> Self {
|
|
|
- Self { lnc }
|
|
|
+ pub fn new<Tag: 'static>(from: &'l dyn LayoutTreeNode<Tag>) -> Self {
|
|
|
+ assert_eq!(
|
|
|
+ std::mem::size_of::<&dyn LayoutTreeNode<Tag>>(),
|
|
|
+ std::mem::size_of::<DynPtr>()
|
|
|
+ );
|
|
|
+ assert_eq!(
|
|
|
+ std::mem::align_of::<&dyn LayoutTreeNode<Tag>>(),
|
|
|
+ std::mem::align_of::<DynPtr>()
|
|
|
+ );
|
|
|
+ Self {
|
|
|
+ current_node_func: current_node_dispatch::<Tag>,
|
|
|
+ child_count_func: child_count_dispatch::<Tag>,
|
|
|
+ child_func: child_dispatch::<Tag>,
|
|
|
+ dynptr: unsafe { std::mem::transmute(from) },
|
|
|
+ }
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-impl<'l> Deref for LayoutNodeAccess<'l> {
|
|
|
- type Target = LayoutNode;
|
|
|
- fn deref(&self) -> &Self::Target {
|
|
|
- self.lnc.layout_node()
|
|
|
+ pub fn current_node(&self) -> &'l LayoutNode {
|
|
|
+ (self.current_node_func)(self.dynptr)
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-impl<'l> LayoutNodeAccess<'l> {
|
|
|
- pub fn child(&self, ndx: usize) -> Option<LayoutNodeAccess<'l>> {
|
|
|
- self.lnc.layout_child(ndx)
|
|
|
+ pub fn child_count(&self) -> usize {
|
|
|
+ (self.child_count_func)(self.dynptr)
|
|
|
}
|
|
|
- pub fn child_len(&self) -> usize {
|
|
|
- self.lnc.layout_child_count()
|
|
|
+
|
|
|
+ pub fn child(&self, ndx: usize) -> Option<LayoutNodeAccess<'l>> {
|
|
|
+ (self.child_func)(self.dynptr, ndx)
|
|
|
}
|
|
|
- pub fn child_iter(&self) -> LayoutChildIter {
|
|
|
- LayoutChildIter::new(self.lnc)
|
|
|
+
|
|
|
+ pub fn child_iter(&self) -> impl Iterator<Item = LayoutNodeAccess> + Clone {
|
|
|
+ LayoutChildIter::new(&self)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/// Data source trait for LayoutNodeAccess.
|
|
|
-pub trait LayoutNodeContainer {
|
|
|
- fn layout_node(&self) -> &LayoutNode;
|
|
|
- fn layout_child(&self, ndx: usize) -> Option<LayoutNodeAccess<'_>>;
|
|
|
- fn layout_child_count(&self) -> usize;
|
|
|
+impl<'l> Deref for LayoutNodeAccess<'l> {
|
|
|
+ type Target = LayoutNode;
|
|
|
+ fn deref(&self) -> &Self::Target {
|
|
|
+ (self.current_node_func)(self.dynptr)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-/// Helper struct to store a leaf LayoutNode and automatically provide a LayoutNodeContainer impl
|
|
|
+/// Helper struct to store a leaf LayoutNode and automatically provide a LayoutTreeNode impl
|
|
|
pub struct LeafLayoutNode(LayoutNode);
|
|
|
|
|
|
impl LeafLayoutNode {
|
|
|
pub fn new(ln: LayoutNode) -> Self {
|
|
|
Self(ln)
|
|
|
}
|
|
|
+
|
|
|
+ pub fn access(&self) -> LayoutNodeAccess {
|
|
|
+ LayoutNodeAccess::new(self)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
impl From<LayoutNode> for LeafLayoutNode {
|
|
@@ -623,37 +641,14 @@ impl std::ops::DerefMut for LeafLayoutNode {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl LayoutNodeContainer for LeafLayoutNode {
|
|
|
- fn layout_node(&self) -> &LayoutNode {
|
|
|
+impl LayoutTreeNode<()> for LeafLayoutNode {
|
|
|
+ fn current_node(&self) -> &LayoutNode {
|
|
|
&self.0
|
|
|
}
|
|
|
- fn layout_child(&self, _ndx: usize) -> Option<LayoutNodeAccess<'_>> {
|
|
|
+ fn child(&self, _ndx: usize) -> Option<LayoutNodeAccess<'_>> {
|
|
|
None
|
|
|
}
|
|
|
- fn layout_child_count(&self) -> usize {
|
|
|
+ fn child_count(&self) -> usize {
|
|
|
0
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-/// Helper LayoutNodeContainer implementation for LayoutNodes with one child
|
|
|
-pub struct LinearAccess<'l>(&'l LayoutNode, LayoutNodeAccess<'l>);
|
|
|
-impl<'l> LinearAccess<'l> {
|
|
|
- pub fn new(parent: &'l LayoutNode, child: LayoutNodeAccess<'l>) -> Self {
|
|
|
- Self(parent, child)
|
|
|
- }
|
|
|
-}
|
|
|
-impl<'l> LayoutNodeContainer for LinearAccess<'l> {
|
|
|
- fn layout_node(&self) -> &LayoutNode {
|
|
|
- self.0
|
|
|
- }
|
|
|
- fn layout_child(&self, ndx: usize) -> Option<LayoutNodeAccess> {
|
|
|
- if ndx == 0 {
|
|
|
- Some(self.1)
|
|
|
- } else {
|
|
|
- None
|
|
|
- }
|
|
|
- }
|
|
|
- fn layout_child_count(&self) -> usize {
|
|
|
- 1
|
|
|
- }
|
|
|
-}
|