#![allow(unused)]
#[cfg(not(loom))]
pub use crossbeam_epoch::{pin, Atomic, Guard, Owned, Shared};
#[cfg(loom)]
mod mock_epoch {
use std::marker::PhantomData;
use std::ptr::NonNull;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use loom::sync::atomic::AtomicPtr;
pub struct Guard {
_marker: PhantomData<*mut ()>,
}
impl Guard {
fn new() -> Self {
Guard {
_marker: PhantomData,
}
}
#[allow(clippy::missing_safety_doc)]
pub unsafe fn defer_destroy<T>(&self, _ptr: Shared<'_, T>) {
}
pub fn flush(&self) {
}
pub fn defer<F, R>(&self, f: F)
where
F: FnOnce() -> R + Send + 'static,
{
let _ = f();
}
}
pub fn pin() -> Guard {
Guard::new()
}
pub struct Shared<'g, T> {
ptr: *const T,
_marker: PhantomData<(&'g (), *const T)>,
}
impl<'g, T> Clone for Shared<'g, T> {
fn clone(&self) -> Self {
*self
}
}
impl<'g, T> Copy for Shared<'g, T> {}
impl<'g, T> Shared<'g, T> {
pub fn null() -> Self {
Shared {
ptr: std::ptr::null(),
_marker: PhantomData,
}
}
pub fn is_null(&self) -> bool {
self.ptr.is_null()
}
pub fn as_raw(&self) -> *const T {
self.ptr
}
pub unsafe fn deref(&self) -> &'g T {
unsafe { &*self.ptr }
}
pub unsafe fn as_ref(&self) -> Option<&'g T> {
if self.is_null() {
None
} else {
Some(unsafe { &*self.ptr })
}
}
pub unsafe fn from_raw(ptr: *const T) -> Self {
Shared {
ptr,
_marker: PhantomData,
}
}
}
pub struct Owned<T> {
data: NonNull<T>,
}
unsafe impl<T: Send> Send for Owned<T> {}
impl<T> Owned<T> {
pub fn new(value: T) -> Self {
let boxed = Box::new(value);
Owned {
data: NonNull::new(Box::into_raw(boxed)).unwrap(),
}
}
pub fn into_shared<'g>(self, _guard: &'g Guard) -> Shared<'g, T> {
let ptr = self.data.as_ptr();
std::mem::forget(self); Shared {
ptr,
_marker: PhantomData,
}
}
pub fn as_ref(&self) -> &T {
unsafe { self.data.as_ref() }
}
pub fn as_mut(&mut self) -> &mut T {
unsafe { self.data.as_mut() }
}
}
impl<T> Drop for Owned<T> {
fn drop(&mut self) {
unsafe {
drop(Box::from_raw(self.data.as_ptr()));
}
}
}
impl<T> std::ops::Deref for Owned<T> {
type Target = T;
fn deref(&self) -> &T {
self.as_ref()
}
}
impl<T> std::ops::DerefMut for Owned<T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { self.data.as_mut() }
}
}
pub struct Atomic<T> {
ptr: AtomicPtr<T>,
owns_data: std::sync::atomic::AtomicBool,
}
unsafe impl<T: Send + Sync> Send for Atomic<T> {}
unsafe impl<T: Send + Sync> Sync for Atomic<T> {}
impl<T> std::fmt::Debug for Atomic<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ptr = self.ptr.load(Ordering::SeqCst);
f.debug_struct("Atomic").field("ptr", &ptr).finish()
}
}
impl<T> Atomic<T> {
pub fn null() -> Self {
Atomic {
ptr: AtomicPtr::new(std::ptr::null_mut()),
owns_data: std::sync::atomic::AtomicBool::new(false),
}
}
pub fn new(value: T) -> Self {
let boxed = Box::new(value);
Atomic {
ptr: AtomicPtr::new(Box::into_raw(boxed)),
owns_data: std::sync::atomic::AtomicBool::new(true),
}
}
pub fn load<'g>(&self, order: Ordering, _guard: &'g Guard) -> Shared<'g, T> {
let ptr = self.ptr.load(order);
Shared {
ptr,
_marker: PhantomData,
}
}
pub fn store(&self, new: Shared<'_, T>, order: Ordering) {
self.ptr.store(new.ptr as *mut T, order);
}
pub fn swap<'g>(
&self,
new: Shared<'_, T>,
order: Ordering,
_guard: &'g Guard,
) -> Shared<'g, T> {
let old = self.ptr.swap(new.ptr as *mut T, order);
Shared {
ptr: old,
_marker: PhantomData,
}
}
pub fn compare_exchange<'g>(
&self,
current: Shared<'_, T>,
new: Shared<'_, T>,
success: Ordering,
failure: Ordering,
_guard: &'g Guard,
) -> Result<Shared<'g, T>, CompareExchangeError<'g, T, Shared<'g, T>>> {
match self.ptr.compare_exchange(
current.ptr as *mut T,
new.ptr as *mut T,
success,
failure,
) {
Ok(ptr) => Ok(Shared {
ptr,
_marker: PhantomData,
}),
Err(ptr) => Err(CompareExchangeError {
current: Shared {
ptr,
_marker: PhantomData,
},
new: Shared {
ptr: new.ptr,
_marker: PhantomData,
},
}),
}
}
pub fn compare_exchange_owned<'g>(
&self,
current: Shared<'_, T>,
new: Owned<T>,
success: Ordering,
failure: Ordering,
_guard: &'g Guard,
) -> Result<Shared<'g, T>, CompareExchangeError<'g, T, Owned<T>>> {
let new_ptr = new.data.as_ptr();
match self.ptr.compare_exchange(current.ptr as *mut T, new_ptr, success, failure) {
Ok(ptr) => {
std::mem::forget(new); Ok(Shared {
ptr,
_marker: PhantomData,
})
}
Err(ptr) => Err(CompareExchangeError {
current: Shared {
ptr,
_marker: PhantomData,
},
new,
}),
}
}
pub fn get_mut(&mut self) -> Option<&mut T> {
let ptr = self.ptr.load(Ordering::Relaxed);
if ptr.is_null() {
None
} else {
unsafe { Some(&mut *ptr) }
}
}
pub fn take(&mut self) -> Option<Box<T>> {
let ptr = self.ptr.swap(std::ptr::null_mut(), Ordering::Relaxed);
if ptr.is_null() {
None
} else {
self.owns_data.store(false, std::sync::atomic::Ordering::Relaxed);
unsafe { Some(Box::from_raw(ptr)) }
}
}
}
impl<T> Default for Atomic<T> {
fn default() -> Self {
Self::null()
}
}
impl<T> Drop for Atomic<T> {
fn drop(&mut self) {
if self.owns_data.load(std::sync::atomic::Ordering::Relaxed) {
let ptr = self.ptr.load(Ordering::Relaxed);
if !ptr.is_null() {
unsafe {
drop(Box::from_raw(ptr));
}
}
}
}
}
impl<T> From<Owned<T>> for Atomic<T> {
fn from(owned: Owned<T>) -> Self {
let ptr = owned.data.as_ptr();
std::mem::forget(owned);
Atomic {
ptr: AtomicPtr::new(ptr),
owns_data: std::sync::atomic::AtomicBool::new(true),
}
}
}
impl<T> From<Shared<'_, T>> for Atomic<T> {
fn from(shared: Shared<'_, T>) -> Self {
Atomic {
ptr: AtomicPtr::new(shared.ptr as *mut T),
owns_data: std::sync::atomic::AtomicBool::new(false),
}
}
}
pub struct CompareExchangeError<'g, T, N> {
pub current: Shared<'g, T>,
pub new: N,
}
}
#[cfg(loom)]
pub use mock_epoch::*;