use std::{
fmt::Display,
mem::ManuallyDrop,
ops::{Deref, DerefMut},
rc::Rc,
sync::Arc,
};
pub trait Recursive {
type Container;
fn destruct(self) -> impl Iterator<Item = Self::Container>;
}
pub trait IntoOptionInner {
type Inner;
fn into_option_inner(self) -> Option<Self::Inner>;
}
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct FlatDrop<K>(ManuallyDrop<K>)
where
K: IntoOptionInner,
K::Inner: Recursive<Container = K>;
impl<K> Drop for FlatDrop<K>
where
K: IntoOptionInner,
K::Inner: Recursive<Container = K>,
{
fn drop(&mut self) {
let value = unsafe { ManuallyDrop::take(&mut self.0) };
let mut to_drop = vec![value];
while let Some(container) = to_drop.pop() {
if let Some(value) = container.into_option_inner() {
to_drop.extend(value.destruct());
}
}
}
}
impl<T> IntoOptionInner for Box<T> {
type Inner = T;
fn into_option_inner(self) -> Option<Self::Inner> {
Some(*self)
}
}
impl<T> IntoOptionInner for Rc<T> {
type Inner = T;
fn into_option_inner(self) -> Option<Self::Inner> {
Rc::into_inner(self)
}
}
impl<T> IntoOptionInner for Arc<T> {
type Inner = T;
fn into_option_inner(self) -> Option<Self::Inner> {
Arc::into_inner(self)
}
}
pub type FlatBox<T> = FlatDrop<Box<T>>;
pub type FlatRc<T> = FlatDrop<Rc<T>>;
pub type FlatArc<T> = FlatDrop<Arc<T>>;
impl<K> FlatDrop<K>
where
K: IntoOptionInner,
K::Inner: Recursive<Container = K>,
{
pub const fn new(container: K) -> Self {
Self(ManuallyDrop::new(container))
}
pub fn into_inner(mut self) -> K {
let value = unsafe { ManuallyDrop::take(&mut self.0) };
std::mem::forget(self);
value
}
}
impl<T> FlatBox<T>
where
T: Recursive<Container = Box<T>>,
{
pub fn unbox(self) -> T {
*self.into_inner()
}
}
impl<K, T> AsRef<T> for FlatDrop<K>
where
T: ?Sized,
K: IntoOptionInner,
K::Inner: Recursive<Container = K>,
K: AsRef<T>,
{
fn as_ref(&self) -> &T {
(**self).as_ref()
}
}
impl<K, T> AsMut<T> for FlatDrop<K>
where
T: ?Sized,
K: IntoOptionInner,
K::Inner: Recursive<Container = K>,
K: AsMut<T>,
{
fn as_mut(&mut self) -> &mut T {
(**self).as_mut()
}
}
impl<K> Deref for FlatDrop<K>
where
K: IntoOptionInner,
K::Inner: Recursive<Container = K>,
{
type Target = K;
fn deref(&self) -> &K {
self.0.deref()
}
}
impl<K> DerefMut for FlatDrop<K>
where
K: IntoOptionInner,
K::Inner: Recursive<Container = K>,
{
fn deref_mut(&mut self) -> &mut K {
self.0.deref_mut()
}
}
impl<K> Display for FlatDrop<K>
where
K: IntoOptionInner + Display,
K::Inner: Recursive<Container = K>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<K as Display>::fmt(self, f)
}
}
impl<K> From<K> for FlatDrop<K>
where
K: IntoOptionInner,
K::Inner: Recursive<Container = K>,
{
fn from(value: K) -> Self {
Self::new(value)
}
}
impl<T> FlatBox<T>
where
T: Recursive<Container = Box<T>>,
{
pub fn new_boxed(value: T) -> Self {
Self::new(Box::new(value))
}
}
impl<T> From<T> for FlatBox<T>
where
T: Recursive<Container = Box<T>>,
{
fn from(value: T) -> Self {
Self::new_boxed(value)
}
}
impl<T> FlatRc<T>
where
T: Recursive<Container = Rc<T>>,
{
pub fn new_rc(value: T) -> Self {
Self::new(Rc::new(value))
}
}
impl<T> From<T> for FlatRc<T>
where
T: Recursive<Container = Rc<T>>,
{
fn from(value: T) -> Self {
Self::new_rc(value)
}
}
impl<T> FlatArc<T>
where
T: Recursive<Container = Arc<T>>,
{
pub fn new_arc(value: T) -> Self {
Self::new(Arc::new(value))
}
}
impl<T> From<T> for FlatArc<T>
where
T: Recursive<Container = Arc<T>>,
{
fn from(value: T) -> Self {
Self::new_arc(value)
}
}
#[cfg(feature = "serde")]
impl<K> serde::Serialize for FlatDrop<K>
where
K: IntoOptionInner,
K::Inner: Recursive<Container = K>,
K: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
<K as serde::Serialize>::serialize(self, serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, K> serde::Deserialize<'de> for FlatDrop<K>
where
K: IntoOptionInner,
K::Inner: Recursive<Container = K>,
K: serde::Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
<K as serde::Deserialize>::deserialize(deserializer).map(Self::new)
}
}
#[cfg(test)]
mod tests {
use crate::{FlatDrop, Recursive};
enum Natural {
Zero,
Succ(FlatDrop<Box<Natural>>),
}
impl Recursive for Natural {
type Container = Box<Natural>;
fn destruct(self) -> impl Iterator<Item = Self::Container> {
match self {
Natural::Zero => None,
Natural::Succ(pred) => Some(pred.into_inner()),
}
.into_iter()
}
}
impl Natural {
pub fn from_usize(value: usize) -> Self {
(0..value).fold(Self::Zero, |nat, _| {
Self::Succ(FlatDrop::new(Box::new(nat)))
})
}
}
#[test]
fn test_large_natural() {
const STACK_SIZE: usize = 4 * 1024;
fn task() {
let nat = Natural::from_usize(STACK_SIZE * 100);
println!("Dropping...");
drop(std::hint::black_box(nat));
println!("Dropped.");
}
std::thread::Builder::new()
.stack_size(STACK_SIZE)
.spawn(task)
.unwrap()
.join()
.unwrap();
}
}