Skip to content

Instantly share code, notes, and snippets.

@eddyb

eddyb/open.rs Secret

Created January 31, 2015 13:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eddyb/e0f4af9a1f0b28f66910 to your computer and use it in GitHub Desktop.
Save eddyb/e0f4af9a1f0b28f66910 to your computer and use it in GitHub Desktop.
#[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