#![no_std]
#![forbid(unsafe_code)]
#![warn(
// Groups
future_incompatible,
nonstandard_style,
rust_2018_compatibility, // unsure if needed with edition="2018"
rust_2018_idioms,
unused,
clippy::all,
clippy::pedantic,
clippy::restriction,
// Individual lints not included in above groups and desired.
macro_use_extern_crate,
missing_copy_implementations,
missing_debug_implementations,
missing_docs,
// missing_doc_code_examples, // maybe someday
private_doc_tests,
single_use_lifetimes, // annoying hits on invisible derived impls
trivial_casts,
trivial_numeric_casts,
// unreachable_pub,
unused_import_braces,
unused_lifetimes,
unused_qualifications,
unused_results,
variant_size_differences,
)]
#![allow(
// explicit_outlives_requirements, // annoying hits on invisible derived impls
clippy::non_ascii_literal,
// clippy::must_use_candidate, // excessively pedantic
// clippy::missing_errors_doc, // for now
// For when clippy::restriction is on:
clippy::else_if_without_else,
// clippy::missing_inline_in_public_items,
clippy::implicit_return,
clippy::missing_docs_in_private_items,
)]
use core::ops::DerefMut;
pub trait DeepSafeDrop<Link>
{
fn take_first_child(&mut self) -> Option<Link>;
fn replace_first_child_with_parent(&mut self, parent: Link)
-> ReplacedFirstChild<Link>;
fn take_next_child(&mut self) -> Option<Link>;
}
#[derive(Debug)]
pub enum ReplacedFirstChild<Link> {
Yes {
first_child: Link
},
No {
returned_parent: Link
},
}
fn take_first_child<T, L>(thing: &mut T) -> Option<L>
where
T: DeepSafeDrop<L> + ?Sized,
{
let first_child = thing.take_first_child();
debug_assert!(matches!(thing.take_first_child(), None));
first_child
}
fn take_parent<L, N>(node: &mut N) -> Option<L>
where
N: DeepSafeDrop<L> + ?Sized,
{
take_first_child(node)
}
fn take_ancestor_next_child<L>(parent: L) -> (L, Option<L>)
where
L: DerefMut,
L::Target: DeepSafeDrop<L>,
{
let mut ancestor = parent;
loop {
if let Some(next_child) = ancestor.take_next_child() {
break (ancestor, Some(next_child));
}
else if let Some(grandancestor) = take_parent(&mut *ancestor) {
drop(ancestor);
ancestor = grandancestor;
}
else {
break (ancestor, None);
}
}
}
fn main_deep_safe_drop<L>(top: L)
where
L: DerefMut,
L::Target: DeepSafeDrop<L>,
{
use ReplacedFirstChild::*;
let mut parent = top;
if let Some(mut cur) = take_first_child(&mut *parent) {
loop {
match cur.replace_first_child_with_parent(parent)
{
Yes { first_child } => {
parent = cur;
cur = first_child;
}
No { returned_parent } => {
parent = returned_parent;
drop(cur);
let (ancestor, ancestor_child) = take_ancestor_next_child(parent);
parent = ancestor;
if let Some(ancestor_child) = ancestor_child {
cur = ancestor_child;
}
else {
drop(parent);
break;
}
}
}
}
}
}
#[inline]
pub fn deep_safe_drop<RootNode, Link>(root: &mut RootNode)
where
RootNode: DeepSafeDrop<Link> + ?Sized,
Link: DerefMut,
Link::Target: DeepSafeDrop<Link>,
{
if let Some(child) = take_first_child(root) {
main_deep_safe_drop(child);
while let Some(child) = root.take_next_child() {
main_deep_safe_drop(child);
}
}
}
#[cfg(test)]
mod tests;