use std::{
borrow::Borrow,
cmp::Ordering,
fmt::{self, Display, Formatter},
hash::{Hash, Hasher},
ops::Deref,
ptr,
sync::atomic,
};
use gazebo::prelude::*;
#[derive(Clone_, Dupe_, Copy_, Debug)]
pub struct FrozenRef<'f, T: 'f + ?Sized> {
pub(crate) value: &'f T,
}
impl<'f, T: 'f + ?Sized> FrozenRef<'f, T> {
pub(crate) const fn new(value: &'f T) -> FrozenRef<T> {
FrozenRef { value }
}
pub fn as_ref(self) -> &'f T {
self.value
}
pub fn map<F, U: 'f + ?Sized>(self, f: F) -> FrozenRef<'f, U>
where
for<'v> F: FnOnce(&'v T) -> &'v U,
{
FrozenRef {
value: f(self.value),
}
}
}
impl<'f, T: ?Sized + Display> Display for FrozenRef<'f, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.value.fmt(f)
}
}
impl<'f, T: ?Sized> Deref for FrozenRef<'f, T> {
type Target = T;
fn deref(&self) -> &T {
self.value
}
}
impl<'f, T: 'f + ?Sized> Borrow<T> for FrozenRef<'f, T> {
fn borrow(&self) -> &T {
&*self
}
}
impl<'f, T: 'f + ?Sized> Borrow<T> for FrozenRef<'f, Box<T>> {
fn borrow(&self) -> &T {
&*self
}
}
impl<'f, T: 'f + ?Sized> PartialEq for FrozenRef<'f, T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
(&*self as &T).eq(&*other as &T)
}
}
impl<'f, T: 'f + ?Sized> Eq for FrozenRef<'f, T> where T: Eq {}
impl<'f, T: 'f + ?Sized> PartialOrd for FrozenRef<'f, T>
where
T: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
(&*self as &T).partial_cmp(&*other as &T)
}
}
impl<'f, T: 'f + ?Sized> Ord for FrozenRef<'f, T>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
(&*self as &T).cmp(&*other as &T)
}
}
impl<'f, T: 'f + ?Sized> Hash for FrozenRef<'f, T>
where
T: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
(&*self as &T).hash(state);
}
}
pub(crate) struct AtomicFrozenRefOption<T>(atomic::AtomicPtr<T>);
impl<T> AtomicFrozenRefOption<T> {
pub(crate) fn new(module: Option<FrozenRef<T>>) -> AtomicFrozenRefOption<T> {
AtomicFrozenRefOption(atomic::AtomicPtr::new(match module {
Some(v) => v.as_ref() as *const T as *mut T,
None => ptr::null_mut(),
}))
}
pub(crate) fn load_relaxed(&self) -> Option<FrozenRef<'static, T>> {
let ptr = self.0.load(atomic::Ordering::Relaxed);
if ptr.is_null() {
None
} else {
Some(FrozenRef::new(unsafe { &*ptr }))
}
}
pub(crate) fn store_relaxed(&self, module: FrozenRef<T>) {
self.0.store(
module.as_ref() as *const T as *mut T,
atomic::Ordering::Relaxed,
);
}
}