use std::mem;
use std::ptr;
pub struct EmptyBox<T> {
ptr: *mut T,
}
impl<T> Drop for EmptyBox<T> {
fn drop(&mut self) {
let boxed = unsafe { Box::from_raw(self.ptr) };
let inner = *boxed;
mem::forget(inner);
}
}
impl<T> EmptyBox<T> {
pub fn take(bx: Box<T>) -> (T, EmptyBox<T>) {
let ptr = Box::into_raw(bx);
let t = unsafe { ptr::read(ptr) };
(t, EmptyBox { ptr })
}
pub fn put(self, t: T) -> Box<T> {
let EmptyBox { ptr } = self;
mem::forget(self);
unsafe {
ptr::write(ptr, t);
Box::from_raw(ptr)
}
}
}
#[cfg(test)]
mod test {
use std::cell::Cell;
use super::*;
#[derive(Clone)]
pub struct DropCounter<'a>(&'a Cell<usize>);
impl<'a> Drop for DropCounter<'a> {
fn drop(&mut self) {
let prev = self.0.get();
self.0.set(prev + 1);
}
}
#[test]
fn drop_counter() {
let counter = Cell::new(0);
mem::drop(DropCounter(&counter));
mem::drop(DropCounter(&counter));
let dc = DropCounter(&counter);
assert_eq!(counter.get(), 2);
mem::drop(dc);
assert_eq!(counter.get(), 3);
}
#[test]
fn no_drop() {
let counter = Cell::new(0);
let dc = {
let boxed = Box::new(DropCounter(&counter));
EmptyBox::take(boxed).0
};
assert_eq!(counter.get(), 0);
mem::drop(dc);
}
#[test]
fn two_drop() {
let counter = Cell::new(0);
let boxed = Box::new(DropCounter(&counter));
let (dc, empty) = EmptyBox::take(boxed);
mem::drop(dc);
mem::drop(empty.put(DropCounter(&counter)));
assert_eq!(counter.get(), 2);
}
}