use std::ptr;
use std::slice;
use std::ops::{Index, IndexMut};
pub struct CVec<T> {
base: *mut T,
len: usize,
dtor: Option<Box<FnMut(*mut T)>>
}
impl<T> Drop for CVec<T> {
fn drop(&mut self) {
if let Some(mut f) = self.dtor.take() {
f(self.base);
}
}
}
impl<T> CVec<T> {
pub unsafe fn new(base: *mut T, len: usize) -> CVec<T> {
assert!(base != ptr::null_mut());
CVec {
base: base,
len: len,
dtor: None,
}
}
pub unsafe fn new_with_dtor<F>(base: *mut T,
len: usize,
dtor: F)
-> CVec<T>
where F: FnMut(*mut T) + 'static
{
assert!(base != ptr::null_mut());
let dtor = Box::new(dtor);
CVec {
base: base,
len: len,
dtor: Some(dtor)
}
}
pub fn get<'a>(&'a self, ofs: usize) -> Option<&'a T> {
if ofs < self.len {
Some(unsafe { &*self.base.offset(ofs as isize) })
} else {
None
}
}
pub fn get_mut<'a>(&'a mut self, ofs: usize) -> Option<&'a mut T> {
if ofs < self.len {
Some(unsafe { &mut *self.base.offset(ofs as isize) })
} else {
None
}
}
pub unsafe fn into_inner(mut self) -> *mut T {
self.dtor = None;
self.base
}
pub fn len(&self) -> usize { self.len }
pub fn is_empty(&self) -> bool { self.len() == 0 }
pub unsafe fn as_cslice(&self) -> CSlice<T> {
CSlice {
base: self.base,
len: self.len
}
}
}
impl<T> AsRef<[T]> for CVec<T> {
fn as_ref(&self) -> &[T] {
unsafe {
slice::from_raw_parts(self.base as *const T, self.len)
}
}
}
impl<T> AsMut<[T]> for CVec<T> {
fn as_mut(&mut self) -> &mut [T] {
unsafe {
slice::from_raw_parts_mut(self.base, self.len)
}
}
}
pub struct CSlice<T> {
base: *mut T,
len: usize
}
impl<T> CSlice<T> {
pub unsafe fn new(base: *mut T, len: usize) -> CSlice<T> {
assert!(base != ptr::null_mut());
CSlice {
base: base,
len: len
}
}
pub fn get<'a>(&'a self, ofs: usize) -> Option<&'a T> {
if ofs < self.len {
Some(unsafe { &*self.base.offset(ofs as isize) })
} else {
None
}
}
pub fn get_mut<'a>(&'a mut self, ofs: usize) -> Option<&'a mut T> {
if ofs < self.len {
Some(unsafe { &mut *self.base.offset(ofs as isize) })
} else {
None
}
}
pub fn len(&self) -> usize { self.len }
pub fn is_empty(&self) -> bool { self.len() == 0 }
}
impl<T> AsRef<[T]> for CSlice<T> {
fn as_ref(&self) -> &[T] {
unsafe {
slice::from_raw_parts(self.base as *const T, self.len)
}
}
}
impl<T> AsMut<[T]> for CSlice<T> {
fn as_mut(&mut self) -> &mut [T] {
unsafe {
slice::from_raw_parts_mut(self.base, self.len)
}
}
}
impl<T> Index<usize> for CSlice<T> {
type Output = T;
fn index<'a>(&'a self, _index: usize) -> &'a T {
assert!(_index < self.len);
unsafe { &*self.base.offset(_index as isize) }
}
}
impl<T> IndexMut<usize> for CSlice<T> {
fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut T {
assert!(_index < self.len);
unsafe { &mut *self.base.offset(_index as isize) }
}
}
impl<T: Clone> Into<Vec<T>> for CSlice<T> {
fn into(self: CSlice<T>) -> Vec<T> {
let mut v = Vec::with_capacity(self.len);
v.extend_from_slice(self.as_ref());
v
}
}
impl<T: Clone> Into<Vec<T>> for CVec<T> {
fn into(self: CVec<T>) -> Vec<T> {
unsafe {
self.as_cslice().into()
}
}
}
#[cfg(test)]
mod tests {
extern crate libc;
use super::{CVec, CSlice};
use std::ptr;
fn v_malloc(n: usize) -> CVec<u8> {
unsafe {
let mem = libc::malloc(n as libc::size_t) as *mut u8;
CVec::new_with_dtor(mem, n, |mem| { libc::free((mem) as *mut _); })
}
}
fn s_malloc(n: usize) -> CSlice<u8> {
unsafe {
let mem: *mut u8 = libc::malloc(n as libc::size_t) as *mut _;
CSlice::new(mem, n)
}
}
#[test]
fn vec_test_basic() {
let mut cv = v_malloc(16);
*cv.get_mut(3).unwrap() = 8;
*cv.get_mut(4).unwrap() = 9;
assert_eq!(*cv.get(3).unwrap(), 8);
assert_eq!(*cv.get(4).unwrap(), 9);
assert_eq!(cv.len(), 16);
}
#[test]
fn slice_test_basic() {
let mut cs = s_malloc(16);
cs[3] = 8;
cs[4] = 9;
assert_eq!(cs[3], 8);
assert_eq!(cs[4], 9);
assert_eq!(cs.len(), 16);
}
#[test]
#[should_panic]
fn vec_test_panic_at_null() {
unsafe {
CVec::new(ptr::null_mut::<u8>(), 9);
}
}
#[test]
#[should_panic]
fn slice_test_panic_at_null() {
unsafe {
CSlice::new(ptr::null_mut::<u8>(), 9);
}
}
#[test]
fn vec_test_overrun_get() {
let cv = v_malloc(16);
assert!(cv.get(17).is_none());
}
#[test]
#[should_panic]
fn slice_test_overrun_get() {
let cs = s_malloc(16);
assert!(cs[17] == 18);
}
#[test]
fn vec_test_overrun_set() {
let mut cv = v_malloc(16);
assert!(cv.get_mut(17).is_none());
}
#[test]
fn vec_test_unwrap() {
unsafe {
let cv = CVec::new_with_dtor(1 as *mut isize,
0,
|_| panic!("Don't run this destructor!"));
let p = cv.into_inner();
assert_eq!(p, 1 as *mut isize);
}
}
#[test]
fn vec_to_slice_test() {
let mut cv = v_malloc(2);
*cv.get_mut(0).unwrap() = 10;
*cv.get_mut(1).unwrap() = 12;
unsafe {
let cs = cv.as_cslice();
assert_eq!(cs[0], 10);
assert_eq!(cs[1], 12);
}
}
#[test]
fn slice_to_vec_test() {
let cv = v_malloc(2);
unsafe {
let mut cs = cv.as_cslice();
cs[0] = 13;
cs[1] = 26;
assert_eq!(*cv.get(0).unwrap(), 13);
assert_eq!(*cv.get(1).unwrap(), 26);
}
}
#[test]
fn convert_test() {
let cv = v_malloc(2);
unsafe {
let mut cs = cv.as_cslice();
cs[0] = 1;
cs[1] = 99;
let v: Vec<_> = cs.into();
assert_eq!(1, v[0]);
assert_eq!(99, v[1]);
}
let v: Vec<_> = cv.into();
assert_eq!(1, v[0]);
assert_eq!(99, v[1]);
}
}