use core::ptr::NonNull;
use core::{cmp, fmt, mem};
#[cfg(feature = "atomic")]
pub use self::atomic::AtomicCursor;
use crate::Cursed;
pub struct Cursor<T> {
ptr: NonNull<T>,
}
impl<T> Cursor<T> {
#[inline]
pub fn new(ptr: NonNull<T>) -> Self {
Self { ptr }
}
#[inline]
pub fn get<C>(self, cursed: &C) -> &T
where
C: Cursed<T>,
{
assert!(cursed.is_owner(self));
unsafe { &*self.ptr.as_ptr() }
}
#[inline]
pub fn get_mut<C>(self, cursed: &mut C) -> &mut T
where
C: Cursed<T>,
{
assert!(cursed.is_owner(self));
unsafe { &mut *self.ptr.as_ptr() }
}
#[inline]
pub unsafe fn new_unchecked(ptr: *mut T) -> Self {
Self::new(NonNull::new_unchecked(ptr))
}
#[inline]
pub fn ptr(self) -> NonNull<T> {
self.ptr
}
#[cfg(feature = "atomic")]
#[inline]
pub fn into_atomic(self) -> AtomicCursor<T> {
AtomicCursor::<T>::new(self)
}
#[inline]
pub(crate) unsafe fn unchecked_add(self, offset: usize) -> Self {
let offset_ptr = self.ptr.as_ptr().add(offset);
Self::new_unchecked(offset_ptr)
}
#[inline]
pub(crate) unsafe fn unchecked_sub(self, offset: usize) -> Self {
let offset_ptr = self.ptr.as_ptr().sub(offset);
Self::new_unchecked(offset_ptr)
}
#[inline]
pub(crate) fn offset_from(self, other: Self) -> usize {
if self == other {
0
} else {
let left = self.ptr.as_ptr() as usize;
let right = other.ptr.as_ptr() as usize;
(left - right) / mem::size_of::<T>()
}
}
}
impl<T> Clone for Cursor<T> {
#[inline]
fn clone(&self) -> Self {
Self::new(self.ptr())
}
}
impl<T> Copy for Cursor<T> {}
impl<T> PartialEq for Cursor<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.ptr == other.ptr
}
}
impl<T> Eq for Cursor<T> {}
impl<T> PartialOrd for Cursor<T> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.ptr.partial_cmp(&other.ptr)
}
}
impl<T> Ord for Cursor<T> {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.ptr.cmp(&other.ptr)
}
}
impl<T> fmt::Debug for Cursor<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Cursor({:?})", self.ptr)
}
}
pub trait AsCursor<T>: Cursed<T> {
fn as_cursor(&self) -> Cursor<T>;
}
mod atomic {
use core::fmt;
use core::marker::PhantomData;
use crate::atomic::{AtomicPtr, Ordering};
use crate::{Bounded, CursedExt, Cursor, Sequence};
pub struct AtomicCursor<T> {
ptr: AtomicPtr<T>,
marker: PhantomData<T>,
}
impl<T> AtomicCursor<T> {
#[inline]
pub fn new(cursor: Cursor<T>) -> Self {
let ptr = AtomicPtr::new(cursor.ptr().as_ptr());
Self {
ptr,
marker: PhantomData,
}
}
#[inline]
pub fn load(&self, order: Ordering) -> Cursor<T> {
let ptr = self.ptr.load(order);
unsafe { Cursor::new_unchecked(ptr) }
}
#[inline]
pub fn store(&self, cursor: Cursor<T>, order: Ordering) {
self.ptr.store(cursor.ptr().as_ptr(), order);
}
#[inline]
pub fn swap(&self, cursor: Cursor<T>, order: Ordering) -> Cursor<T> {
let prev_ptr = self.ptr.swap(cursor.ptr().as_ptr(), order);
unsafe { Cursor::new_unchecked(prev_ptr) }
}
#[inline]
pub fn compare_and_swap(
&self,
current: Cursor<T>,
new: Cursor<T>,
order: Ordering,
) -> Cursor<T> {
let prev_ptr =
self.ptr
.compare_and_swap(current.ptr().as_ptr(), new.ptr().as_ptr(), order);
unsafe { Cursor::new_unchecked(prev_ptr) }
}
#[inline]
pub fn compare_exchange(
&self,
current: Cursor<T>,
new: Cursor<T>,
success: Ordering,
failure: Ordering,
) -> Result<Cursor<T>, Cursor<T>> {
let result = self.ptr.compare_exchange(
current.ptr().as_ptr(),
new.ptr().as_ptr(),
success,
failure,
);
unsafe {
match result {
Ok(success) => Ok(Cursor::new_unchecked(success)),
Err(failure) => Err(Cursor::new_unchecked(failure)),
}
}
}
#[inline]
pub fn compare_exchange_weak(
&self,
current: Cursor<T>,
new: Cursor<T>,
success: Ordering,
failure: Ordering,
) -> Result<Cursor<T>, Cursor<T>> {
let result = self.ptr.compare_exchange(
current.ptr().as_ptr(),
new.ptr().as_ptr(),
success,
failure,
);
unsafe {
match result {
Ok(success) => Ok(Cursor::new_unchecked(success)),
Err(failure) => Err(Cursor::new_unchecked(failure)),
}
}
}
#[inline]
pub fn next<C>(&self, cursed: &C, order: Ordering) -> bool
where
C: Sequence<T>,
{
let (load, store) = Self::load_store_order(order);
let cursor = self.load(load);
cursed
.next(cursor)
.map(|cursor| self.store(cursor, store))
.is_some()
}
#[inline]
pub fn prev<C>(&self, cursed: &C, order: Ordering) -> bool
where
C: Sequence<T>,
{
let (load, store) = Self::load_store_order(order);
let cursor = self.load(load);
cursed
.prev(cursor)
.map(|cursor| self.store(cursor, store))
.is_some()
}
#[inline]
pub fn wrapping_next<C>(&self, cursed: &C, order: Ordering)
where
C: Bounded<T>,
{
let (load, store) = Self::load_store_order(order);
let cursor = self.load(load);
let cursor = cursed.wrapping_next(cursor);
self.store(cursor, store);
}
#[inline]
pub fn wrapping_prev<C>(&self, cursed: &C, order: Ordering)
where
C: Bounded<T>,
{
let (load, store) = Self::load_store_order(order);
let cursor = self.load(load);
let cursor = cursed.wrapping_prev(cursor);
self.store(cursor, store);
}
#[inline]
pub fn into_cursor(self) -> Cursor<T> {
unsafe { Cursor::new_unchecked(self.ptr.into_inner()) }
}
#[inline]
fn load_store_order(order: Ordering) -> (Ordering, Ordering) {
let load = match order {
Ordering::AcqRel => Ordering::Acquire,
Ordering::Release => Ordering::Relaxed,
other => other,
};
let store = match order {
Ordering::AcqRel => Ordering::Release,
Ordering::Acquire => Ordering::Relaxed,
other => other,
};
(load, store)
}
}
impl<T: fmt::Debug> fmt::Debug for AtomicCursor<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "AtomicCursor({:?})", self.ptr)
}
}
impl<T> From<AtomicCursor<T>> for Cursor<T> {
fn from(cursor: AtomicCursor<T>) -> Self {
cursor.into_cursor()
}
}
impl<T> From<Cursor<T>> for AtomicCursor<T> {
fn from(cursor: Cursor<T>) -> Self {
cursor.into_atomic()
}
}
}