#![no_std]
#[cfg(feature = "alloc")]
extern crate alloc;
mod generated;
mod unordered_copy;
#[cfg(feature = "alloc")]
use core::alloc::Layout;
use core::{
cell::UnsafeCell, hint::assert_unchecked, marker::PhantomData, mem::MaybeUninit, ptr::NonNull,
};
use generated::*;
use unordered_copy::*;
use crate::private::Sealed;
pub trait RacyStorage: Sealed {}
impl RacyStorage for u8 {}
impl RacyStorage for u16 {}
impl RacyStorage for u32 {}
impl RacyStorage for u64 {}
impl RacyStorage for usize {}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum Ordering {
Unordered,
SeqCst,
}
#[inline(always)]
pub fn fence() {
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
}
#[inline(always)]
pub fn atomic_pause() {
core::hint::spin_loop();
}
#[cfg(feature = "alloc")]
pub struct RacyBox<T: RacyStorage> {
ptr: RacyPtr<T>,
len: usize,
}
#[cfg(feature = "alloc")]
#[derive(Debug)]
pub enum RacyBoxNewError {
SizeOverflow,
LayoutError,
AllocationFailure,
}
#[cfg(feature = "alloc")]
impl<T: RacyStorage> RacyBox<T> {
pub fn new(value: T) -> Result<Self, RacyBoxNewError> {
let layout = unsafe { Self::create_layout(1).unwrap_unchecked() };
let ptr = unsafe { alloc::alloc::alloc(layout) };
let Some(ptr) = NonNull::new(ptr) else {
return Err(RacyBoxNewError::AllocationFailure);
};
let ptr = ptr.cast::<T>();
unsafe { ptr.write(value) };
let ptr = unsafe { enter_racy_memory(ptr.cast::<T>()) };
Ok(Self { ptr, len: 1 })
}
pub fn with_capacity(capacity: usize) -> Result<Self, RacyBoxNewError> {
let layout = Self::create_layout(capacity)?;
let ptr = unsafe { alloc::alloc::alloc_zeroed(layout) };
let Some(ptr) = NonNull::new(ptr) else {
return Err(RacyBoxNewError::AllocationFailure);
};
let ptr = unsafe { enter_racy_memory(ptr.cast::<T>()) };
Ok(Self { ptr, len: capacity })
}
#[inline(always)]
pub const fn as_slice(&self) -> RacySlice<'_, T> {
unsafe { RacySlice::from_raw_parts(self.ptr, self.len) }
}
#[inline]
const fn create_layout(capacity: usize) -> Result<Layout, RacyBoxNewError> {
const {
unsafe {
assert_unchecked(size_of::<T>() > 0);
};
}
let Some(size) = size_of::<T>().checked_mul(capacity) else {
return Err(RacyBoxNewError::SizeOverflow);
};
let Ok(layout) = Layout::from_size_align(size, align_of::<T>()) else {
return Err(RacyBoxNewError::LayoutError);
};
Ok(layout)
}
}
#[cfg(feature = "alloc")]
impl<T: RacyStorage> Drop for RacyBox<T> {
fn drop(&mut self) {
let ptr = unsafe { exit_racy_memory(self.ptr) };
let layout = unsafe { Self::create_layout(self.len).unwrap_unchecked() };
unsafe { alloc::alloc::dealloc(ptr.as_ptr().cast(), layout) };
}
}
#[must_use]
pub struct RacyMemory<T: RacyStorage> {
ptr: RacyPtr<T>,
len: usize,
}
unsafe impl<T: RacyStorage> Send for RacyMemory<T> {}
unsafe impl<T: RacyStorage> Sync for RacyMemory<T> {}
impl<T: RacyStorage> RacyMemory<T> {
#[inline]
#[must_use]
pub unsafe fn enter(ptr: NonNull<u8>, len: usize) -> RacyMemory<u8> {
let ptr = unsafe { enter_racy_memory(ptr) };
RacyMemory::from_raw_parts(ptr, len)
}
#[inline]
#[must_use]
pub unsafe fn enter_ptr(ptr: NonNull<T>) -> Self {
let ptr = unsafe { enter_racy_memory(ptr) };
Self::from_raw_parts(ptr.cast(), 1)
}
#[inline]
#[must_use]
pub unsafe fn enter_slice(ptr: NonNull<[T]>) -> Self {
let len = ptr.len();
let ptr = unsafe { enter_racy_memory(ptr.cast::<T>()) };
Self::from_raw_parts(ptr.cast(), len)
}
#[inline]
#[must_use]
pub unsafe fn exit(self) -> (NonNull<T>, usize) {
let ptr = unsafe { exit_racy_memory(self.ptr) };
(ptr, self.len)
}
#[inline(always)]
pub const fn as_slice(&self) -> RacySlice<'_, T> {
unsafe { RacySlice::from_raw_parts(self.ptr, self.len) }
}
#[inline(always)]
pub const fn into_raw_parts(self) -> (RacyPtr<T>, usize) {
(self.ptr, self.len)
}
pub const fn from_raw_parts(ptr: RacyPtr<T>, len: usize) -> Self {
Self { ptr, len }
}
}
unsafe fn enter_racy_memory<T: RacyStorage>(ptr: NonNull<T>) -> RacyPtr<T> {
let mut ptr = ptr.as_ptr();
unsafe {
core::arch::asm!(
"/* Magic spell: let {} no longer be memory in Rust's eyes! */",
inlateout(reg) ptr,
options(nostack, preserves_flags)
)
}
RacyPtr::from_ptr(unsafe { NonNull::new_unchecked(ptr.cast()) })
}
unsafe fn exit_racy_memory<T: RacyStorage>(ptr: RacyPtr<T>) -> NonNull<T> {
let mut ptr = ptr.as_ptr().as_ptr();
unsafe {
core::arch::asm!(
"/* Magic spell: let {} be memory in Rust's eyes! */",
inlateout(reg) ptr,
options(nostack, preserves_flags)
)
}
unsafe { NonNull::new_unchecked(ptr) }.cast()
}
mod private {
pub trait Sealed: 'static + Copy + Eq + Send + Sync + core::fmt::Display {}
impl Sealed for u8 {}
impl Sealed for u16 {}
impl Sealed for u32 {}
impl Sealed for u64 {}
impl Sealed for usize {}
}
#[derive(Clone, Copy)]
pub struct RacySlice<'a, T: RacyStorage> {
ptr: RacyPtr<T>,
len: usize,
__marker: PhantomData<&'a UnsafeCell<T>>,
}
unsafe impl<T: RacyStorage> Send for RacySlice<'_, T> {}
unsafe impl<T: RacyStorage> Sync for RacySlice<'_, T> {}
impl<'a, T: RacyStorage> RacySlice<'a, T> {
#[inline(always)]
pub const fn into_raw_parts(self) -> (RacyPtr<T>, usize) {
(self.ptr, self.len)
}
#[inline(always)]
pub const unsafe fn from_raw_parts(ptr: RacyPtr<T>, len: usize) -> Self {
Self {
ptr,
len,
__marker: PhantomData,
}
}
const fn as_ptr(&self) -> RacyPtr<T> {
self.ptr
}
#[inline(always)]
pub const fn len(&self) -> usize {
self.len
}
const fn byte_length(&self) -> usize {
unsafe {
assert_unchecked(self.len().checked_mul(size_of::<T>()).is_some());
self.len.unchecked_mul(size_of::<T>())
}
}
#[inline(always)]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
pub fn align_to<U: RacyStorage>(
self,
) -> (RacySlice<'a, u8>, RacySlice<'a, U>, RacySlice<'a, u8>) {
let byte_length = self.byte_length();
let head_ptr = self.ptr.as_ptr();
let head_length = head_ptr.align_offset(align_of::<U>()).min(byte_length);
let body_ptr = unsafe { head_ptr.byte_add(head_length) };
let remaining_byte_length = byte_length - head_length;
let body_length = remaining_byte_length / size_of::<U>();
let tail_length = remaining_byte_length % size_of::<U>();
debug_assert_eq!(
head_length + body_length * size_of::<U>() + tail_length,
byte_length,
"align_to produced a collection of slices with different total byte length than original"
);
let tail_ptr = unsafe { body_ptr.byte_add(body_length * size_of::<U>()) };
if const { align_of::<U>() <= align_of::<T>() } {
unsafe {
assert_unchecked(
head_length == 0
&& tail_length == 0
&& body_length == byte_length / size_of::<U>(),
);
};
}
(
RacySlice {
ptr: RacyPtr::from_ptr(head_ptr),
len: head_length,
__marker: PhantomData,
},
RacySlice {
ptr: RacyPtr::from_ptr(body_ptr),
len: body_length,
__marker: PhantomData,
},
RacySlice {
ptr: RacyPtr::from_ptr(tail_ptr),
len: tail_length,
__marker: PhantomData,
},
)
}
#[inline(always)]
pub const fn to_bytes(self) -> RacySlice<'a, u8> {
unsafe { RacySlice::from_raw_parts(self.as_ptr().cast(), self.byte_length()) }
}
#[inline]
pub const fn iter(&self) -> RacyIter<'a, T> {
RacyIter::new(*self)
}
#[inline]
pub fn slice_from(&self, offset: usize) -> Self {
let ptr = RacyPtr::from_ptr(unsafe {
self.ptr
.as_ptr()
.byte_add(offset.min(self.len) * size_of::<T>())
});
let len = self.len.saturating_sub(offset);
unsafe { Self::from_raw_parts(ptr, len) }
}
#[inline]
pub fn slice_to(&self, offset: usize) -> Self {
let ptr = self.ptr;
let len = self.len.min(offset);
unsafe { Self::from_raw_parts(ptr, len) }
}
#[inline]
pub fn slice(&self, start: usize, end: usize) -> Self {
let start = start.min(self.len);
let end = end.min(self.len);
let len = end.saturating_sub(start);
let ptr = RacyPtr::from_ptr(unsafe { self.ptr.as_ptr().byte_add(start * size_of::<T>()) });
unsafe { Self::from_raw_parts(ptr, len) }
}
#[inline]
pub fn as_aligned<U: RacyStorage>(&self) -> Option<Racy<'a, U>> {
unsafe { assert_unchecked(self.ptr.as_ptr().cast::<T>().is_aligned()) };
if self.byte_length() < size_of::<U>() || !self.ptr.as_ptr().cast::<U>().is_aligned() {
None
} else {
Some(Racy::from_ptr(self.ptr.as_ptr()))
}
}
#[inline]
pub fn load_unaligned<U: RacyStorage>(&self) -> Option<U> {
unsafe { assert_unchecked(self.ptr.as_ptr().cast::<T>().is_aligned()) };
if self.byte_length() < size_of::<U>() {
return None;
}
if UNALIGNED_ACCESS_IS_OK
|| const { core::mem::align_of::<U>() <= core::mem::align_of::<T>() }
{
let racy = Racy::<U>::from_ptr(self.ptr.as_ptr());
return Some(racy.load(Ordering::Unordered));
}
if const { core::mem::size_of::<U>() == core::mem::size_of::<u8>() } {
type Target = u8;
let mut scratch = MaybeUninit::<Target>::uninit();
let dst = unsafe { NonNull::new_unchecked(scratch.as_mut_ptr().cast::<()>()) };
unsafe { unordered_memcpy_down_unsynchronized(self.ptr.as_ptr(), dst, size_of::<U>()) };
let result = unsafe { scratch.assume_init() };
Some(unsafe { core::mem::transmute_copy::<Target, U>(&result) })
} else if const { core::mem::size_of::<U>() == core::mem::size_of::<u16>() } {
type Target = u16;
let mut scratch = MaybeUninit::<Target>::uninit();
let dst = unsafe { NonNull::new_unchecked(scratch.as_mut_ptr().cast::<()>()) };
unsafe { unordered_memcpy_down_unsynchronized(self.ptr.as_ptr(), dst, size_of::<U>()) };
let result = unsafe { scratch.assume_init() };
Some(unsafe { core::mem::transmute_copy::<Target, U>(&result) })
} else if const { core::mem::size_of::<U>() == core::mem::size_of::<u32>() } {
type Target = u32;
let mut scratch = MaybeUninit::<Target>::uninit();
let dst = unsafe { NonNull::new_unchecked(scratch.as_mut_ptr().cast::<()>()) };
unsafe { unordered_memcpy_down_unsynchronized(self.ptr.as_ptr(), dst, size_of::<U>()) };
let result = unsafe { scratch.assume_init() };
Some(unsafe { core::mem::transmute_copy::<Target, U>(&result) })
} else if const { core::mem::size_of::<U>() == core::mem::size_of::<u64>() } {
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
panic!("Cannot use this atomic operation on a 32-bit architecture");
}
type Target = u64;
let mut scratch = MaybeUninit::<Target>::uninit();
let dst = unsafe { NonNull::new_unchecked(scratch.as_mut_ptr().cast::<()>()) };
unsafe { unordered_memcpy_down_unsynchronized(self.ptr.as_ptr(), dst, size_of::<U>()) };
let result = unsafe { scratch.assume_init() };
Some(unsafe { core::mem::transmute_copy::<Target, U>(&result) })
} else {
panic!("Unsupported T: RacyStorage");
}
}
#[inline]
pub fn store_unaligned<U: RacyStorage>(&self, val: U) -> Option<()> {
unsafe { assert_unchecked(self.ptr.as_ptr().cast::<T>().is_aligned()) };
if self.byte_length() < size_of::<U>() {
return None;
}
if UNALIGNED_ACCESS_IS_OK
|| const { core::mem::align_of::<U>() <= core::mem::align_of::<T>() }
{
let racy = Racy::<U>::from_ptr(self.ptr.as_ptr());
racy.store(val, Ordering::Unordered);
return Some(());
}
if const { core::mem::size_of::<U>() == core::mem::size_of::<u64>() } {
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
panic!("Cannot use this atomic operation on a 32-bit architecture");
}
}
let src = unsafe { NonNull::new_unchecked(&val as *const _ as *mut ()) };
unsafe { unordered_memcpy_down_unsynchronized(src, self.ptr.as_ptr(), size_of::<U>()) };
Some(())
}
pub fn get(&self, index: usize) -> Option<Racy<'a, T>> {
if index >= self.len() {
None
} else {
let ptr =
RacyPtr::<T>::from_ptr(unsafe { self.ptr.as_ptr().cast::<T>().add(index).cast() });
Some(Racy::from_ptr(ptr.as_ptr()))
}
}
pub fn copy_from_slice(&self, src: &[T]) {
if self.len() != src.len() {
len_mismatch_fail();
}
let count = self.len();
let src = unsafe { NonNull::new_unchecked(src.as_ptr().cast_mut()) };
let dst: NonNull<T> = self.as_ptr().as_ptr().cast();
unsafe { unordered_copy_nonoverlapping(src, dst, count) };
}
pub fn copy_into_slice(&self, dst: &mut [T]) {
if self.len() != dst.len() {
len_mismatch_fail();
}
let count = self.len();
let src: NonNull<T> = self.as_ptr().as_ptr().cast();
let dst = unsafe { NonNull::new_unchecked(dst.as_ptr().cast_mut()) };
unsafe { unordered_copy_nonoverlapping(src, dst, count) };
}
pub fn copy_from_racy_slice(&self, other: &Self) {
if self.len() != other.len() {
len_mismatch_fail();
}
let count = self.len();
if unsafe {
self.ptr.as_ptr() <= other.ptr.as_ptr()
&& other.ptr.as_ptr() < self.ptr.as_ptr().byte_add(self.byte_length())
|| other.ptr.as_ptr() <= self.ptr.as_ptr()
&& self.ptr.as_ptr() < other.ptr.as_ptr().byte_add(other.byte_length())
} {
unsafe { unordered_copy(other.as_ptr(), self.as_ptr(), count) };
} else {
let dst: NonNull<T> = self.as_ptr().as_ptr().cast();
let src: NonNull<T> = other.as_ptr().as_ptr().cast();
unsafe { unordered_copy_nonoverlapping(src, dst, count) };
}
}
}
pub struct RacyIter<'a, T: RacyStorage> {
ptr: RacyPtr<T>,
end: NonNull<()>,
_marker: PhantomData<Racy<'a, T>>,
}
unsafe impl<T: RacyStorage> Send for RacyIter<'_, T> {}
unsafe impl<T: RacyStorage> Sync for RacyIter<'_, T> {}
impl<'a, T: RacyStorage> RacyIter<'a, T> {
#[inline]
const fn new(slice: RacySlice<'a, T>) -> Self {
let len = slice.len();
let ptr: RacyPtr<T> = slice.as_ptr();
let end = unsafe { ptr.as_ptr().cast::<T>().add(len).cast::<()>() };
Self {
ptr,
end,
_marker: PhantomData,
}
}
}
impl<'a, T: RacyStorage> Iterator for RacyIter<'a, T> {
type Item = Racy<'a, T>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let ptr = self.ptr;
let end = self.end;
unsafe {
if ptr.as_ptr() == end {
return None;
}
self.ptr = RacyPtr::from_ptr(ptr.as_ptr().cast::<T>().add(1).cast::<()>());
Some(Racy::from_ptr(ptr.as_ptr()))
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let exact = unsafe { self.end.offset_from_unsigned(self.ptr.as_ptr()) };
(exact, Some(exact))
}
#[inline]
fn count(self) -> usize {
unsafe { self.end.offset_from_unsigned(self.ptr.as_ptr()) }
}
}
impl<'a, T: RacyStorage> DoubleEndedIterator for RacyIter<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
let ptr = self.ptr;
let end = self.end;
unsafe {
if ptr.as_ptr() == end {
return None;
}
self.end = end.cast::<T>().sub(1).cast::<()>();
Some(Racy::from_ptr(self.end))
}
}
}
impl<'a, T: RacyStorage> ExactSizeIterator for RacyIter<'a, T> {}
impl<'a, T: RacyStorage> IntoIterator for RacySlice<'a, T> {
type Item = Racy<'a, T>;
type IntoIter = RacyIter<'a, T>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[track_caller]
#[cold]
const fn len_mismatch_fail() -> ! {
panic!("copy_from_slice: source slice length does not match destination slice length")
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct RacyPtr<T: RacyStorage>(NonNull<()>, PhantomData<NonNull<UnsafeCell<T>>>);
unsafe impl<T: RacyStorage> Send for RacyPtr<T> {}
unsafe impl<T: RacyStorage> Sync for RacyPtr<T> {}
impl<T: RacyStorage> RacyPtr<T> {
#[inline(always)]
#[must_use]
pub const fn dangling() -> RacyPtr<T> {
Self::from_ptr(NonNull::<T>::dangling().cast())
}
const fn from_ptr(ptr: NonNull<()>) -> Self {
Self(ptr, PhantomData)
}
pub const fn as_ptr(self) -> NonNull<()> {
self.0
}
pub const fn cast<U: RacyStorage>(self) -> RacyPtr<U> {
RacyPtr(self.0.cast(), PhantomData)
}
pub const unsafe fn as_racy<'a>(self) -> Racy<'a, T> {
Racy::from_ptr(self.0)
}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Racy<'a, T: RacyStorage>(NonNull<()>, PhantomData<&'a UnsafeCell<T>>);
unsafe impl<T: RacyStorage> Send for Racy<'_, T> {}
unsafe impl<T: RacyStorage> Sync for Racy<'_, T> {}
impl<T: RacyStorage> Racy<'_, T> {
const fn from_ptr(ptr: NonNull<()>) -> Self {
Self(ptr, PhantomData)
}
const fn as_ptr(&self) -> NonNull<()> {
self.0
}
pub const fn addr(&self) -> *const () {
self.0.as_ptr()
}
#[inline]
#[cfg(any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "arm"
))]
pub fn compare_exchange(&self, current: T, new: T) -> Result<T, T> {
if const { core::mem::size_of::<T>() == core::mem::size_of::<u8>() } {
type Target = u8;
let cur = unsafe { core::mem::transmute_copy::<T, Target>(¤t) };
let new = unsafe { core::mem::transmute_copy::<T, Target>(&new) };
let old = atomic_cmp_xchg_8_seq_cst(self.as_ptr(), cur, new);
let old = unsafe { core::mem::transmute_copy::<Target, T>(&old) };
if old == current { Ok(old) } else { Err(old) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u16>() } {
type Target = u16;
let cur = unsafe { core::mem::transmute_copy::<T, Target>(¤t) };
let new = unsafe { core::mem::transmute_copy::<T, Target>(&new) };
let old = atomic_cmp_xchg_16_seq_cst(self.as_ptr(), cur, new);
let old = unsafe { core::mem::transmute_copy::<Target, T>(&old) };
if old == current { Ok(old) } else { Err(old) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u32>() } {
type Target = u32;
let cur = unsafe { core::mem::transmute_copy::<T, Target>(¤t) };
let new = unsafe { core::mem::transmute_copy::<T, Target>(&new) };
let old = atomic_cmp_xchg_32_seq_cst(self.as_ptr(), cur, new);
let old = unsafe { core::mem::transmute_copy::<Target, T>(&old) };
if old == current { Ok(old) } else { Err(old) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u64>() } {
type Target = u64;
let cur = unsafe { core::mem::transmute_copy::<T, Target>(¤t) };
let new = unsafe { core::mem::transmute_copy::<T, Target>(&new) };
let old = atomic_cmp_xchg_64_seq_cst(self.as_ptr(), cur, new);
let old = unsafe { core::mem::transmute_copy::<Target, T>(&old) };
if old == current { Ok(old) } else { Err(old) }
} else {
panic!("Unsupported T: RacyStorage");
}
}
#[inline]
#[cfg(any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "arm"
))]
pub fn fetch_add(&self, val: T) -> T {
if const { core::mem::size_of::<T>() == core::mem::size_of::<u8>() } {
type Target = u8;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_add_8_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u16>() } {
type Target = u16;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_add_16_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u32>() } {
type Target = u32;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_add_32_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u64>() } {
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
panic!("Cannot use this atomic operation on a 32-bit architecture");
}
type Target = u64;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_add_64_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else {
panic!("Unsupported T: RacyStorage");
}
}
#[inline]
#[cfg(any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "arm"
))]
pub fn fetch_and(&self, val: T) -> T {
if const { core::mem::size_of::<T>() == core::mem::size_of::<u8>() } {
type Target = u8;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_and_8_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u16>() } {
type Target = u16;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_and_16_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u32>() } {
type Target = u32;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_and_32_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u64>() } {
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
panic!("Cannot use this atomic operation on a 32-bit architecture");
}
type Target = u64;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_and_64_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else {
panic!("Unsupported T: RacyStorage");
}
}
#[inline]
#[cfg(any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "arm"
))]
pub fn fetch_or(&self, val: T) -> T {
if const { core::mem::size_of::<T>() == core::mem::size_of::<u8>() } {
type Target = u8;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_or_8_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u16>() } {
type Target = u16;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_or_16_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u32>() } {
type Target = u32;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_or_32_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u64>() } {
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
panic!("Cannot use this atomic operation on a 32-bit architecture");
}
type Target = u64;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_or_64_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else {
panic!("Unsupported T: RacyStorage");
}
}
#[inline]
#[cfg(any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "arm"
))]
pub fn fetch_xor(&self, val: T) -> T {
if const { core::mem::size_of::<T>() == core::mem::size_of::<u8>() } {
type Target = u8;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_xor_8_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u16>() } {
type Target = u16;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_xor_16_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u32>() } {
type Target = u32;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_xor_32_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u64>() } {
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
panic!("Cannot use this atomic operation on a 32-bit architecture");
}
type Target = u64;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_xor_64_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else {
panic!("Unsupported T: RacyStorage");
}
}
#[inline]
#[cfg(any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "arm"
))]
pub fn load(&self, order: Ordering) -> T {
if const { core::mem::size_of::<T>() == core::mem::size_of::<u8>() } {
type Target = u8;
let result = if order == Ordering::SeqCst {
atomic_load_8_seq_cst(self.as_ptr())
} else {
atomic_load_8_unsynchronized(self.as_ptr())
};
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u16>() } {
type Target = u16;
let result = if order == Ordering::SeqCst {
atomic_load_16_seq_cst(self.as_ptr())
} else {
atomic_load_16_unsynchronized(self.as_ptr())
};
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u32>() } {
type Target = u32;
let result = if order == Ordering::SeqCst {
atomic_load_32_seq_cst(self.as_ptr())
} else {
atomic_load_32_unsynchronized(self.as_ptr())
};
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u64>() } {
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
panic!("Cannot use this atomic operation on a 32-bit architecture");
}
type Target = u64;
let result = if order == Ordering::SeqCst {
atomic_load_64_seq_cst(self.as_ptr())
} else {
atomic_load_64_unsynchronized(self.as_ptr())
};
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else {
panic!("Unsupported T: RacyStorage");
}
}
#[inline]
#[cfg(any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "arm"
))]
pub fn store(&self, val: T, order: Ordering) {
if const { core::mem::size_of::<T>() == core::mem::size_of::<u8>() } {
type Target = u8;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
if order == Ordering::SeqCst {
atomic_store_8_seq_cst(self.as_ptr(), val)
} else {
atomic_store_8_unsynchronized(self.as_ptr(), val)
}
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u16>() } {
type Target = u16;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
if order == Ordering::SeqCst {
atomic_store_16_seq_cst(self.as_ptr(), val)
} else {
atomic_store_16_unsynchronized(self.as_ptr(), val)
}
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u32>() } {
type Target = u32;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
if order == Ordering::SeqCst {
atomic_store_32_seq_cst(self.as_ptr(), val)
} else {
atomic_store_32_unsynchronized(self.as_ptr(), val)
}
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u64>() } {
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
panic!("Cannot use this atomic operation on a 32-bit architecture");
}
type Target = u64;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
if order == Ordering::SeqCst {
atomic_store_64_seq_cst(self.as_ptr(), val)
} else {
atomic_store_64_unsynchronized(self.as_ptr(), val)
}
} else {
panic!("Unsupported T: RacyStorage");
}
}
#[inline]
#[cfg(any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "arm"
))]
pub fn swap(&self, val: T) -> T {
if const { core::mem::size_of::<T>() == core::mem::size_of::<u8>() } {
type Target = u8;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_exchange_8_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u16>() } {
type Target = u16;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_exchange_16_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u32>() } {
type Target = u32;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_exchange_32_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else if const { core::mem::size_of::<T>() == core::mem::size_of::<u64>() } {
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
panic!("Cannot use this atomic operation on a 32-bit architecture");
}
type Target = u64;
let val = unsafe { core::mem::transmute_copy::<T, Target>(&val) };
let result = atomic_exchange_64_seq_cst(self.as_ptr(), val);
unsafe { core::mem::transmute_copy::<Target, T>(&result) }
} else {
panic!("Unsupported T: RacyStorage");
}
}
}
#[inline]
unsafe fn unordered_copy_nonoverlapping<T: RacyStorage>(
src: NonNull<T>,
dst: NonNull<T>,
count: usize,
) {
let count = count * size_of::<T>();
unsafe { unordered_memcpy_down_unsynchronized(src.cast(), dst.cast(), count) };
}
#[inline]
unsafe fn unordered_copy<T: RacyStorage>(src: RacyPtr<T>, dst: RacyPtr<T>, count: usize) {
let count = count * size_of::<T>();
if dst.as_ptr() <= src.as_ptr() {
unsafe { unordered_memcpy_down_unsynchronized(src.as_ptr(), dst.as_ptr(), count) };
} else {
unsafe { unordered_memcpy_up_unsynchronized(src.as_ptr(), dst.as_ptr(), count) };
}
}