#[cfg(not(feature = "std"))]
extern crate alloc;
use libc::c_void;
use std::alloc::Layout;
use std::marker::PhantomData;
use std::mem::{align_of, size_of};
use std::ptr::{copy_nonoverlapping, NonNull};
#[cfg(not(feature = "std"))]
use self::alloc::alloc::handle_alloc_error;
#[cfg(feature = "std")]
use std::alloc::handle_alloc_error;
#[cfg(feature = "nightly")]
use std::marker::Unsize;
#[cfg(feature = "nightly")]
use std::ops::CoerceUnsized;
pub struct Unique<T: ?Sized> {
pointer: NonNull<T>,
marker: PhantomData<T>,
}
unsafe impl<T: Send + ?Sized> Send for Unique<T> {}
unsafe impl<T: Sync + ?Sized> Sync for Unique<T> {}
impl<T: ?Sized> Unique<T> {
pub const unsafe fn new(pointer: NonNull<T>) -> Self {
Self {
pointer,
marker: PhantomData,
}
}
}
impl<T: ?Sized> Unique<T> {
pub fn as_non_null_ptr(&self) -> NonNull<T> {
self.pointer
}
}
#[cfg(feature = "nightly")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> {}
#[cfg(windows)]
unsafe fn malloc_aligned<T>(size: usize) -> *mut c_void {
struct AlignmentChecker<T>(PhantomData<T>);
impl<T> AlignmentChecker<T> {
const ENSURE_ALIGNMENT_IS_1: usize = 1 - align_of::<T>();
}
assert_eq!(
0,
AlignmentChecker::<T>::ENSURE_ALIGNMENT_IS_1,
"Windows malloc() only support alignment of 1"
);
libc::malloc(size)
}
#[cfg(all(not(windows), target_os = "android"))]
unsafe fn malloc_aligned<T>(size: usize) -> *mut c_void {
libc::memalign(align_of::<T>(), size)
}
#[cfg(all(not(windows), not(target_os = "android")))]
unsafe fn malloc_aligned<T>(size: usize) -> *mut c_void {
let mut result = std::ptr::null_mut();
let align = align_of::<T>().max(size_of::<*mut ()>());
libc::posix_memalign(&mut result, align, size);
result
}
pub fn gen_malloc<T>(count: usize) -> NonNull<T> {
let requested_size = count.checked_mul(size_of::<T>()).expect("memory overflow");
let mut res;
unsafe {
res = malloc_aligned::<T>(requested_size);
if res.is_null() && requested_size == 0 {
res = malloc_aligned::<T>(align_of::<T>());
}
}
NonNull::new(res as *mut T).unwrap_or_else(|| handle_alloc_error(Layout::new::<T>()))
}
pub unsafe fn gen_free<T>(ptr: NonNull<T>) {
libc::free(ptr.as_ptr() as *mut c_void);
}
pub unsafe fn gen_realloc<T>(ptr: NonNull<T>, old_count: usize, new_count: usize) -> NonNull<T> {
if size_of::<T>() == 0 {
return ptr;
}
(|| {
let requested_size = new_count.checked_mul(size_of::<T>())?.max(align_of::<T>());
let mut res = libc::realloc(ptr.as_ptr() as *mut c_void, requested_size);
if res.is_null() {
return None;
}
if res as usize % align_of::<T>() != 0 {
let actual_res = malloc_aligned::<T>(requested_size);
if actual_res.is_null() {
return None;
}
let copy_len = old_count.min(new_count) * size_of::<T>();
copy_nonoverlapping(res, actual_res, copy_len);
libc::free(res);
res = actual_res;
}
NonNull::new(res as *mut T)
})()
.unwrap_or_else(|| handle_alloc_error(Layout::new::<T>()))
}
#[cfg(all(test, not(windows)))]
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Default))]
pub(crate) struct SharedCounter {
#[cfg(feature = "std")]
counter: std::rc::Rc<std::cell::Cell<usize>>,
#[cfg(not(feature = "std"))]
counter: NonNull<usize>,
}
#[cfg(all(test, not(windows), not(feature = "std")))]
impl Default for SharedCounter {
fn default() -> Self {
let counter = gen_malloc(1);
unsafe {
std::ptr::write(counter.as_ptr(), 0);
Self { counter }
}
}
}
#[cfg(all(test, not(windows)))]
impl SharedCounter {
pub(crate) fn get(&self) -> usize {
#[cfg(feature = "std")]
{
self.counter.get()
}
#[cfg(not(feature = "std"))]
unsafe {
*self.counter.as_ref()
}
}
pub(crate) fn assert_eq(&self, value: usize) {
assert_eq!(self.get(), value);
}
fn inc(&self) {
#[cfg(feature = "std")]
{
self.counter.set(self.counter.get() + 1);
}
#[cfg(not(feature = "std"))]
unsafe {
*self.counter.as_ptr() += 1;
}
}
}
#[cfg(all(test, not(windows)))]
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub(crate) struct DropCounter(SharedCounter);
#[cfg(all(test, not(windows)))]
impl std::ops::Deref for DropCounter {
type Target = SharedCounter;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(all(test, not(windows)))]
impl Drop for DropCounter {
fn drop(&mut self) {
self.0.inc();
}
}
#[cfg(test)]
#[derive(Default)]
#[repr(C)] pub struct PanicOnClone(u8);
#[cfg(test)]
impl Clone for PanicOnClone {
fn clone(&self) -> Self {
panic!("panic on clone");
}
}