-
-
Save eddyb/82a442f0ef4d137a762e 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
#[lang="move"] | |
struct Move<Sized? T, S: MoveSource<T>> { | |
ptr: *mut T, | |
src: S | |
} | |
#[lang="move_source"] | |
trait MoveSource<Sized? T> { | |
unsafe fn cleanup(self, ptr: *mut T) {} | |
} | |
#[lang="move_stack"] | |
struct Stack<'a>; | |
impl<'a, T> MoveSource<T> For Stack<'a> { | |
// No need to "deallocate" stack values. | |
unsafe fn cleanup(self, _: *mut T) {} | |
} | |
impl<Sized? T, S: MoveSource<T>> Move<T, S> { | |
pub unsafe fn from(ptr: *mut T, src: S) -> Move<T, S> { | |
Move { | |
ptr: ptr, | |
src: src | |
} | |
} | |
pub unsafe fn into_parts(self) -> (*mut T, S) { | |
let (ptr, src) = (self.ptr, self.src); | |
mem::forget(self); | |
(ptr, src) | |
} | |
} | |
impl<Sized? T, S: MoveSource<T>> Drop for Move<T, S> { | |
fn drop(&mut self) { | |
drop_in_place(self.ptr); | |
// Maybe MoveSource should require Self be Copy? | |
self.src.cleanup(self.ptr); | |
} | |
} | |
trait DerefMove<S: MoveSource<Self>> { | |
type Out; | |
type OutSrc: MoveSource<Out>; | |
fn deref_move(self: Move<Self, S>) -> Move<Out, OutSrc>; | |
} | |
impl<Sized? T, S> DerefMove<S> for Box<T> { | |
type Out = T; | |
type OutSrc = Heap; | |
fn deref_move(self: Move<Box<T>, S>) -> Move<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 Move<Box<Foo>, Heap>, rather than the | |
// Move<Box<Box<Foo>>, Stack<'a>> that the compiler creates. | |
let the_box: Box<T> = *self; | |
unsafe { | |
Move::from(transmute::<Box<T>, *mut T>(the_box), Heap) | |
} | |
} | |
} | |
struct Heap; | |
impl<Sized? T> MoveSource<T> for Heap { | |
unsafe fn cleanup(self, ptr: *mut T) { | |
heap::deallocate(data_pointer(ptr), size_of_val(&*ptr)); | |
} | |
} | |
impl<T, S> DerefMove<S> for Vec<T> { | |
type Out = [T]; | |
type OutSrc = HeapSized; | |
fn deref_move(self: Move<Vec<T>, S>) -> Move<T, HeapSized> { | |
let vec: *mut [T] = &mut *self; | |
let size = self.capacity * mem::size_of::<T>(); | |
unsafe { | |
mem::forget(self); | |
Move::from(vec, HeapSized(size)) | |
} | |
} | |
} | |
struct HeapSized(uint); | |
impl<Sized? T> MoveSource<T> for HeapSized { | |
unsafe fn cleanup(self, ptr: *mut T) { | |
heap::deallocate(data_pointer(ptr), self.0); | |
} | |
} | |
struct MoveItems<T, S: MoveSource<[T]>> { | |
start: *mut T, | |
end: *mut T, | |
// This might be better off as a per-type-implementing-MoveSource | |
// custom "bundled dtor". Would be zero-sized for Stack and just | |
// (*mut T, uint) (w/o the length of *mut [T]) for HeapSized. | |
alloc: *mut [T], | |
src: S | |
} | |
impl<T, S: MoveSource<[T]>> IntoIter for Move<[T], S> { | |
type Iter = MoveItems<T, S>; | |
fn into_iter(self) -> MoveItems<T, S> { | |
unsafe { | |
let (start, len) = (self.as_mut_ptr(), self.len()); | |
let (alloc, src) = Move::into_parts(self); | |
MoveItems { | |
start: start, | |
end: start.offset(len), | |
alloc: alloc, | |
src: src | |
} | |
} | |
} | |
} | |
impl<T, S: MoveSource<[T]>> Drop for MoveItems<T, S> { | |
fn drop(&mut self) { | |
for _ in self {} | |
self.src.cleanup(self.alloc); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
MoveSource
needs to be an RFC19unsafe impl
, in addition tocleanup
being an unsafe function.Bikeshed: I think
MoveSource
should be calledDealloc
orCleanup
andMove
be calledRoot
.