use crate::*;
use crate::meta::*;
use core::alloc::Layout;
use core::mem::MaybeUninit;
use core::ptr::NonNull;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] pub struct Global;
#[cfg(feature = "alloc")] #[cfg(allocator_api = "*")] impl From<Global> for alloc::alloc::Global { fn from(_: Global) -> Self { Self } }
#[cfg(feature = "alloc")] #[cfg(allocator_api = "*")] impl From<alloc::alloc::Global> for Global { fn from(_: alloc::alloc::Global) -> Self { Self } }
impl Meta for Global {
type Error = ();
const MAX_ALIGN : Alignment = Alignment::MAX;
const MAX_SIZE : usize = usize::MAX/2;
const ZST_SUPPORTED : bool = true;
}
impl ZstSupported for Global {}
unsafe impl ZstInfalliable for Global {}
unsafe impl Stateless for Global {}
unsafe impl fat::Alloc for Global {
fn alloc_uninit(&self, layout: Layout) -> Result<AllocNN, Self::Error> {
match layout.size() {
0 => Ok(util::nn::dangling(layout)),
n if n > Self::MAX_SIZE => Err(()),
_ => {
debug_assert!(layout.pad_to_align().size() <= Self::MAX_SIZE, "bug: undefined behavior: Layout when padded to alignment exceeds isize::MAX, which violates Layout's invariants");
let alloc = unsafe { alloc::alloc::alloc(layout) };
NonNull::new(alloc.cast()).ok_or(())
}
}
}
fn alloc_zeroed(&self, layout: Layout) -> Result<AllocNN0, Self::Error> {
match layout.size() {
0 => Ok(util::nn::dangling(layout)),
n if n > Self::MAX_SIZE => Err(()),
_ => {
debug_assert!(layout.pad_to_align().size() <= Self::MAX_SIZE, "bug: undefined behavior: Layout when padded to alignment exceeds isize::MAX, which violates Layout's invariants");
let alloc = unsafe { alloc::alloc::alloc_zeroed(layout) };
NonNull::new(alloc.cast()).ok_or(())
}
}
}
}
unsafe impl fat::Free for Global {
unsafe fn free(&self, ptr: AllocNN, layout: Layout) {
if layout.size() == 0 { return }
unsafe { alloc::alloc::dealloc(ptr.as_ptr().cast(), layout) }
}
}
unsafe impl fat::Realloc for Global {
unsafe fn realloc_uninit(&self, ptr: AllocNN, old_layout: Layout, new_layout: Layout) -> Result<AllocNN, Self::Error> {
if new_layout.size() > Self::MAX_SIZE {
Err(())
} else if old_layout == new_layout {
Ok(ptr)
} else if old_layout.align() != new_layout.align() || old_layout.size() == 0 || new_layout.size() == 0 {
let alloc = fat::Alloc::alloc_uninit(self, new_layout)?;
{
#![allow(clippy::undocumented_unsafe_blocks)]
let old : & [MaybeUninit<u8>] = unsafe { util::slice::from_raw_bytes_layout (ptr, old_layout) };
let new : &mut [MaybeUninit<u8>] = unsafe { util::slice::from_raw_bytes_layout_mut(alloc, new_layout) };
let n = old.len().min(new.len());
new[..n].copy_from_slice(&old[..n]);
}
unsafe { fat::Free::free(self, ptr, old_layout) };
Ok(alloc)
} else {
let alloc = unsafe { alloc::alloc::realloc(ptr.as_ptr().cast(), old_layout, new_layout.size()) };
NonNull::new(alloc.cast()).ok_or(())
}
}
}
#[allow(clippy::undocumented_unsafe_blocks)] unsafe impl core::alloc::GlobalAlloc for Global {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { unsafe { alloc::alloc::alloc(layout) } }
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { unsafe { alloc::alloc::alloc_zeroed(layout) } }
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { unsafe { alloc::alloc::dealloc(ptr, layout) } }
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { unsafe { alloc::alloc::realloc(ptr, layout, new_size) } }
}
#[cfg(allocator_api = "1.50")] unsafe impl core::alloc::Allocator for Global {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, core::alloc::AllocError> {
let data = fat::Alloc::alloc_uninit(self, layout).map_err(|_| core::alloc::AllocError)?;
Ok(util::nn::slice_from_raw_parts(data.cast(), layout.size()))
}
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, core::alloc::AllocError> {
let data = fat::Alloc::alloc_zeroed(self, layout).map_err(|_| core::alloc::AllocError)?;
Ok(util::nn::slice_from_raw_parts(data.cast(), layout.size()))
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
unsafe { fat::Free::free(self, ptr.cast(), layout) }
}
unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, core::alloc::AllocError> {
let data = unsafe { fat::Realloc::realloc_uninit(self, ptr.cast(), old_layout, new_layout) }.map_err(|_| core::alloc::AllocError)?;
Ok(util::nn::slice_from_raw_parts(data.cast(), new_layout.size()))
}
unsafe fn grow_zeroed(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, core::alloc::AllocError> {
let data = unsafe { fat::Realloc::realloc_zeroed(self, ptr.cast(), old_layout, new_layout) }.map_err(|_| core::alloc::AllocError)?;
Ok(util::nn::slice_from_raw_parts(data.cast(), new_layout.size()))
}
unsafe fn shrink(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, core::alloc::AllocError> {
let data = unsafe { fat::Realloc::realloc_uninit(self, ptr.cast(), old_layout, new_layout) }.map_err(|_| core::alloc::AllocError)?;
Ok(util::nn::slice_from_raw_parts(data.cast(), new_layout.size()))
}
}
#[cfg(test)] const GLOBAL_ALLOC_ZERO_INITS : bool = cfg!(any(
target_os = "linux", target_os = "macos", ));
#[test] fn fat_alignment() { fat::test::alignment(Global) }
#[test] fn fat_edge_case_sizes() { fat::test::edge_case_sizes(Global) }
#[test] fn fat_uninit() { if !GLOBAL_ALLOC_ZERO_INITS { unsafe { fat::test::uninit_alloc_unsound(Global) } } }
#[test] fn fat_uninit_realloc() { fat::test::uninit_realloc(Global) }
#[test] fn fat_zeroed() { fat::test::zeroed_alloc(Global) }
#[test] fn fat_zeroed_realloc() { fat::test::zeroed_realloc(Global) }
#[test] fn fat_zst_support() { fat::test::zst_supported_accurate(Global) }