diff --git a/atspi/examples/bus-tree.rs b/atspi/examples/bus-tree.rs index 26812b8b..752be128 100644 --- a/atspi/examples/bus-tree.rs +++ b/atspi/examples/bus-tree.rs @@ -16,6 +16,7 @@ use atspi::{ AccessibilityConnection, Role, }; use display_tree::{AsTree, DisplayTree, Style}; +use futures::future::try_join_all; type Result = std::result::Result>; @@ -70,37 +71,51 @@ impl A11yNode { impl A11yNode { async fn from_accessible_proxy(ap: AccessibleProxy<'_>) -> Result { - let role = ap.get_role().await?; - let child_objs = ap.get_children().await?; - let connection = ap.inner().connection(); - - // Convert `Vec` to a `Vec`. - let children = child_objs - .iter() - .map(|child| child.as_accessible_proxy(connection)) - .collect::>(); - - // Resolve the futures and filter out the errors. - let children = futures::future::join_all(children) - .await - .into_iter() - .filter_map(|child| child.ok()) - .collect::>(); - - // Convert to a `Vec>`. - let children = children - .into_iter() - .map(|child| Box::pin(Self::from_accessible_proxy(child))) - .collect::>(); - - // Resolve the futures and filter out the errors. - let children = futures::future::join_all(children) - .await - .into_iter() - .filter_map(|child| child.ok()) - .collect::>(); - - Ok(A11yNode { role, children }) + let connection = ap.inner().connection().clone(); + // Contains the processed `A11yNode`'s. + let mut nodes: Vec = Vec::new(); + + // Contains the `AccessibleProxy` yet to be processed. + let mut stack: Vec = vec![ap]; + + // If the stack has an `AccessibleProxy`, we take the last. + while let Some(ap) = stack.pop() { + let child_objects = ap.get_children().await?; + let mut children_proxies = try_join_all( + child_objects + .into_iter() + .map(|child| child.into_accessible_proxy(&connection)), + ) + .await?; + + let roles = try_join_all(children_proxies.iter().map(|child| child.get_role())).await?; + stack.append(&mut children_proxies); + + let children = roles + .into_iter() + .map(|role| A11yNode { role, children: Vec::new() }) + .collect::>(); + + let role = ap.get_role().await?; + nodes.push(A11yNode { role, children }); + } + + let mut fold_stack: Vec = Vec::with_capacity(nodes.len()); + + while let Some(mut node) = nodes.pop() { + if node.children.is_empty() { + fold_stack.push(node); + continue; + } + + // If the node has children, we fold in the children from 'fold_stack'. + // There may be more on 'fold_stack' than the node requires. + let begin = fold_stack.len().saturating_sub(node.children.len()); + node.children = fold_stack.split_off(begin); + fold_stack.push(node); + } + + fold_stack.pop().ok_or("No root node built".into()) } }