| #[lang="open"] | |
| struct Open<Sized? T, S: SlotSource<T>> { | |
| ptr: *mut T, | |
| src: S | |
| } | |
| #[lang="slot_source"] | |
| trait SlotSource<Sized? T> { | |
| unsafe fn cleanup(self, ptr: *mut T) {} | |
| } | |
| #[lang="slot_stack"] | |
| struct Stack<'a>; | |
| impl<'a, T> SlotSource<T> For Stack<'a> { | |
| // No need to "deallocate" stack values. | |
| } | |
| impl<Sized? T, S: SlotSource<T>> Open<T, S> { | |
| pub unsafe fn from_parts(ptr: *mut T, src: S) -> Open<T, S> { | |
| Open { | |
| 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: SlotSource<T>> Drop for Open<T, S> { | |
| fn drop(&mut self) { | |
| drop_in_place(self.ptr); | |
| // Maybe SlotSource should require Self be Copy? | |
| self.src.cleanup(self.ptr); | |
| } | |
| } | |
| trait DerefOpen<S: SlotSource<Self>> { | |
| type Out; | |
| type OutSrc: SlotSource<Out>; | |
| fn deref_move(self: Open<Self, S>) -> Open<Out, OutSrc>; | |
| } | |
| impl<Sized? T, S> DerefOpen<S> for Box<T> { | |
| type Out = T; | |
| type OutSrc = Heap; | |
| fn deref_move(self: Open<Box<T>, S>) -> Open<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 Open<Box<Foo>, Heap>, rather than the | |
| // Open<Box<Box<Foo>>, Stack<'a>> that the compiler creates. | |
| let the_box: Box<T> = *self; | |
| unsafe { | |
| Open::from_parts(transmute::<Box<T>, *mut T>(the_box), Heap) | |
| } | |
| } | |
| } | |
| struct Heap; | |
| impl<Sized? T> SlotSource<T> for Heap { | |
| unsafe fn cleanup(self, ptr: *mut T) { | |
| heap::deallocate(data_pointer(ptr), size_of_val(&*ptr)); | |
| } | |
| } | |
| impl<T, S> DerefOpen<S> for Vec<T> { | |
| type Out = [T]; | |
| type OutSrc = HeapSized; | |
| fn deref_move(self: Open<Vec<T>, S>) -> Open<T, HeapSized> { | |
| let vec: *mut [T] = &mut *self; | |
| let size = self.capacity * mem::size_of::<T>(); | |
| unsafe { | |
| mem::forget(self); | |
| Open::from_parts(vec, HeapSized(size)) | |
| } | |
| } | |
| } | |
| struct HeapSized(uint); | |
| impl<Sized? T> SlotSource<T> for HeapSized { | |
| unsafe fn cleanup(self, ptr: *mut T) { | |
| heap::deallocate(data_pointer(ptr), self.0); | |
| } | |
| } | |
| struct IntoIter<T, S: SlotSource<[T]>> { | |
| start: *mut T, | |
| end: *mut T, | |
| // This might be better off as a per-type-implementing-SlotSource | |
| // 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: SlotSource<[T]>> IntoIterator for Open<[T], S> { | |
| type Iter = IntoIter<T, S>; | |
| fn into_iter(self) -> IntoIter<T, S> { | |
| unsafe { | |
| let (start, len) = (self.as_mut_ptr(), self.len()); | |
| let (alloc, src) = Open::into_parts(self); | |
| IntoIter { | |
| start: start, | |
| end: start.offset(len), | |
| alloc: alloc, | |
| src: src | |
| } | |
| } | |
| } | |
| } | |
| impl<T, S: SlotSource<[T]>> Drop for IntoIter<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