use super::{IndexedNode, List, Node, Object};
use crate::IndexedObject;
use std::mem;
pub(crate) enum Pending<T, B> {
Object(IndexedObject<T, B>),
Node(IndexedNode<T, B>),
}
pub(crate) fn dismantle<T, B>(pending: &mut Vec<Pending<T, B>>) {
while let Some(descendant) = pending.pop() {
match descendant {
Pending::Object(mut object) => match object.inner_mut() {
Object::Node(node) => node.release_children(pending),
Object::List(list) => release_list(list, pending),
Object::Value(_) => {}
},
Pending::Node(mut node) => node.inner_mut().release_children(pending),
}
}
}
pub(crate) fn release_list<T, B>(list: &mut List<T, B>, pending: &mut Vec<Pending<T, B>>) {
pending.extend(list.take_entries().into_iter().filter(owns_objects).map(Pending::Object));
}
fn owns_objects<T, B>(object: &IndexedObject<T, B>) -> bool {
match object.inner() {
Object::Node(_) => true,
Object::List(list) => !list.is_empty(),
Object::Value(_) => false,
}
}
impl<T, B> Node<T, B> {
pub(crate) fn release_children(&mut self, pending: &mut Vec<Pending<T, B>>) {
if let Some(graph) = self.graph.take() {
pending.extend(graph.into_iter().filter(owns_objects).map(Pending::Object));
}
if let Some(included) = self.included.take() {
pending.extend(included.into_iter().map(Pending::Node));
}
if !self.properties.is_empty() {
pending.extend(
mem::take(&mut self.properties)
.into_iter()
.flat_map(|(_, objects)| objects)
.filter(owns_objects)
.map(Pending::Object),
);
}
if let Some(reverse) = self.reverse_properties.take() {
pending.extend(reverse.into_iter().flat_map(|(_, nodes)| nodes).map(Pending::Node));
}
}
}
impl<T, B> Drop for Node<T, B> {
fn drop(&mut self) {
let mut pending = Vec::new();
self.release_children(&mut pending);
dismantle(&mut pending);
}
}
impl<T, B> Drop for List<T, B> {
fn drop(&mut self) {
let mut pending = Vec::new();
release_list(self, &mut pending);
dismantle(&mut pending);
}
}