use thunderdome::Arena;
use crate::{Children, Node, NodeIndex};
use std::collections::VecDeque;
pub struct SceneGraphDetachIter<'a, T> {
arena: &'a mut Arena<Node<T>>,
stacks: VecDeque<StackState<T>>,
}
impl<'a, T> SceneGraphDetachIter<'a, T> {
pub(crate) fn new(
arena: &'a mut Arena<Node<T>>,
head_index: NodeIndex,
current_children: Option<Children>,
) -> Self {
let mut stacks = VecDeque::new();
if let Some(children) = current_children {
stacks.push_front(StackState::new(
head_index,
arena.remove(children.first).unwrap(),
NodeIndex::Branch(children.first),
));
}
SceneGraphDetachIter { arena, stacks }
}
}
impl<'a, T> Iterator for SceneGraphDetachIter<'a, T> {
type Item = DetachedNode<T>;
fn next(&mut self) -> Option<Self::Item> {
let stack_frame = self.stacks.pop_front()?;
if let Some(next_sibling) = stack_frame.current_child.next_sibling {
self.stacks.push_front(StackState::new(
stack_frame.parent,
self.arena.remove(next_sibling).unwrap(),
NodeIndex::Branch(next_sibling),
));
}
if let Some(children) = stack_frame.current_child.children {
let new_stack = StackState::new(
stack_frame.current_child_idx,
self.arena.remove(children.first).unwrap(),
NodeIndex::Branch(children.first),
);
self.stacks.push_front(new_stack);
}
Some(DetachedNode {
parent_idx: stack_frame.parent,
node_idx: stack_frame.current_child_idx,
node_value: stack_frame.current_child.value,
})
}
}
impl<'a, T> Drop for SceneGraphDetachIter<'a, T> {
fn drop(&mut self) {
for _ in self {}
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub struct DetachedNode<T> {
pub parent_idx: NodeIndex,
pub node_idx: NodeIndex,
pub node_value: T,
}
impl<T> std::fmt::Debug for DetachedNode<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DetachedNode")
.field("parent_idx", &self.parent_idx)
.field("node_idx", &self.node_idx)
.finish_non_exhaustive()
}
}
struct StackState<T> {
parent: NodeIndex,
current_child: Node<T>,
current_child_idx: NodeIndex,
}
impl<T> std::fmt::Debug for StackState<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("StackState")
.field("parent", &self.parent)
.field("current_child", &self.current_child)
.field("current_child_idx", &self.current_child_idx)
.finish()
}
}
impl<T> StackState<T> {
fn new(parent: NodeIndex, first_child: Node<T>, first_child_idx: NodeIndex) -> Self {
Self {
parent,
current_child: first_child,
current_child_idx: first_child_idx,
}
}
}
#[cfg(test)]
mod tests {
use crate::SceneGraph;
use super::*;
#[test]
fn detach_handles_empty() {
let mut scene_graph = SceneGraph::new("Root");
assert!(scene_graph.iter_detach_from_root().next().is_none());
}
#[test]
fn detach_iteration() {
let mut sg = SceneGraph::new("Root");
let root_idx = NodeIndex::Root;
sg.attach(root_idx, "First Child").unwrap();
let second_child = sg.attach(root_idx, "Second Child").unwrap();
sg.attach(second_child, "First Grandchild").unwrap();
assert_eq!(
Vec::from_iter(sg.iter_detach_from_root().map(|d_v| d_v.node_value)),
vec!["First Child", "Second Child", "First Grandchild"]
);
assert!(sg.is_empty());
}
#[test]
fn stagger_detach_iteration() {
let mut sg = SceneGraph::new("Root");
let root_idx = NodeIndex::Root;
let child = sg.attach(root_idx, "First Child").unwrap();
sg.attach(child, "Second Child").unwrap();
assert_eq!(
Vec::from_iter(sg.iter_detach_from_root().map(|value| value.node_value)),
vec!["First Child", "Second Child"]
);
assert!(sg.is_empty());
}
#[test]
fn single_detach_iteration() {
let mut sg = SceneGraph::new("Root");
let root_idx = NodeIndex::Root;
sg.attach(root_idx, "First Child").unwrap();
assert_eq!(
Vec::from_iter(sg.iter_detach_from_root().map(|value| value.node_value)),
vec!["First Child",]
);
assert!(sg.is_empty());
}
#[test]
fn child_detach_iteration() {
let mut sg = SceneGraph::new("Root");
let root_idx = NodeIndex::Root;
sg.attach(root_idx, "First Child").unwrap();
let second_child = sg.attach(root_idx, "Second Child").unwrap();
sg.attach(second_child, "First Grandchild").unwrap();
sg.attach(second_child, "Second Grandchild").unwrap();
sg.attach(second_child, "Third Grandchild").unwrap();
sg.attach(second_child, "Fourth Grandchild").unwrap();
assert_eq!(
Vec::from_iter(sg.iter_detach(second_child).unwrap().map(|d_v| d_v.node_value)),
vec![
"First Grandchild",
"Second Grandchild",
"Third Grandchild",
"Fourth Grandchild"
]
);
assert!(!sg.is_empty());
}
#[test]
fn child_detach_iteration_grand() {
let mut sg = SceneGraph::new("Root");
let root_idx = NodeIndex::Root;
sg.attach(root_idx, "First Child").unwrap();
let second_child = sg.attach(root_idx, "Second Child").unwrap();
let gc = sg.attach(second_child, "First Grandchild").unwrap();
sg.attach(gc, "First Great-Grandchild").unwrap();
sg.attach(second_child, "Second Grandchild").unwrap();
sg.attach(second_child, "Third Grandchild").unwrap();
assert_eq!(
Vec::from_iter(sg.iter_detach(second_child).unwrap().map(|d_v| d_v.node_value)),
vec![
"First Grandchild",
"First Great-Grandchild",
"Second Grandchild",
"Third Grandchild"
]
);
assert!(!sg.is_empty());
}
#[test]
fn child_detach_iteration_grand2() {
let mut sg = SceneGraph::new("Root");
let root_idx = NodeIndex::Root;
sg.attach(root_idx, "First Child").unwrap();
let second_child = sg.attach(root_idx, "Second Child").unwrap();
let gc = sg.attach(second_child, "First Grandchild").unwrap();
sg.attach(gc, "First Great-Grandchild").unwrap();
sg.attach(second_child, "Second Grandchild").unwrap();
sg.attach(second_child, "Third Grandchild").unwrap();
assert_eq!(
Vec::from_iter(sg.iter_detach(gc).unwrap().map(|d_v| d_v.node_value)),
vec!["First Great-Grandchild",]
);
assert_eq!(
Vec::from_iter(sg.iter_detach(gc).unwrap().map(|d_v| d_v.node_value)),
Vec::<&'static str>::new()
);
}
}