use debug;
#[derive(Debug)]
pub struct Garbage {
ptr: *const u8,
dtor: unsafe fn(*const u8),
}
impl Garbage {
pub fn new(ptr: *const u8, dtor: fn(*const u8)) -> Garbage {
debug_assert!(ptr as usize > 0, "Creating garbage with invalid pointer.");
Garbage {
ptr: ptr,
dtor: dtor,
}
}
pub unsafe fn new_box<T>(item: *const T) -> Garbage {
unsafe fn dtor<T>(ptr: *const u8) {
Box::from_raw(ptr as *mut u8 as *mut T);
}
Garbage {
ptr: item as *const u8,
dtor: dtor::<T>,
}
}
pub fn ptr(&self) -> *const u8 {
self.ptr
}
}
impl Drop for Garbage {
fn drop(&mut self) {
debug::exec(|| println!("Destroying garbage: {:?}", self));
unsafe { (self.dtor)(self.ptr); }
}
}
unsafe impl Send for Garbage {}
#[cfg(test)]
mod tests {
use super::*;
use std::ptr;
fn nop(_: *const u8) {}
#[test]
fn ptr() {
let g = Garbage::new(0x2 as *const u8, nop);
assert_eq!(g.ptr() as usize, 2);
}
#[test]
fn new_box() {
for _ in 0..1000 {
unsafe { Garbage::new_box(Box::into_raw(Box::new(2))); }
}
}
#[cfg(debug_assertions)]
#[test]
#[should_panic]
fn debug_invalid_pointer() {
Garbage::new(ptr::null(), nop);
}
}