Skip to content

Instantly share code, notes, and snippets.

@cppio
Last active August 3, 2024 15:19
Show Gist options
  • Select an option

  • Save cppio/4f3ab339bb99b017c841319a0807faf6 to your computer and use it in GitHub Desktop.

Select an option

Save cppio/4f3ab339bb99b017c841319a0807faf6 to your computer and use it in GitHub Desktop.
Rust technique to allow a recursive type to be destructured while having an optimized drop implementation.
use std::{
mem::ManuallyDrop,
ops::{Deref, DerefMut},
};
pub trait BoxDrop {
fn drop(self: Box<Self>);
}
#[repr(transparent)]
pub struct DropBox<T: BoxDrop + ?Sized>(ManuallyDrop<Box<T>>);
impl<T: BoxDrop + ?Sized> DropBox<T> {
pub fn from_box(boxed: Box<T>) -> Self {
Self(ManuallyDrop::new(boxed))
}
pub fn into_box(this: Self) -> Box<T> {
let slot = &mut ManuallyDrop::new(this).0;
unsafe { ManuallyDrop::take(slot) }
}
}
impl<T: BoxDrop> DropBox<T> {
pub fn new(value: T) -> Self {
Self::from_box(Box::new(value))
}
pub fn into_inner(this: Self) -> T {
*Self::into_box(this)
}
}
impl<T: BoxDrop + ?Sized> Drop for DropBox<T> {
fn drop(&mut self) {
let slot = &mut self.0;
BoxDrop::drop(unsafe { ManuallyDrop::take(slot) });
}
}
impl<T: BoxDrop + ?Sized> Deref for DropBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T: BoxDrop + ?Sized> DerefMut for DropBox<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
pub enum List<T> {
Nil,
Cons(T, DropBox<Self>),
}
impl<T> BoxDrop for List<T> {
fn drop(mut self: Box<Self>) {
while let Self::Cons(_, tl) = *self {
self = DropBox::into_box(tl);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment