mdarray 0.3.0

Multidimensional array for Rust
Documentation
use std::alloc::{self, Allocator, Layout};
use std::marker::PhantomData;
use std::ptr::NonNull;
use std::{cmp, mem};

pub struct RawVec<T, A: Allocator> {
    ptr: NonNull<T>,
    capacity: usize,
    alloc: A,
    _marker: PhantomData<T>,
}

impl<T, A: Allocator> RawVec<T, A> {
    pub fn allocator(&self) -> &A {
        &self.alloc
    }

    pub fn as_mut_ptr(&mut self) -> *mut T {
        self.ptr.as_ptr()
    }

    pub fn as_ptr(&self) -> *const T {
        self.ptr.as_ptr()
    }

    pub fn capacity(&self) -> usize {
        self.capacity
    }

    pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self {
        Self { ptr: NonNull::new_unchecked(ptr), capacity, alloc, _marker: PhantomData }
    }

    pub fn grow(&mut self, capacity: usize) {
        self.grow_exact(cmp::max(2 * self.capacity, capacity));
    }

    pub fn grow_exact(&mut self, capacity: usize) {
        let new_layout = Layout::array::<T>(capacity).unwrap();

        let result = if self.capacity == 0 {
            self.alloc.allocate(new_layout)
        } else {
            let old_layout = Layout::array::<T>(self.capacity).unwrap();

            unsafe { self.alloc.grow(self.ptr.cast(), old_layout, new_layout) }
        };

        let ptr = match result {
            Ok(ptr) => ptr,
            Err(_) => alloc::handle_alloc_error(new_layout),
        };

        self.ptr = ptr.cast();
        self.capacity = ptr.len() / mem::size_of::<T>();
    }

    pub fn new_in(alloc: A) -> Self {
        Self { ptr: NonNull::dangling(), capacity: 0, alloc, _marker: PhantomData }
    }

    pub fn shrink(&mut self, capacity: usize) {
        let old_layout = Layout::array::<T>(self.capacity).unwrap();
        let new_layout = Layout::array::<T>(capacity).unwrap();

        let result = unsafe { self.alloc.shrink(self.ptr.cast(), old_layout, new_layout) };

        let ptr = match result {
            Ok(ptr) => ptr,
            Err(_) => alloc::handle_alloc_error(new_layout),
        };

        self.ptr = ptr.cast();
        self.capacity = ptr.len() / mem::size_of::<T>();
    }

    pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
        let layout = Layout::array::<T>(capacity).unwrap();

        let ptr = match alloc.allocate(layout) {
            Ok(ptr) => ptr,
            Err(_) => alloc::handle_alloc_error(layout),
        };

        Self {
            ptr: ptr.cast(),
            capacity: ptr.len() / mem::size_of::<T>(),
            alloc,
            _marker: PhantomData,
        }
    }
}

impl<T, A: Allocator> Drop for RawVec<T, A> {
    fn drop(&mut self) {
        if self.capacity > 0 {
            let layout = Layout::array::<T>(self.capacity).unwrap();

            unsafe { self.alloc.deallocate(self.ptr.cast(), layout) }
        }
    }
}

unsafe impl<T: Send, A: Allocator + Send> Send for RawVec<T, A> {}
unsafe impl<T: Sync, A: Allocator + Sync> Sync for RawVec<T, A> {}