use crate::abi::datastructures::{ItemRef, ItemTreeNode, ItemVisitor, ItemVisitorVTable}; use crate::ComponentRefPin; use core::pin::Pin; /// Visit each items recursively /// /// The state parametter returned by the visitor is passed to each children. pub fn visit_items( component: ComponentRefPin, mut visitor: impl FnMut(ComponentRefPin, Pin, &State) -> State, state: State, ) { visit_internal(component, &mut visitor, -1, &state) } fn visit_internal( component: ComponentRefPin, visitor: &mut impl FnMut(ComponentRefPin, Pin, &State) -> State, index: isize, state: &State, ) { let mut actual_visitor = |component: ComponentRefPin, index: isize, item: Pin| { let s = visitor(component, item, state); visit_internal(component, visitor, index, &s); }; vtable::new_vref!(let mut actual_visitor : VRefMut for ItemVisitor = &mut actual_visitor); component.as_ref().visit_children_item(index, actual_visitor); } /// Visit the children within an array of ItemTreeNode /// /// The dynamic visitor is called for the dynamic nodes, its signature is /// `fn(base: &Base, visitor: vtable::VRefMut, dyn_index: usize)` /// /// FIXME: the design of this use lots of indirection and stack frame in recursive functions /// Need to check if the compiler is able to optimize away some of it. /// Possibly we should generate code that directly call the visitor instead pub fn visit_item_tree( base: Pin<&Base>, component: ComponentRefPin, item_tree: &[ItemTreeNode], index: isize, mut visitor: vtable::VRefMut, visit_dynamic: impl Fn(Pin<&Base>, vtable::VRefMut, usize), ) { let mut visit_at_index = |idx: usize| match &item_tree[idx] { ItemTreeNode::Item { item, .. } => { visitor.visit_item(component, idx as isize, item.apply_pin(base)); } ItemTreeNode::DynamicTree { index } => visit_dynamic(base, visitor.borrow_mut(), *index), }; if index == -1 { visit_at_index(0); } else { match &item_tree[index as usize] { ItemTreeNode::Item { children_index, chilren_count, .. } => { for c in *children_index..(*children_index + *chilren_count) { visit_at_index(c as usize); } } ItemTreeNode::DynamicTree { .. } => todo!(), }; }; }