Fix the parent index for sub-components

We never ended up passing the right index but always zero.

Fix by rewriting build_item_tree to be basically the same as build_array_helper,
with two differences:

(1) we maintain absolute and relative children offsets and parent indices
(2) When traversing over the children of an element there are two scenarios: either
  the element is a sub-component, in which case we iterate through the children of the root element,
  or we can use ElementRc's children directly
This commit is contained in:
Simon Hausmann 2021-11-01 17:57:30 +01:00
parent efa1448565
commit 80f1a8ab11

View file

@ -143,13 +143,6 @@ pub fn build_array_helper(component: &Component, mut visit_item: impl FnMut(&Ele
} }
} }
struct SubTree<State> {
component: Rc<Component>,
parent_index: u32,
children_offset: u32,
state: State,
}
/// Visit each item in order in which they should appear in the children tree array. /// Visit each item in order in which they should appear in the children tree array.
/// The parameter of the visitor are /// The parameter of the visitor are
/// 1. The application specific state (can be used to keep track of how to reach fields) /// 1. The application specific state (can be used to keep track of how to reach fields)
@ -158,44 +151,32 @@ struct SubTree<State> {
/// 4. the first_children_offset, /// 4. the first_children_offset,
/// 5. the parent index /// 5. the parent index
/// ///
/// The start_subtree callback is called when encountering a sub-component. /// The visit_sub_component callback is called when encountering a sub-component.
/// The parameters are: /// The parameters are:
/// 1. The application specific state /// 1. The application specific state
/// 2. The current component being built (the parent of the sub-component!) /// 2. The current component being built (the parent of the sub-component!)
/// 3. The element used to instantiate the sub-component /// 3. The element used to instantiate the sub-component
#[allow(dead_code)] #[allow(dead_code)]
pub fn build_item_tree<State>( pub fn build_item_tree<ComponentState>(
root_component: &Rc<Component>, root_component: &Rc<Component>,
initial_state: State, initial_state: ComponentState,
mut visit_item: impl FnMut(&State, &Rc<Component>, &ElementRc, u32, u32), mut visit_item: impl FnMut(&ComponentState, &Rc<Component>, &ElementRc, u32, u32),
mut start_subtree: impl FnMut(&State, &Rc<Component>, &ElementRc) -> State, mut visit_sub_component: impl FnMut(&ComponentState, &Rc<Component>, &ElementRc) -> ComponentState,
) { ) {
visit_item(&initial_state, root_component, &root_component.root_element, 1, 0); visit_item(&initial_state, root_component, &root_component.root_element, 1, 0);
let mut subtrees_to_process = VecDeque::default(); visit_children(
subtrees_to_process.push_back(SubTree { &initial_state,
component: root_component.clone(), &root_component.root_element.borrow().children,
parent_index: 0, &root_component,
children_offset: 1, &root_component.root_element,
state: initial_state, 0,
}); 0,
1,
while let Some(SubTree { component, parent_index, children_offset, state }) = 1,
subtrees_to_process.pop_front() &mut visit_item,
{ &mut visit_sub_component,
visit_children( );
&state,
&component,
&component.root_element,
parent_index,
0,
children_offset,
1,
&mut visit_item,
&mut start_subtree,
&mut subtrees_to_process,
);
}
// Size of the element's children and grand-children, // Size of the element's children and grand-children,
// needed to calculate the sub-component relative children offset indices // needed to calculate the sub-component relative children offset indices
@ -211,110 +192,95 @@ pub fn build_item_tree<State>(
// sub-component children, needed to allocate the correct amount of // sub-component children, needed to allocate the correct amount of
// index spaces for sub-components. // index spaces for sub-components.
fn item_sub_tree_size(e: &ElementRc) -> usize { fn item_sub_tree_size(e: &ElementRc) -> usize {
let mut count = if let Some(sub_component) = e.borrow().sub_component() { let e = if let Some(sub_component) = e.borrow().sub_component() {
sub_component.root_element.borrow().children.len() sub_component.root_element.clone()
} else { } else {
e.borrow().children.len() e.clone()
}; };
let mut count = e.borrow().children.len();
for i in &e.borrow().children { for i in &e.borrow().children {
count += item_sub_tree_size(i); count += item_sub_tree_size(i);
} }
count count
} }
// Returns the number of indices in the item tree the element needs. If the element is fn visit_children<ComponentState>(
// a built-in item, then this function returns 1. If the element is a sub-component, then state: &ComponentState,
// the number of items (including children) the sub-component needs is returned. children: &Vec<ElementRc>,
fn item_tree_element_size(element: &ElementRc) -> usize {
let mut size = 1;
if let Some(sub_component) = element.borrow().sub_component() {
for child in &sub_component.root_element.borrow().children {
size += item_tree_element_size(&child);
}
}
size
}
fn visit_children<State>(
state: &State,
component: &Rc<Component>, component: &Rc<Component>,
parent_item: &ElementRc, parent_item: &ElementRc,
parent_index: u32, parent_index: u32,
relative_parent_index: u32, relative_parent_index: u32,
children_offset: u32, children_offset: u32,
relative_children_offset: u32, relative_children_offset: u32,
visit_item: &mut impl FnMut(&State, &Rc<Component>, &ElementRc, u32, u32), visit_item: &mut impl FnMut(&ComponentState, &Rc<Component>, &ElementRc, u32, u32),
start_subtree: &mut impl FnMut(&State, &Rc<Component>, &ElementRc) -> State, visit_sub_component: &mut impl FnMut(
subtrees_to_process: &mut VecDeque<SubTree<State>>, &ComponentState,
&Rc<Component>,
&ElementRc,
) -> ComponentState,
) { ) {
debug_assert_eq!( debug_assert_eq!(
relative_parent_index, relative_parent_index,
parent_item.borrow().item_index.get().map(|x| *x as u32).unwrap_or(parent_index) parent_item.borrow().item_index.get().map(|x| *x as u32).unwrap_or(parent_index)
); );
let mut offset = children_offset + parent_item.borrow().children.len() as u32; let mut offset = children_offset + children.len() as u32;
let sub_tree_size = offset - children_offset; let mut sub_component_states = VecDeque::new();
for child in &parent_item.borrow().children { for child in children.iter() {
if let Some(sub_component) = child.borrow().sub_component() { if let Some(sub_component) = child.borrow().sub_component() {
let subtree_state = start_subtree(state, component, child); let sub_component_state = visit_sub_component(state, component, child);
visit_item( visit_item(
&subtree_state, &sub_component_state,
sub_component, sub_component,
&sub_component.root_element, &sub_component.root_element,
offset, offset,
parent_index, parent_index,
); );
subtrees_to_process.push_back(SubTree { sub_component_states.push_back(sub_component_state);
component: sub_component.clone(),
parent_index,
children_offset: offset,
state: subtree_state,
});
} else { } else {
visit_item(state, component, child, offset, parent_index); visit_item(state, component, child, offset, parent_index);
} }
offset += item_sub_tree_size(child) as u32; offset += item_sub_tree_size(child) as u32;
} }
let mut offset = children_offset + sub_tree_size; let mut offset = children_offset + children.len() as u32;
let mut relative_offset = relative_children_offset + sub_tree_size; let mut relative_offset = relative_children_offset + children.len() as u32;
let mut index = children_offset; let mut index = children_offset;
let mut relative_index = relative_children_offset; let mut relative_index = relative_children_offset;
for e in &parent_item.borrow().children { for e in children.iter() {
let mut subtrees = VecDeque::new(); if let Some(sub_component) = e.borrow().sub_component() {
visit_children( let sub_tree_state = sub_component_states.pop_front().unwrap();
state,
component,
e,
index,
relative_index,
offset,
relative_offset,
visit_item,
start_subtree,
&mut subtrees,
);
while let Some(SubTree { component, parent_index, children_offset, state }) =
subtrees.pop_front()
{
visit_children( visit_children(
&state, &sub_tree_state,
&component, &sub_component.root_element.borrow().children,
&component.root_element, sub_component,
parent_index, &sub_component.root_element,
index,
0, 0,
children_offset, offset,
1, 1,
visit_item, visit_item,
start_subtree, visit_sub_component,
subtrees_to_process, );
} else {
visit_children(
state,
&e.borrow().children,
component,
e,
index,
relative_index,
offset,
relative_offset,
visit_item,
visit_sub_component,
); );
} }
index += item_tree_element_size(e) as u32; index += 1;
relative_index += 1; relative_index += 1;
offset += item_sub_tree_size(e) as u32; offset += item_sub_tree_size(e) as u32;
relative_offset += sub_children_count(e) as u32; relative_offset += sub_children_count(e) as u32;