Created
July 19, 2015 17:55
-
-
Save eddyb/cce96357c8083d88819a to your computer and use it in GitHub Desktop.
This file contains 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
mod owned { | |
#[lang="own_in"] | |
struct OwnIn<T: ?Sized, P: Place<T>> { | |
ptr: *mut T, | |
place: P | |
} | |
#[lang="place"] | |
trait Place<T: ?Sized> { | |
unsafe fn cleanup(self, ptr: *mut T) {} | |
} | |
#[lang="place_stack"] | |
struct Stack<'a>; | |
type Own<'a, T> = OwnIn<T, Stack<'a>>; | |
impl<'a, T> Place<T> For Stack<'a> { | |
// No need to "deallocate" stack values. | |
} | |
impl<T: ?Sized, P: Place<T>> OwnIn<T, P> { | |
pub unsafe fn from_parts(ptr: *mut T, place: P) -> OwnIn<T, P> { | |
OwnIn { | |
ptr: ptr, | |
place: place | |
} | |
} | |
pub fn into_parts(self) -> (*mut T, P) { | |
let (ptr, place) = (self.ptr, self.place); | |
mem::forget(self); | |
(ptr, place) | |
} | |
} | |
impl<T: ?Sized, P: Place<T>> Drop for OwnIn<T, P> { | |
fn drop(&mut self) { | |
unsafe { | |
intrinsics::drop_in_place(self.ptr); | |
// Maybe Place should require Self: Copy? | |
self.place.cleanup(self.ptr); | |
} | |
} | |
} | |
trait DerefOwn<P: Place<Self>>: Deref { | |
type TargetPlace: Place<Self::Target>; | |
fn deref_move(self: OwnIn<Self, P>) -> OwnIn<Self::Target, Self::TargetPlace>; | |
} | |
} | |
mod boxed { | |
impl<T: ?Sized, P> DerefOwn<P> for Box<T> { | |
type TargetPlace = Heap; | |
fn deref_move(self: OwnIn<Box<T>, P>) -> OwnIn<T, Heap> { | |
// The way this works, {**box box foo} will free the outer box, | |
// move the value out, and only then it would free the inner box. | |
// The outer box can be freed early because it's cheaper and more | |
// flexible to pass around OwnIn<Box<Foo>, Heap>, rather than the | |
// OwnIn<Box<Box<Foo>>, Stack<'a>> that the compiler creates. | |
let the_box: Box<T> = *self; | |
unsafe { | |
OwnIn::from_parts(Box::into_raw(the_box), Heap) | |
} | |
} | |
} | |
struct Heap; | |
impl<T: ?Sized> Place<T> for Heap { | |
unsafe fn cleanup(self, ptr: *mut T) { | |
heap::deallocate(data_pointer(ptr), size_of_val(&*ptr)); | |
} | |
} | |
} | |
mod vec { | |
impl<T, P> DerefOwn<P> for Vec<T> { | |
type TargetPlace = HeapSized; | |
fn deref_move(self: OwnIn<Vec<T>, P>) -> OwnIn<T, HeapSized> { | |
let vec: *mut [T] = &mut *self; | |
let size = self.capacity * mem::size_of::<T>(); | |
mem::forget(self); | |
unsafe { | |
OwnIn::from_parts(vec, HeapSized(size)) | |
} | |
} | |
} | |
struct HeapSized(usize); | |
impl<T: ?Sized> Place<T> for HeapSized { | |
unsafe fn cleanup(self, ptr: *mut T) { | |
heap::deallocate(data_pointer(ptr), self.0); | |
} | |
} | |
} | |
mod slice { | |
struct IntoIter<T, P: Place<[T]>> { | |
start: *mut T, | |
end: *mut T, | |
// This might be better off as a per-type-implementing-Place | |
// custom "bundled dtor". Would be zero-sized for Stack and just | |
// (*mut T, usize) (w/o the length of *mut [T]) for HeapSized. | |
alloc: *mut [T], | |
place: P | |
} | |
impl<T, P: Place<[T]>> IntoIterator for OwnIn<[T], P> { | |
type Iter = IntoIter<T, P>; | |
fn into_iter(self) -> IntoIter<T, P> { | |
let (start, len) = (self.as_mut_ptr(), self.len()); | |
let (alloc, place) = OwnIn::into_parts(self); | |
IntoIter { | |
start: start, | |
end: start.offset(len), | |
alloc: alloc, | |
place: place | |
} | |
} | |
} | |
impl<T, P: Place<[T]>> Drop for IntoIter<T, P> { | |
fn drop(&mut self) { | |
for _ in self {} | |
self.place.cleanup(self.alloc); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment