Last active
August 3, 2024 15:19
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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