| #[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
This comment has been minimized.
arielb1 commentedNov 26, 2014
MoveSourceneeds to be an RFC19unsafe impl, in addition tocleanupbeing an unsafe function.Bikeshed: I think
MoveSourceshould be calledDeallocorCleanupandMovebe calledRoot.