use alloc::sync::Arc;
use core::{fmt::Debug, ops::Deref, ptr::NonNull};
pub struct RcuRef<T, M>
where
T: ?Sized,
M: ?Sized,
{
#[allow(dead_code)]
arc: Arc<T>,
data: NonNull<M>,
}
impl<T: ?Sized, M: ?Sized + Debug> Debug for RcuRef<T, M> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("RcuRef")
.field("data", &self.deref())
.finish()
}
}
impl<T: ?Sized> RcuRef<T, T> {
pub fn new(arc: Arc<T>) -> Self {
Self {
data: arc.as_ref().into(),
arc,
}
}
}
impl<T: ?Sized, M: ?Sized> RcuRef<T, M> {
pub fn map<N: ?Sized, F: for<'a> FnOnce(&'a M) -> &'a N>(
reference: Self,
f: F,
) -> RcuRef<T, N> {
RcuRef {
arc: reference.arc,
data: f(unsafe { reference.data.as_ref() }).into(),
}
}
pub fn try_map<N: ?Sized, F: for<'a> FnOnce(&'a M) -> Option<&'a N>>(
reference: Self,
f: F,
) -> Option<RcuRef<T, N>> {
let val = f(unsafe { reference.data.as_ref() })?;
Some(RcuRef {
arc: Arc::clone(&reference.arc),
data: val.into(),
})
}
pub fn same_epoch<M2>(this: &Self, other: &RcuRef<T, M2>) -> bool {
Arc::ptr_eq(&this.arc, &other.arc)
}
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
core::ptr::eq(this.data.as_ptr(), other.data.as_ptr())
}
pub fn ptr_addr_eq(this: &Self, other: &Self) -> bool {
std::ptr::addr_eq(this.data.as_ptr(), other.data.as_ptr())
}
#[allow(clippy::should_implement_trait)]
pub fn clone(this: &Self) -> Self {
Self {
arc: Arc::clone(&this.arc),
data: this.data,
}
}
pub fn get_root(this: &Self) -> &T {
&this.arc
}
}
impl<T: ?Sized, M: ?Sized> Deref for RcuRef<T, M> {
type Target = M;
fn deref(&self) -> &Self::Target {
unsafe { self.data.as_ref() }
}
}