Skip to content

Instantly share code, notes, and snippets.

@eddyb
Created July 19, 2015 17:55
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/cce96357c8083d88819a to your computer and use it in GitHub Desktop.
Save eddyb/cce96357c8083d88819a to your computer and use it in GitHub Desktop.
mod owned {
#[lang="own_in"]
struct OwnIn<T: ?Sized, P: Place<T>> {
ptr: *mut T,
place: P
}
#[lang="place"]
trait Place<T: ?Sized> {
unsafe fn cleanup(self, ptr: *mut T) {}
}
#[lang="place_stack"]
struct Stack<'a>;
type Own<'a, T> = OwnIn<T, Stack<'a>>;
impl<'a, T> Place<T> For Stack<'a> {
// No need to "deallocate" stack values.
}
impl<T: ?Sized, P: Place<T>> OwnIn<T, P> {
pub unsafe fn from_parts(ptr: *mut T, place: P) -> OwnIn<T, P> {
OwnIn {
ptr: ptr,
place: place
}
}
pub fn into_parts(self) -> (*mut T, P) {
let (ptr, place) = (self.ptr, self.place);
mem::forget(self);
(ptr, place)
}
}
impl<T: ?Sized, P: Place<T>> Drop for OwnIn<T, P> {
fn drop(&mut self) {
unsafe {
intrinsics::drop_in_place(self.ptr);
// Maybe Place should require Self: Copy?
self.place.cleanup(self.ptr);
}
}
}
trait DerefOwn<P: Place<Self>>: Deref {
type TargetPlace: Place<Self::Target>;
fn deref_move(self: OwnIn<Self, P>) -> OwnIn<Self::Target, Self::TargetPlace>;
}
}
mod boxed {
impl<T: ?Sized, P> DerefOwn<P> for Box<T> {
type TargetPlace = Heap;
fn deref_move(self: OwnIn<Box<T>, P>) -> OwnIn<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 OwnIn<Box<Foo>, Heap>, rather than the
// OwnIn<Box<Box<Foo>>, Stack<'a>> that the compiler creates.
let the_box: Box<T> = *self;
unsafe {
OwnIn::from_parts(Box::into_raw(the_box), Heap)
}
}
}
struct Heap;
impl<T: ?Sized> Place<T> for Heap {
unsafe fn cleanup(self, ptr: *mut T) {
heap::deallocate(data_pointer(ptr), size_of_val(&*ptr));
}
}
}
mod vec {
impl<T, P> DerefOwn<P> for Vec<T> {
type TargetPlace = HeapSized;
fn deref_move(self: OwnIn<Vec<T>, P>) -> OwnIn<T, HeapSized> {
let vec: *mut [T] = &mut *self;
let size = self.capacity * mem::size_of::<T>();
mem::forget(self);
unsafe {
OwnIn::from_parts(vec, HeapSized(size))
}
}
}
struct HeapSized(usize);
impl<T: ?Sized> Place<T> for HeapSized {
unsafe fn cleanup(self, ptr: *mut T) {
heap::deallocate(data_pointer(ptr), self.0);
}
}
}
mod slice {
struct IntoIter<T, P: Place<[T]>> {
start: *mut T,
end: *mut T,
// This might be better off as a per-type-implementing-Place
// custom "bundled dtor". Would be zero-sized for Stack and just
// (*mut T, usize) (w/o the length of *mut [T]) for HeapSized.
alloc: *mut [T],
place: P
}
impl<T, P: Place<[T]>> IntoIterator for OwnIn<[T], P> {
type Iter = IntoIter<T, P>;
fn into_iter(self) -> IntoIter<T, P> {
let (start, len) = (self.as_mut_ptr(), self.len());
let (alloc, place) = OwnIn::into_parts(self);
IntoIter {
start: start,
end: start.offset(len),
alloc: alloc,
place: place
}
}
}
impl<T, P: Place<[T]>> Drop for IntoIter<T, P> {
fn drop(&mut self) {
for _ in self {}
self.place.cleanup(self.alloc);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment