use core::{
borrow::Borrow,
cmp::Ordering,
fmt::{self, Debug, Display},
hash::{Hash, Hasher},
ops::{Deref, RangeBounds},
ptr::NonNull,
};
use crate::borrow::AtomicBorrow;
pub struct Ref<'a, T: ?Sized> {
value: NonNull<T>,
borrow: AtomicBorrow<'a>,
}
unsafe impl<'b, T: ?Sized + 'b> Sync for Ref<'b, T> where for<'a> &'a T: Sync {}
unsafe impl<'b, T: ?Sized + 'b> Send for Ref<'b, T> where for<'a> &'a T: Send {}
impl<'a, T> Clone for Ref<'a, T>
where
T: ?Sized,
{
#[inline]
fn clone(&self) -> Self {
Ref {
borrow: self.borrow.clone(),
value: self.value,
}
}
#[inline]
fn clone_from(&mut self, source: &Self) {
self.borrow = source.borrow.clone();
self.value = source.value;
}
}
impl<'a, T> Deref for Ref<'a, T>
where
T: ?Sized,
{
type Target = T;
#[inline(always)]
fn deref(&self) -> &T {
unsafe { self.value.as_ref() }
}
}
impl<'a, T> Debug for Ref<'a, T>
where
T: Debug + ?Sized,
{
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<T as Debug>::fmt(self, f)
}
}
impl<'a, T> Display for Ref<'a, T>
where
T: Display + ?Sized,
{
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<T as Display>::fmt(self, f)
}
}
impl<'a, T, U> PartialEq<U> for Ref<'a, T>
where
T: PartialEq<U> + ?Sized,
{
#[inline(always)]
fn eq(&self, other: &U) -> bool {
<T as PartialEq<U>>::eq(self, other)
}
}
impl<'a, T, U> PartialOrd<U> for Ref<'a, T>
where
T: PartialOrd<U> + ?Sized,
{
#[inline(always)]
fn partial_cmp(&self, other: &U) -> Option<Ordering> {
<T as PartialOrd<U>>::partial_cmp(self, other)
}
}
impl<'a, T> Hash for Ref<'a, T>
where
T: Hash + ?Sized,
{
#[inline(always)]
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
<T as Hash>::hash(self, state)
}
}
impl<'a, T> Borrow<T> for Ref<'a, T> {
#[inline(always)]
fn borrow(&self) -> &T {
self
}
}
impl<'a, T, U> AsRef<U> for Ref<'a, T>
where
T: AsRef<U> + ?Sized,
{
#[inline(always)]
fn as_ref(&self) -> &U {
<T as AsRef<U>>::as_ref(self)
}
}
impl<'a, T> Ref<'a, T>
where
T: ?Sized,
{
#[inline]
pub fn new(r: &'a T) -> Self {
Ref {
value: NonNull::from(r),
borrow: AtomicBorrow::dummy(),
}
}
#[inline]
pub fn with_borrow(r: &'a T, borrow: AtomicBorrow<'a>) -> Self {
Ref {
value: NonNull::from(r),
borrow,
}
}
#[inline]
pub fn into_split(r: Ref<'a, T>) -> (NonNull<T>, AtomicBorrow<'a>) {
(r.value, r.borrow)
}
#[inline]
pub fn map<F, U>(r: Ref<'a, T>, f: F) -> Ref<'a, U>
where
F: FnOnce(&T) -> &U,
U: ?Sized,
{
Ref {
value: NonNull::from(f(&*r)),
borrow: r.borrow,
}
}
pub fn filter_map<U: ?Sized, F>(r: Ref<'a, T>, f: F) -> Result<Ref<'a, U>, Self>
where
F: FnOnce(&T) -> Option<&U>,
{
match f(&*r) {
Some(value) => Ok(Ref {
value: NonNull::from(value),
borrow: r.borrow,
}),
None => Err(r),
}
}
pub fn map_split<U, V, F>(r: Ref<'a, T>, f: F) -> (Ref<'a, U>, Ref<'a, V>)
where
U: ?Sized,
V: ?Sized,
F: FnOnce(&T) -> (&U, &V),
{
let borrow_u = r.borrow.clone();
let borrow_v = r.borrow;
let (u, v) = f(unsafe { r.value.as_ref() });
(
Ref {
value: NonNull::from(u),
borrow: borrow_u,
},
Ref {
value: NonNull::from(v),
borrow: borrow_v,
},
)
}
pub fn leak(r: Ref<'a, T>) -> &'a T {
core::mem::forget(r.borrow);
unsafe { r.value.as_ref() }
}
#[inline]
pub fn as_ref<U>(r: Ref<'a, T>) -> Ref<'a, U>
where
U: ?Sized,
T: AsRef<U>,
{
Ref {
value: NonNull::from(<T as AsRef<U>>::as_ref(&r)),
borrow: r.borrow,
}
}
#[inline]
pub fn as_deref(r: Ref<'a, T>) -> Ref<'a, T::Target>
where
T: Deref,
{
Ref {
value: NonNull::from(<T as Deref>::deref(&*r)),
borrow: r.borrow,
}
}
}
impl<'a, T> Ref<'a, Option<T>> {
#[inline]
pub fn transpose(r: Ref<'a, Option<T>>) -> Option<Ref<'a, T>> {
Some(Ref {
value: r.as_ref().map(NonNull::from)?,
borrow: r.borrow,
})
}
}
impl<'a, T> Ref<'a, [T]> {
#[inline]
pub fn slice<R>(r: Ref<'a, [T]>, range: R) -> Ref<'a, [T]>
where
R: RangeBounds<usize>,
{
let bounds = (range.start_bound().cloned(), range.end_bound().cloned());
let slice = &*r;
let slice = &slice[bounds];
Ref {
value: NonNull::from(slice),
borrow: r.borrow,
}
}
}