use std::alloc::{GlobalAlloc, Layout};
use std::os::raw::c_void;
use rustmex_core::shim::{rustmex_malloc, rustmex_free, rustmex_make_memory_persistent};
#[allow(non_camel_case_types)]
pub struct mxAlloc;
#[cfg(not(test))]
#[cfg(any(feature = "alloc", feature = "doc"))]
#[global_allocator]
static ALLOCATOR: mxAlloc = mxAlloc;
unsafe impl GlobalAlloc for mxAlloc {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let ptr = rustmex_malloc(layout.size());
if !ptr.is_null() {
rustmex_make_memory_persistent(ptr);
}
ptr as *mut u8
}
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
rustmex_free(ptr as *mut c_void);
}
}
use std::ptr::NonNull;
use std::ops::{Deref, DerefMut};
pub struct NonPersistent<T: ?Sized>(NonNull<T>);
impl<T> NonPersistent<T> {
pub unsafe fn new(t: T) -> Self {
let nn = NonNull::new(rustmex_malloc(std::mem::size_of::<T>()) as *mut T)
.expect("OOM");
std::ptr::write(nn.as_ptr(), t);
Self(nn)
}
}
impl<T: Copy> NonPersistent<T> {
pub fn inner(np: NonPersistent<T>) -> T {
*unsafe { np.0.as_ref() }
}
}
#[cfg(doc)]
#[allow(unused_imports)]
use std::ffi::CString;
impl NonPersistent<[u8]> {
pub unsafe fn from_stringish<B: AsRef<[u8]>>(b: B, append_null: bool) -> Self {
let b = b.as_ref();
let l = b.len() + if append_null { 1 } else { 0 };
let ptr = rustmex_malloc(l) as *mut u8;
if ptr.is_null() {
panic!("OOM");
}
let b2 = std::slice::from_raw_parts_mut(ptr, l);
b2[0..b.len()].copy_from_slice(b);
if append_null {
b2[b.len()] = b'\0';
}
NonPersistent(NonNull::from(b2))
}
}
impl<T: ?Sized> NonPersistent<T> {
pub unsafe fn ptr(np: &NonPersistent<T>) -> *const T {
np.0.as_ptr()
}
pub unsafe fn mut_ptr(np: &mut NonPersistent<T>) -> *mut T {
np.0.as_ptr()
}
pub fn persist(mut np: NonPersistent<T>) -> Box<T> {
let ptr = unsafe { Self::mut_ptr(&mut np) };
unsafe { rustmex_make_memory_persistent(ptr as *mut c_void); }
std::mem::forget(np);
unsafe { Box::from_raw(ptr) }
}
}
impl<T: ?Sized> Deref for NonPersistent<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.0.as_ref() }
}
}
impl<T: ?Sized> DerefMut for NonPersistent<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.0.as_mut() }
}
}
impl<T: ?Sized> AsRef<T> for NonPersistent<T> {
fn as_ref(&self) -> &T {
self.deref()
}
}
impl<T: ?Sized> AsMut<T> for NonPersistent<T> {
fn as_mut(&mut self) -> &mut T {
self.deref_mut()
}
}
impl<T: ?Sized> std::ops::Drop for NonPersistent<T> {
fn drop(&mut self) {
unsafe {
let ptr = self.0.as_mut();
std::ptr::drop_in_place(ptr);
rustmex_free(ptr as *mut T as *mut c_void);
}
}
}
unsafe impl<T> std::marker::Sync for NonPersistent<T> where T: Sync + ?Sized {}
unsafe impl<T> std::marker::Send for NonPersistent<T> where T: Send + ?Sized {}
use std::fmt;
impl<T: ?Sized> fmt::Debug for NonPersistent<T> where T: fmt::Debug {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "NonPersistent(")?;
self.deref().fmt(f)?;
write!(f, ")")
}
}
impl<T: ?Sized> fmt::Display for NonPersistent<T> where T: fmt::Display {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.deref().fmt(f)
}
}
use std::cmp::{PartialEq, Eq};
impl<T: ?Sized, Other> PartialEq<Other> for NonPersistent<T> where T: PartialEq<Other> {
fn eq(&self, other: &Other) -> bool {
self.deref().eq(other)
}
}
impl<T: ?Sized> Eq for NonPersistent<T> where T: Eq + PartialEq<NonPersistent<T>> {}