#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(test)]
extern crate alloc;
#[cfg(feature = "std")]
use std as core;
use core::{
any::Any,
ffi::{c_char, CStr},
marker::PhantomData,
mem,
mem::ManuallyDrop,
pin::Pin,
ptr::NonNull,
};
mod impls;
mod iter;
mod sys;
pub use iter::*;
#[repr(transparent)]
pub struct Malloced<T: ?Sized> {
ptr: NonNull<T>,
_marker: PhantomData<T>,
}
impl<T> IntoIterator for Malloced<[T]> {
type Item = T;
type IntoIter = SliceIter<T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
unsafe {
let buf = self.ptr.cast::<T>();
let len = self.len();
mem::forget(self);
let ptr = buf.as_ptr();
let end = if mem::size_of::<T>() == 0 {
(ptr as *mut i8).wrapping_add(len) as *mut T
} else {
ptr.add(len)
};
SliceIter {
buf,
marker: PhantomData,
ptr,
end,
}
}
}
}
#[cfg(test)]
impl<T> Malloced<[T]> {
fn alloc(values: &[T]) -> Option<Self>
where
T: Copy,
{
let value_size = mem::size_of::<T>();
let alloc_size = values.len().checked_mul(value_size.max(1))?;
unsafe {
let buf = sys::malloc(alloc_size).cast::<T>();
if buf.is_null() {
return None;
}
for (i, &value) in values.iter().enumerate() {
let ptr: *mut T = if value_size == 0 {
buf.cast::<u8>().add(i).cast()
} else {
buf.add(i)
};
ptr.write(value);
}
Some(Malloced::slice_from_raw_parts(buf, values.len()))
}
}
}
impl<T: ?Sized> Malloced<T> {
#[inline]
pub unsafe fn from_raw(ptr: *mut T) -> Self {
Self {
ptr: NonNull::new_unchecked(ptr),
_marker: PhantomData,
}
}
#[inline]
pub fn into_raw(this: Self) -> *mut T {
Self::leak(this)
}
#[inline]
pub fn into_pin(this: Self) -> Pin<Malloced<T>> {
unsafe { Pin::new_unchecked(this) }
}
#[inline]
pub fn leak<'a>(this: Self) -> &'a mut T
where
T: 'a,
{
unsafe { &mut *ManuallyDrop::new(this).ptr.as_ptr() }
}
#[inline]
pub fn as_ptr(this: &Self) -> *const T {
this.ptr.as_ptr()
}
#[inline]
pub fn as_mut_ptr(this: &mut Self) -> *mut T {
this.ptr.as_ptr()
}
#[inline]
pub fn into_any(this: Self) -> Malloced<dyn Any>
where
T: Sized + Any,
{
let ptr = this.ptr.as_ptr() as *mut dyn Any;
mem::forget(this);
unsafe { Malloced::from_raw(ptr) }
}
#[inline]
pub fn into_any_send(this: Self) -> Malloced<dyn Any + Send + Sync>
where
T: Sized + Any + Send + Sync,
{
let ptr = this.ptr.as_ptr() as *mut (dyn Any + Send + Sync);
mem::forget(this);
unsafe { Malloced::from_raw(ptr) }
}
}
impl<T> Malloced<[T]> {
#[inline]
pub unsafe fn slice_from_raw_parts(data: *mut T, len: usize) -> Self {
Self::from_raw(core::ptr::slice_from_raw_parts_mut(data, len))
}
}
impl Malloced<CStr> {
#[inline]
pub unsafe fn from_ptr(ptr: *mut c_char) -> Self {
let len = if mem::size_of::<*mut CStr>() == mem::size_of::<*mut c_char>() {
1
} else {
CStr::from_ptr(ptr).to_bytes_with_nul().len()
};
let ptr = core::ptr::slice_from_raw_parts_mut(ptr, len) as *mut CStr;
Self::from_raw(ptr)
}
}
impl Malloced<dyn Any> {
#[inline]
pub fn downcast<T: Any>(self) -> Result<Malloced<T>, Self> {
if self.is::<T>() {
let raw: *mut dyn Any = Malloced::into_raw(self);
Ok(unsafe { Malloced::from_raw(raw as *mut T) })
} else {
Err(self)
}
}
}
impl Malloced<dyn Any + Send> {
#[inline]
pub fn downcast<T: Any>(self) -> Result<Malloced<T>, Self> {
if self.is::<T>() {
let raw: *mut (dyn Any + Send) = Malloced::into_raw(self);
Ok(unsafe { Malloced::from_raw(raw as *mut T) })
} else {
Err(self)
}
}
}
impl Malloced<dyn Any + Send + Sync> {
#[inline]
pub fn downcast<T: Any>(self) -> Result<Malloced<T>, Self> {
if self.is::<T>() {
let raw: *mut (dyn Any + Send + Sync) = Malloced::into_raw(self);
Ok(unsafe { Malloced::from_raw(raw as *mut T) })
} else {
Err(self)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
mod c_str {
use super::*;
#[test]
fn from_ptr() {
let buf = Malloced::<[c_char]>::alloc(&[b'h' as _, b'i' as _, 0]).unwrap();
let ptr = ManuallyDrop::new(buf).ptr.as_ptr() as *mut c_char;
let result = unsafe { Malloced::<CStr>::from_ptr(ptr) };
assert_eq!(result.to_bytes(), b"hi");
}
}
}