Skip to content

Instantly share code, notes, and snippets.

@mikeyhew
Last active June 5, 2018 06:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikeyhew/8ac8bbb77803ee239daeeffc7028a8b7 to your computer and use it in GitHub Desktop.
Save mikeyhew/8ac8bbb77803ee239daeeffc7028a8b7 to your computer and use it in GitHub Desktop.
DerefMove and DerefInto
#![feature(arbitrary_self_types, specialization)]
use std::{
mem::{self, ManuallyDrop},
ptr::{self, NonNull},
marker::PhantomData,
ops::{Deref, DerefMut},
};
struct Move<'a, T: 'a + ?Sized> {
ptr: NonNull<T>,
_marker: PhantomData<&'a mut [u8]>,
}
impl<'a, T: 'a + ?Sized> Move<'a, T> {
/// Constructs a Move<T> from an &mut T
/// will take ownership of the T, and you must
/// avoid the original T from being destructed
/// mem::ManuallyDrop is a good way to do that
unsafe fn from_mut(r: &mut T) -> Self {
Move {
ptr: NonNull::new_unchecked(r),
_marker: PhantomData,
}
}
}
impl<'a, T: ?Sized> Drop for Move<'a, T> {
fn drop(&mut self) {
unsafe { ptr::drop_in_place(self.ptr.as_ptr()) };
}
}
impl<'a, T: ?Sized> Deref for Move<'a, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { self.ptr.as_ref() }
}
}
impl<'a, T: ?Sized> DerefMut for Move<'a, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { self.ptr.as_mut() }
}
}
impl<'a, T: ?Sized> DerefMove for Move<'a, T> {
fn deref_move<'b, F, Output>(self: Move<'b, Self>, f: F) -> Output
where
F: for<'c> FnOnce(Move<'c, Self::Target>) -> Output
{
f(self.deref_into())
}
}
impl<'a, T: Sized> DerefInto for Move<'a, T> {
fn deref_into(self) -> T {
let ptr = self.ptr;
mem::forget(self);
unsafe { ptr::read(ptr.as_ptr()) }
}
}
trait DerefInto: DerefMut {
fn deref_into(self) -> Self::Target;
}
trait DerefMove: DerefMut {
fn deref_move<'a, F, Output>(self: Move<'a, Self>, f: F) -> Output
where
F: for<'b> FnOnce(Move<'b, Self::Target>) -> Output;
}
impl<T: Sized> DerefInto for T
where
T: DerefMove,
T::Target: Sized,
{
default fn deref_into(self) -> Self::Target {
let mut holder = ManuallyDrop::new(self);
let move_ref = unsafe { Move::from_mut(&mut *holder) };
move_ref.deref_move(|move_ref| {
move_ref.deref_into()
})
}
}
// requiring `T: Sized` until `ManuallyDrop` supports `T: ?Sized`
impl<T: Sized> DerefMove for Box<T> {
fn deref_move<'a, F, Output>(self: Move<'a, Self>, f: F) -> Output
where
F: for<'b> FnOnce(Move<'b, Self::Target>) -> Output
{
let bx: Box<T> = self.deref_into();
let mut holder: Box<ManuallyDrop<T>> = unsafe { mem::transmute(bx) };
let move_ref = unsafe { Move::from_mut(&mut **holder) };
f(move_ref)
}
}
fn main() {
// current Box special-casing
let bx = Box::new(vec![1,2,3]);
let vec: Vec<i32> = *bx;
println!("Box special-casing: {:?}", vec);
// same effect using DerefInto
let bx = Box::new(vec![4,5,6]);
let vec: Vec<i32> = bx.deref_into();
println!("DerefInto: {:?}", vec);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment