use bevy_ecs::prelude::*;
pub struct DepthFirstReversePostOrder {
stack: Vec<(Entity, bool)>,
}
impl DepthFirstReversePostOrder {
pub fn new(root: Entity) -> Self {
Self {
stack: vec![(root, false)],
}
}
pub fn next(&mut self, world: &World) -> Option<Entity> {
loop {
let (entity, expanded) = self.stack.pop()?;
if expanded {
return Some(entity);
}
self.stack.push((entity, true));
if let Some(children) = world.get::<Children>(entity) {
for child in children.iter() {
self.stack.push((child, false));
}
}
}
}
pub fn collect(&mut self, world: &World) -> Vec<Entity> {
let mut result = Vec::new();
while let Some(entity) = self.next(world) {
result.push(entity);
}
result
}
}
#[cfg(test)]
mod tests {
use super::*;
use bevy_ecs::world::World;
fn collect_traversal_order(world: &World, root: Entity) -> Vec<Entity> {
DepthFirstReversePostOrder::new(root).collect(world)
}
#[test]
fn test_basic_traversal_order() {
let mut world = World::new();
let gc1a = world.spawn_empty().id();
let gc1b = world.spawn_empty().id();
let gc2a = world.spawn_empty().id();
let child1 = world.spawn_empty().id();
let child2 = world.spawn_empty().id();
let root = world.spawn_empty().id();
world.entity_mut(child1).add_children(&[gc1a, gc1b]);
world.entity_mut(child2).add_children(&[gc2a]);
world.entity_mut(root).add_children(&[child1, child2]);
let result = collect_traversal_order(&world, root);
assert_eq!(result, vec![gc2a, child2, gc1b, gc1a, child1, root]);
}
#[test]
fn test_single_node() {
let mut world = World::new();
let root = world.spawn_empty().id();
let result = collect_traversal_order(&world, root);
assert_eq!(result, vec![root]);
}
#[test]
fn test_deep_hierarchy() {
let mut world = World::new();
let d = world.spawn_empty().id();
let c = world.spawn_empty().id();
let b = world.spawn_empty().id();
let a = world.spawn_empty().id();
world.entity_mut(c).add_children(&[d]);
world.entity_mut(b).add_children(&[c]);
world.entity_mut(a).add_children(&[b]);
let result = collect_traversal_order(&world, a);
assert_eq!(result, vec![d, c, b, a]);
}
#[test]
fn test_wide_tree() {
let mut world = World::new();
let c1 = world.spawn_empty().id();
let c2 = world.spawn_empty().id();
let c3 = world.spawn_empty().id();
let c4 = world.spawn_empty().id();
let root = world.spawn_empty().id();
world.entity_mut(root).add_children(&[c1, c2, c3, c4]);
let result = collect_traversal_order(&world, root);
assert_eq!(result, vec![c4, c3, c2, c1, root]);
}
#[test]
fn test_next_returns_none_after_exhaustion() {
let mut world = World::new();
let root = world.spawn_empty().id();
let mut traversal = DepthFirstReversePostOrder::new(root);
assert_eq!(traversal.next(&world), Some(root));
assert_eq!(traversal.next(&world), None);
assert_eq!(traversal.next(&world), None);
}
#[test]
fn test_next_step_by_step_matches_collect() {
let mut world = World::new();
let gc = world.spawn_empty().id();
let child = world.spawn_empty().id();
let root = world.spawn_empty().id();
world.entity_mut(child).add_children(&[gc]);
world.entity_mut(root).add_children(&[child]);
let expected = DepthFirstReversePostOrder::new(root).collect(&world);
let mut traversal = DepthFirstReversePostOrder::new(root);
let mut stepwise = Vec::new();
while let Some(e) = traversal.next(&world) {
stepwise.push(e);
}
assert_eq!(stepwise, expected);
assert_eq!(stepwise, vec![gc, child, root]);
}
#[test]
fn test_mixed_siblings_with_and_without_children() {
let mut world = World::new();
let b1 = world.spawn_empty().id();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
let root = world.spawn_empty().id();
world.entity_mut(b).add_children(&[b1]);
world.entity_mut(root).add_children(&[a, b]);
let result = collect_traversal_order(&world, root);
assert_eq!(result, vec![b1, b, a, root]);
}
#[test]
fn test_node_without_children_component_is_leaf() {
let mut world = World::new();
let leaf = world.spawn_empty().id();
let mut traversal = DepthFirstReversePostOrder::new(leaf);
assert_eq!(traversal.next(&world), Some(leaf));
assert_eq!(traversal.next(&world), None);
}
}