use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt;
use std::fmt::Display;
use std::fmt::Formatter;
use std::hash::Hash;
use std::hash::Hasher;
use std::ops::Deref;
use std::ptr;
use std::sync::atomic;
use allocative::Allocative;
use dupe::Clone_;
use dupe::Copy_;
use dupe::Dupe;
use dupe::Dupe_;
use crate::values::Freeze;
use crate::values::Freezer;
use crate::values::FrozenHeapRef;
use crate::values::Trace;
use crate::values::Tracer;
#[derive(Clone_, Dupe_, Copy_, Debug, Allocative)]
#[allocative(skip)] pub struct FrozenRef<'f, T: 'f + ?Sized> {
pub(crate) value: &'f T,
}
impl<'f, T> Default for FrozenRef<'f, [T]> {
fn default() -> FrozenRef<'f, [T]> {
FrozenRef { value: &[] }
}
}
unsafe impl<'v, 'f, T: 'f + ?Sized> Trace<'v> for FrozenRef<'f, T> {
fn trace(&mut self, _: &Tracer<'v>) {
}
}
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),
}
}
pub fn try_map_result<F, U: 'f + ?Sized, E>(self, f: F) -> Result<FrozenRef<'f, U>, E>
where
for<'v> F: FnOnce(&'v T) -> Result<&'v U, E>,
{
Ok(FrozenRef {
value: f(self.value)?,
})
}
pub fn try_map_option<F, U: 'f + ?Sized>(self, f: F) -> Option<FrozenRef<'f, U>>
where
for<'v> F: FnOnce(&'v T) -> Option<&'v U>,
{
Some(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);
}
}
impl<'f, T: 'f + ?Sized> Freeze for FrozenRef<'f, T> {
type Frozen = Self;
fn freeze(self, _freezer: &Freezer) -> anyhow::Result<Self::Frozen> {
Ok(self)
}
}
pub(crate) struct AtomicFrozenRefOption<T>(atomic::AtomicPtr<T>);
unsafe impl<'v, T> Trace<'v> for AtomicFrozenRefOption<T> {
fn trace(&mut self, _: &Tracer<'v>) {
}
}
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,
);
}
}
#[derive(Clone, Dupe, Allocative)]
pub struct OwnedFrozenRef<T: ?Sized + 'static> {
owner: FrozenHeapRef,
value: FrozenRef<'static, T>,
}
impl<T: ?Sized> OwnedFrozenRef<T> {
pub unsafe fn new_unchecked(value: &'static T, owner: FrozenHeapRef) -> OwnedFrozenRef<T> {
OwnedFrozenRef {
owner,
value: FrozenRef::new(value),
}
}
pub fn as_ref<'a>(&'a self) -> &'a T {
self.value.as_ref()
}
pub fn map<F, U: ?Sized>(self, f: F) -> OwnedFrozenRef<U>
where
for<'v> F: FnOnce(&'v T) -> &'v U,
{
OwnedFrozenRef {
owner: self.owner,
value: self.value.map(f),
}
}
pub fn try_map_result<F, U: ?Sized, E>(self, f: F) -> Result<OwnedFrozenRef<U>, E>
where
for<'v> F: FnOnce(&'v T) -> Result<&'v U, E>,
{
Ok(OwnedFrozenRef {
owner: self.owner,
value: self.value.try_map_result(f)?,
})
}
pub fn try_map_option<F, U: ?Sized>(self, f: F) -> Option<OwnedFrozenRef<U>>
where
for<'v> F: FnOnce(&'v T) -> Option<&'v U>,
{
Some(OwnedFrozenRef {
owner: self.owner,
value: self.value.try_map_option(f)?,
})
}
pub fn owner(&self) -> &FrozenHeapRef {
&self.owner
}
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for OwnedFrozenRef<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.value, f)
}
}
impl<T: ?Sized + fmt::Display> fmt::Display for OwnedFrozenRef<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.value, f)
}
}
impl<T: ?Sized> Deref for OwnedFrozenRef<T> {
type Target = T;
fn deref(&self) -> &T {
self.as_ref()
}
}