use std::mem;
use std::ptr;
use libc::{self, c_void};
#[derive(Copy, Eq, PartialEq)]
pub struct Man<T>(*mut T);
impl<T> Man<T> {
pub unsafe fn new(mut val: T) -> Man<T> {
let (size, ptr) = typed_malloc::<T>();
ptr::copy_nonoverlapping(&mut val, ptr, size);
mem::forget(val);
Man(ptr as *mut T)
}
pub unsafe fn from_raw(p: *const T) -> Man<T> {
Man(p as *mut T)
}
pub unsafe fn free(self) {
ptr::drop_in_place(self.0);
libc::free(self.0 as *mut c_void);
}
}
impl<T> Clone for Man<T> where T: Clone {
fn clone(&self) -> Self {
unsafe { Man::new(self.as_ref().clone()) }
}
}
unsafe fn typed_malloc<T>() -> (usize, *mut T) {
let size = mem::size_of::<T>();
match libc::malloc(size) as usize {
0 => panic!("malloc failed on size {}", size),
n @ _ => (size, n as *mut T)
}
}
impl<T> AsRef<T> for Man<T> {
fn as_ref(&self) -> &T {
unsafe { mem::transmute::<*mut T, &T>(self.0) }
}
}
impl<T> AsMut<T> for Man<T> {
fn as_mut(&mut self) -> &mut T {
unsafe { mem::transmute::<*mut T, &mut T>(self.0) }
}
}
#[cfg(test)]
mod tests {
use super::Man;
#[test]
pub fn test_man_dereference() {
unsafe {
let p = Man::new(42);
assert_eq!(*p.as_ref(), 42);
p.free()
}
}
#[test]
pub fn test_man_string() {
unsafe {
let p = Man::new(String::from("foobar"));
assert_eq!(p.as_ref().as_str(), "foobar");
p.free()
}
}
#[test]
pub fn test_man_big_drop() {
const KILOBYTE: usize = 1024;
unsafe {
for _ in 0..(64 * 1024 * 1024) {
let p = Man::new(Box::new([0u8; KILOBYTE])); }
}
}
}