-
-
Save eddyb/e0f4af9a1f0b28f66910 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="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