1076 lines
33 KiB
Rust
1076 lines
33 KiB
Rust
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
// See Notices.txt for copyright information
|
|
#![allow(clippy::type_complexity)]
|
|
use crate::{
|
|
intern::type_map::TypeIdMap,
|
|
util::{ConstBool, GenericConstBool},
|
|
};
|
|
use bitvec::{ptr::BitPtr, slice::BitSlice, vec::BitVec};
|
|
use hashbrown::{hash_map::RawEntryMut, HashMap, HashTable};
|
|
use serde::{Deserialize, Serialize};
|
|
use std::{
|
|
any::{Any, TypeId},
|
|
borrow::{Borrow, Cow},
|
|
cmp::Ordering,
|
|
fmt,
|
|
hash::{BuildHasher, Hash, Hasher},
|
|
iter::FusedIterator,
|
|
marker::PhantomData,
|
|
ops::Deref,
|
|
sync::{Mutex, RwLock},
|
|
};
|
|
|
|
pub mod type_map;
|
|
|
|
pub trait InternedCompare {
|
|
type InternedCompareKey: Ord + Hash;
|
|
fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey;
|
|
fn interned_compare_key_weak(this: &std::sync::Weak<Self>) -> Self::InternedCompareKey;
|
|
}
|
|
|
|
/// Warning: doesn't do what you want with `T = dyn Trait`,
|
|
/// since it compares pointers, but pointers can be unequal due do
|
|
/// different copies of the same vtable
|
|
pub struct PtrEqWithMetadata<T: ?Sized>(pub *const T);
|
|
|
|
impl<T: ?Sized> Copy for PtrEqWithMetadata<T> {}
|
|
|
|
impl<T: ?Sized> Clone for PtrEqWithMetadata<T> {
|
|
fn clone(&self) -> Self {
|
|
*self
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized> PartialEq for PtrEqWithMetadata<T> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
std::ptr::eq(self.0, other.0)
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized> Eq for PtrEqWithMetadata<T> {}
|
|
|
|
impl<T: ?Sized> PartialOrd for PtrEqWithMetadata<T> {
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized> Ord for PtrEqWithMetadata<T> {
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
#[allow(ambiguous_wide_pointer_comparisons)]
|
|
self.0.cmp(&other.0)
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized> Hash for PtrEqWithMetadata<T> {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.0.hash(state);
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized> fmt::Debug for PtrEqWithMetadata<T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_tuple("PtrEqWithMetadata").field(&self.0).finish()
|
|
}
|
|
}
|
|
|
|
/// Warning: doesn't do what you want for `[T]` or `str`, since it ignores length
|
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
|
pub struct PtrEqWithTypeId(pub *const (), pub TypeId);
|
|
|
|
mod sealed {
|
|
pub trait SupportsPtrEqWithTypeIdSealed {}
|
|
}
|
|
|
|
pub trait SupportsPtrEqWithTypeId: 'static + sealed::SupportsPtrEqWithTypeIdSealed {
|
|
fn get_ptr_eq_with_type_id(&self) -> PtrEqWithTypeId;
|
|
}
|
|
|
|
impl<T: 'static> sealed::SupportsPtrEqWithTypeIdSealed for T {}
|
|
|
|
impl<T: 'static> SupportsPtrEqWithTypeId for T {
|
|
fn get_ptr_eq_with_type_id(&self) -> PtrEqWithTypeId {
|
|
PtrEqWithTypeId(self as *const Self as *const (), TypeId::of::<Self>())
|
|
}
|
|
}
|
|
|
|
impl<T> InternedCompare for T {
|
|
type InternedCompareKey = PtrEqWithMetadata<Self>;
|
|
fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey {
|
|
PtrEqWithMetadata(this)
|
|
}
|
|
fn interned_compare_key_weak(this: &std::sync::Weak<Self>) -> Self::InternedCompareKey {
|
|
PtrEqWithMetadata(this.as_ptr())
|
|
}
|
|
}
|
|
|
|
impl<T> InternedCompare for [T] {
|
|
type InternedCompareKey = PtrEqWithMetadata<Self>;
|
|
fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey {
|
|
PtrEqWithMetadata(this)
|
|
}
|
|
fn interned_compare_key_weak(this: &std::sync::Weak<Self>) -> Self::InternedCompareKey {
|
|
PtrEqWithMetadata(this.as_ptr())
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
pub struct BitSlicePtrEq(BitPtr, usize);
|
|
|
|
impl InternedCompare for BitSlice {
|
|
type InternedCompareKey = BitSlicePtrEq;
|
|
fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey {
|
|
BitSlicePtrEq(this.as_bitptr(), this.len())
|
|
}
|
|
fn interned_compare_key_weak(_this: &std::sync::Weak<Self>) -> Self::InternedCompareKey {
|
|
unreachable!("not currently implementable since Weak<BitSlice> can't be constructed")
|
|
}
|
|
}
|
|
|
|
impl InternedCompare for str {
|
|
type InternedCompareKey = PtrEqWithMetadata<Self>;
|
|
fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey {
|
|
PtrEqWithMetadata(this)
|
|
}
|
|
fn interned_compare_key_weak(this: &std::sync::Weak<Self>) -> Self::InternedCompareKey {
|
|
PtrEqWithMetadata(this.as_ptr())
|
|
}
|
|
}
|
|
|
|
pub trait InternContext: 'static + Send + Sync + Hash + Ord + fmt::Debug + Clone {
|
|
type InternedImpl<T: ?Sized + 'static + Send + Sync>: 'static + Send + Sync + Clone;
|
|
type InternedGuardImpl<T: ?Sized + 'static + Send + Sync>: 'static
|
|
+ Send
|
|
+ Sync
|
|
+ Clone
|
|
+ Borrow<T>;
|
|
type AllContextsAreIdentical: GenericConstBool;
|
|
fn interned_compare_key<T: InternedCompare + ?Sized + 'static + Send + Sync>(
|
|
v: &Self::InternedImpl<T>,
|
|
) -> T::InternedCompareKey {
|
|
T::interned_compare_key_ref(Self::guard(v).borrow())
|
|
}
|
|
fn guard<T: ?Sized + 'static + Send + Sync>(
|
|
v: &Self::InternedImpl<T>,
|
|
) -> Self::InternedGuardImpl<T>;
|
|
fn try_guard<T: ?Sized + 'static + Send + Sync>(
|
|
v: &Self::InternedImpl<T>,
|
|
) -> Option<Self::InternedGuardImpl<T>>;
|
|
fn into_guard<T: ?Sized + 'static + Send + Sync>(
|
|
v: Self::InternedImpl<T>,
|
|
) -> Self::InternedGuardImpl<T> {
|
|
Self::guard(&v)
|
|
}
|
|
fn unguard<T: ?Sized + 'static + Send + Sync>(
|
|
v: &Self::InternedGuardImpl<T>,
|
|
) -> Self::InternedImpl<T>;
|
|
fn unguard_move<T: ?Sized + 'static + Send + Sync>(
|
|
v: Self::InternedGuardImpl<T>,
|
|
) -> Self::InternedImpl<T> {
|
|
Self::unguard(&v)
|
|
}
|
|
fn alloc_str(&self, value: Cow<'_, str>) -> Self::InternedGuardImpl<str>;
|
|
fn alloc_slice<T: Clone + Send + Sync + 'static>(
|
|
&self,
|
|
value: Cow<'_, [T]>,
|
|
) -> Self::InternedGuardImpl<[T]>;
|
|
fn alloc_sized<T: Clone + Send + Sync + 'static>(
|
|
&self,
|
|
value: Cow<'_, T>,
|
|
) -> Self::InternedGuardImpl<T>;
|
|
fn interner<T: ?Sized + Send + Sync + 'static>(&self) -> &Interner<T, Self>;
|
|
}
|
|
|
|
pub trait BitSliceInternContext: InternContext {
|
|
fn alloc_bit_slice(&self, value: Cow<'_, BitSlice>) -> Self::InternedGuardImpl<BitSlice>;
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
|
|
pub struct GlobalContext;
|
|
|
|
impl InternContext for GlobalContext {
|
|
type InternedImpl<T: ?Sized + 'static + Send + Sync> = &'static T;
|
|
type InternedGuardImpl<T: ?Sized + 'static + Send + Sync> = &'static T;
|
|
type AllContextsAreIdentical = ConstBool<true>;
|
|
|
|
fn guard<T: ?Sized + 'static + Send + Sync>(
|
|
v: &Self::InternedImpl<T>,
|
|
) -> Self::InternedGuardImpl<T> {
|
|
*v
|
|
}
|
|
fn try_guard<T: ?Sized + 'static + Send + Sync>(
|
|
v: &Self::InternedImpl<T>,
|
|
) -> Option<Self::InternedGuardImpl<T>> {
|
|
Some(*v)
|
|
}
|
|
fn unguard<T: ?Sized + 'static + Send + Sync>(
|
|
v: &Self::InternedGuardImpl<T>,
|
|
) -> Self::InternedImpl<T> {
|
|
*v
|
|
}
|
|
fn alloc_str(&self, value: Cow<'_, str>) -> Self::InternedGuardImpl<str> {
|
|
value.into_owned().leak()
|
|
}
|
|
fn alloc_slice<T: Clone + Send + Sync + 'static>(
|
|
&self,
|
|
value: Cow<'_, [T]>,
|
|
) -> Self::InternedGuardImpl<[T]> {
|
|
value.into_owned().leak()
|
|
}
|
|
fn alloc_sized<T: Clone + Send + Sync + 'static>(
|
|
&self,
|
|
value: Cow<'_, T>,
|
|
) -> Self::InternedGuardImpl<T> {
|
|
Box::leak(Box::new(value.into_owned()))
|
|
}
|
|
fn interner<T: ?Sized + 'static + Send + Sync>(&self) -> &Interner<T, Self> {
|
|
static TYPE_ID_MAP: TypeIdMap = TypeIdMap::new();
|
|
TYPE_ID_MAP.get_or_insert_default()
|
|
}
|
|
}
|
|
|
|
impl BitSliceInternContext for GlobalContext {
|
|
fn alloc_bit_slice(&self, value: Cow<'_, BitSlice>) -> Self::InternedGuardImpl<BitSlice> {
|
|
value.into_owned().leak()
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct AGCContext(std::sync::Arc<TypeIdMap>);
|
|
|
|
impl AGCContext {
|
|
pub fn new() -> Self {
|
|
Self(std::sync::Arc::new(TypeIdMap::new()))
|
|
}
|
|
}
|
|
|
|
impl Default for AGCContext {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
pub struct AGCContextId(*const ());
|
|
|
|
impl fmt::Debug for AGCContextId {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
self.0.fmt(f)
|
|
}
|
|
}
|
|
|
|
impl AGCContext {
|
|
pub fn id(&self) -> AGCContextId {
|
|
AGCContextId(std::sync::Arc::as_ptr(&self.0).cast())
|
|
}
|
|
}
|
|
|
|
impl Hash for AGCContext {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.id().hash(state);
|
|
}
|
|
}
|
|
|
|
impl Ord for AGCContext {
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
self.id().cmp(&other.id())
|
|
}
|
|
}
|
|
|
|
impl PartialOrd for AGCContext {
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl Eq for AGCContext {}
|
|
|
|
impl PartialEq for AGCContext {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.id().eq(&other.id())
|
|
}
|
|
}
|
|
|
|
impl fmt::Debug for AGCContext {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_struct("AGCContext")
|
|
.field("id", &self.id())
|
|
.finish_non_exhaustive()
|
|
}
|
|
}
|
|
|
|
impl InternContext for AGCContext {
|
|
type InternedImpl<T: ?Sized + 'static + Send + Sync> = std::sync::Weak<T>;
|
|
type InternedGuardImpl<T: ?Sized + 'static + Send + Sync> = std::sync::Arc<T>;
|
|
type AllContextsAreIdentical = ConstBool<false>;
|
|
|
|
fn interned_compare_key<T: InternedCompare + ?Sized + 'static + Send + Sync>(
|
|
v: &Self::InternedImpl<T>,
|
|
) -> T::InternedCompareKey {
|
|
T::interned_compare_key_weak(v)
|
|
}
|
|
fn guard<T: ?Sized + 'static + Send + Sync>(
|
|
v: &Self::InternedImpl<T>,
|
|
) -> Self::InternedGuardImpl<T> {
|
|
v.upgrade().expect("expired")
|
|
}
|
|
fn try_guard<T: ?Sized + 'static + Send + Sync>(
|
|
v: &Self::InternedImpl<T>,
|
|
) -> Option<Self::InternedGuardImpl<T>> {
|
|
v.upgrade()
|
|
}
|
|
fn unguard<T: ?Sized + 'static + Send + Sync>(
|
|
v: &Self::InternedGuardImpl<T>,
|
|
) -> Self::InternedImpl<T> {
|
|
std::sync::Arc::downgrade(v)
|
|
}
|
|
fn alloc_str(&self, value: Cow<'_, str>) -> Self::InternedGuardImpl<str> {
|
|
match value {
|
|
Cow::Borrowed(value) => value.into(),
|
|
Cow::Owned(value) => value.into(),
|
|
}
|
|
}
|
|
fn alloc_slice<T: Clone + Send + Sync + 'static>(
|
|
&self,
|
|
value: Cow<'_, [T]>,
|
|
) -> Self::InternedGuardImpl<[T]> {
|
|
match value {
|
|
Cow::Borrowed(value) => value.into(),
|
|
Cow::Owned(value) => value.into(),
|
|
}
|
|
}
|
|
fn alloc_sized<T: Clone + Send + Sync + 'static>(
|
|
&self,
|
|
value: Cow<'_, T>,
|
|
) -> Self::InternedGuardImpl<T> {
|
|
std::sync::Arc::new(value.into_owned())
|
|
}
|
|
fn interner<T: ?Sized + Send + Sync + 'static>(&self) -> &Interner<T, Self> {
|
|
self.0.get_or_insert_default()
|
|
}
|
|
}
|
|
|
|
pub trait Intern<C: InternContext = GlobalContext>: Any + Send + Sync {
|
|
fn intern_with_ctx(&self, context: &C) -> Interned<Self, C>;
|
|
fn intern_sized_with_ctx(self, context: &C) -> Interned<Self, C>
|
|
where
|
|
Self: Clone,
|
|
{
|
|
Self::intern_owned_with_ctx(self, context)
|
|
}
|
|
fn intern_owned_with_ctx(this: <Self as ToOwned>::Owned, context: &C) -> Interned<Self, C>
|
|
where
|
|
Self: ToOwned,
|
|
{
|
|
Self::intern_cow_with_ctx(Cow::Owned(this), context)
|
|
}
|
|
fn intern_cow_with_ctx(this: Cow<'_, Self>, context: &C) -> Interned<Self, C>
|
|
where
|
|
Self: ToOwned,
|
|
{
|
|
this.intern_with_ctx(context)
|
|
}
|
|
fn intern(&self) -> Interned<Self, C>
|
|
where
|
|
C: InternContext<AllContextsAreIdentical = ConstBool<true>> + Default,
|
|
{
|
|
self.intern_with_ctx(&C::default())
|
|
}
|
|
fn intern_sized(self) -> Interned<Self, C>
|
|
where
|
|
Self: Clone,
|
|
C: InternContext<AllContextsAreIdentical = ConstBool<true>> + Default,
|
|
{
|
|
self.intern_sized_with_ctx(&C::default())
|
|
}
|
|
fn intern_owned(this: <Self as ToOwned>::Owned) -> Interned<Self, C>
|
|
where
|
|
Self: ToOwned,
|
|
C: InternContext<AllContextsAreIdentical = ConstBool<true>> + Default,
|
|
{
|
|
Self::intern_owned_with_ctx(this, &C::default())
|
|
}
|
|
fn intern_cow(this: Cow<'_, Self>) -> Interned<Self, C>
|
|
where
|
|
Self: ToOwned,
|
|
C: InternContext<AllContextsAreIdentical = ConstBool<true>> + Default,
|
|
{
|
|
Self::intern_cow_with_ctx(this, &C::default())
|
|
}
|
|
}
|
|
|
|
pub struct Interner<T: ?Sized + 'static + Send + Sync, C: InternContext> {
|
|
map: Mutex<HashMap<C::InternedGuardImpl<T>, ()>>,
|
|
_phantom: PhantomData<fn(&C)>,
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync, C: InternContext> Default for Interner<T, C> {
|
|
fn default() -> Self {
|
|
Self {
|
|
map: Default::default(),
|
|
_phantom: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync + Hash + Eq + ToOwned, C: InternContext> Interner<T, C> {
|
|
fn intern<F: FnOnce(Cow<'_, T>) -> C::InternedGuardImpl<T>>(
|
|
&self,
|
|
alloc: F,
|
|
value: Cow<'_, T>,
|
|
) -> Interned<T, C> {
|
|
let mut map = self.map.lock().unwrap();
|
|
let hasher = map.hasher().clone();
|
|
let hash = hasher.hash_one(&*value);
|
|
let inner = match map
|
|
.raw_entry_mut()
|
|
.from_hash(hash, |k| k.borrow() == &*value)
|
|
{
|
|
RawEntryMut::Occupied(entry) => C::unguard(entry.key()),
|
|
RawEntryMut::Vacant(entry) => C::unguard(
|
|
entry
|
|
.insert_with_hasher(hash, alloc(value), (), |k| hasher.hash_one(k.borrow()))
|
|
.0,
|
|
),
|
|
};
|
|
Interned {
|
|
inner,
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Clone + 'static + Send + Sync + Hash + Eq, C: InternContext> Interner<T, C> {
|
|
fn intern_sized(&self, context: &C, value: Cow<'_, T>) -> Interned<T, C> {
|
|
self.intern(|value| context.alloc_sized(value), value)
|
|
}
|
|
}
|
|
|
|
impl<T: Clone + 'static + Send + Sync + Hash + Eq, C: InternContext> Interner<[T], C> {
|
|
fn intern_slice(&self, context: &C, value: Cow<'_, [T]>) -> Interned<[T], C> {
|
|
self.intern(|value| context.alloc_slice(value), value)
|
|
}
|
|
}
|
|
|
|
impl<C: BitSliceInternContext> Interner<BitSlice, C> {
|
|
fn intern_bit_slice(&self, context: &C, value: Cow<'_, BitSlice>) -> Interned<BitSlice, C> {
|
|
self.intern(|value| context.alloc_bit_slice(value), value)
|
|
}
|
|
}
|
|
|
|
impl<C: InternContext> Interner<str, C> {
|
|
fn intern_str(&self, context: &C, value: Cow<'_, str>) -> Interned<str, C> {
|
|
self.intern(|value| context.alloc_str(value), value)
|
|
}
|
|
}
|
|
|
|
pub struct Interned<T: ?Sized + 'static + Send + Sync, C: InternContext = GlobalContext> {
|
|
inner: C::InternedImpl<T>,
|
|
_phantom: PhantomData<&'static C>,
|
|
}
|
|
|
|
macro_rules! forward_fmt_trait {
|
|
($Tr:ident) => {
|
|
impl<T: ?Sized + 'static + Send + Sync + fmt::$Tr, C: InternContext> fmt::$Tr
|
|
for Interned<T, C>
|
|
{
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
if let Some(guard) = C::try_guard(&self.inner) {
|
|
guard.borrow().fmt(f)
|
|
} else {
|
|
write!(f, "<Expired>")
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync + fmt::$Tr, C: InternContext> fmt::$Tr
|
|
for Guard<T, C>
|
|
{
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
self.inner.borrow().fmt(f)
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
forward_fmt_trait!(Debug);
|
|
forward_fmt_trait!(Display);
|
|
forward_fmt_trait!(LowerExp);
|
|
forward_fmt_trait!(LowerHex);
|
|
forward_fmt_trait!(Octal);
|
|
forward_fmt_trait!(Pointer);
|
|
forward_fmt_trait!(UpperExp);
|
|
forward_fmt_trait!(UpperHex);
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct InternedSliceIter<T: Clone + 'static + Send + Sync, C: InternContext> {
|
|
slice: Interned<[T], C>,
|
|
index: std::ops::Range<usize>,
|
|
}
|
|
|
|
impl<T: Clone + 'static + Send + Sync, C: InternContext> Iterator for InternedSliceIter<T, C> {
|
|
type Item = T;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
self.index
|
|
.next()
|
|
.map(|index| self.slice.guard()[index].clone())
|
|
}
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
self.index.size_hint()
|
|
}
|
|
}
|
|
|
|
impl<T: Clone + 'static + Send + Sync, C: InternContext> DoubleEndedIterator
|
|
for InternedSliceIter<T, C>
|
|
{
|
|
fn next_back(&mut self) -> Option<Self::Item> {
|
|
self.index
|
|
.next_back()
|
|
.map(|index| self.slice.guard()[index].clone())
|
|
}
|
|
}
|
|
|
|
impl<T: Clone + 'static + Send + Sync, C: InternContext> FusedIterator for InternedSliceIter<T, C> {}
|
|
|
|
impl<T: Clone + 'static + Send + Sync, C: InternContext> ExactSizeIterator
|
|
for InternedSliceIter<T, C>
|
|
{
|
|
}
|
|
|
|
impl<T: Clone + 'static + Send + Sync, C: InternContext> IntoIterator for Interned<[T], C> {
|
|
type Item = T;
|
|
type IntoIter = InternedSliceIter<T, C>;
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
InternedSliceIter {
|
|
index: 0..self.guard().len(),
|
|
slice: self,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, T: 'static + Send + Sync, C: InternContext> IntoIterator for &'a Interned<[T], C>
|
|
where
|
|
C::InternedImpl<[T]>: Borrow<[T]>,
|
|
{
|
|
type Item = &'a T;
|
|
type IntoIter = std::slice::Iter<'a, T>;
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
self.inner.borrow().iter()
|
|
}
|
|
}
|
|
|
|
impl<'a, T: 'static + Send + Sync, C: InternContext> IntoIterator for &'a mut Interned<[T], C>
|
|
where
|
|
C::InternedImpl<[T]>: Borrow<[T]>,
|
|
{
|
|
type Item = &'a T;
|
|
type IntoIter = std::slice::Iter<'a, T>;
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
self.inner.borrow().iter()
|
|
}
|
|
}
|
|
|
|
impl<I: Clone, C: InternContext<AllContextsAreIdentical = ConstBool<true>> + Default>
|
|
FromIterator<I> for Interned<[I], C>
|
|
where
|
|
[I]: Intern<C>,
|
|
{
|
|
fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
|
|
Intern::intern_owned(Vec::from_iter(iter))
|
|
}
|
|
}
|
|
|
|
impl<I, C: InternContext<AllContextsAreIdentical = ConstBool<true>> + Default> Default
|
|
for Interned<[I], C>
|
|
where
|
|
[I]: Intern<C>,
|
|
{
|
|
fn default() -> Self {
|
|
[][..].intern()
|
|
}
|
|
}
|
|
|
|
impl<C: InternContext<AllContextsAreIdentical = ConstBool<true>> + Default> Default
|
|
for Interned<str, C>
|
|
where
|
|
str: Intern<C>,
|
|
{
|
|
fn default() -> Self {
|
|
"".intern()
|
|
}
|
|
}
|
|
|
|
impl<C: BitSliceInternContext<AllContextsAreIdentical = ConstBool<true>> + Default> Default
|
|
for Interned<BitSlice, C>
|
|
where
|
|
BitSlice: Intern<C>,
|
|
{
|
|
fn default() -> Self {
|
|
<&BitSlice>::default().intern()
|
|
}
|
|
}
|
|
|
|
impl<I: Clone + Default, C: InternContext<AllContextsAreIdentical = ConstBool<true>> + Default>
|
|
Default for Interned<I, C>
|
|
where
|
|
I: Intern<C>,
|
|
{
|
|
fn default() -> Self {
|
|
I::default().intern()
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync, C: InternContext> Interned<T, C> {
|
|
pub fn cast_unchecked<U: ?Sized + 'static + Send + Sync>(
|
|
this: Self,
|
|
f: impl FnOnce(C::InternedImpl<T>) -> C::InternedImpl<U>,
|
|
) -> Interned<U, C> {
|
|
Interned {
|
|
inner: f(this.inner),
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
pub fn try_cast_unchecked<U: ?Sized + 'static + Send + Sync, E>(
|
|
this: Self,
|
|
f: impl FnOnce(C::InternedImpl<T>) -> Result<C::InternedImpl<U>, E>,
|
|
) -> Result<Interned<U, C>, E> {
|
|
Ok(Interned {
|
|
inner: f(this.inner)?,
|
|
_phantom: PhantomData,
|
|
})
|
|
}
|
|
pub fn into_inner(this: Self) -> C::InternedImpl<T> {
|
|
this.inner
|
|
}
|
|
pub fn get_ref(this: &Self) -> &C::InternedImpl<T> {
|
|
&this.inner
|
|
}
|
|
pub fn guard(&self) -> Guard<T, C> {
|
|
Guard {
|
|
inner: C::guard(&self.inner),
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync, C: InternContext> Clone for Interned<T, C> {
|
|
fn clone(&self) -> Self {
|
|
Interned {
|
|
inner: self.inner.clone(),
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync, C: InternContext> Copy for Interned<T, C> where
|
|
C::InternedImpl<T>: Copy
|
|
{
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync, C: InternContext> Deref for Interned<T, C>
|
|
where
|
|
C::InternedImpl<T>: Borrow<T>,
|
|
{
|
|
type Target = T;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
self.inner.borrow()
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync + InternedCompare, C: InternContext> PartialEq
|
|
for Interned<T, C>
|
|
{
|
|
fn eq(&self, other: &Self) -> bool {
|
|
<C as InternContext>::interned_compare_key(&self.inner)
|
|
== <C as InternContext>::interned_compare_key(&other.inner)
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync + InternedCompare, C: InternContext> Eq for Interned<T, C> {}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync + InternedCompare, C: InternContext> PartialOrd
|
|
for Interned<T, C>
|
|
{
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync + InternedCompare, C: InternContext> Ord for Interned<T, C> {
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
<C as InternContext>::interned_compare_key(&self.inner)
|
|
.cmp(&<C as InternContext>::interned_compare_key(&other.inner))
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync + InternedCompare, C: InternContext> Hash
|
|
for Interned<T, C>
|
|
{
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
<C as InternContext>::interned_compare_key(&self.inner).hash(state);
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync + Serialize, C: InternContext> Serialize for Interned<T, C> {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: serde::Serializer,
|
|
{
|
|
self.guard().serialize(serializer)
|
|
}
|
|
}
|
|
|
|
impl<
|
|
'de,
|
|
T: 'static + Send + Sync + Deserialize<'de> + Clone + Intern<C>,
|
|
C: InternContext<AllContextsAreIdentical = ConstBool<true>> + Default,
|
|
> Deserialize<'de> for Interned<T, C>
|
|
{
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
T::deserialize(deserializer).map(Intern::intern_sized)
|
|
}
|
|
}
|
|
|
|
impl<
|
|
'de,
|
|
T: 'static + Send + Sync + Clone,
|
|
C: InternContext<AllContextsAreIdentical = ConstBool<true>> + Default,
|
|
> Deserialize<'de> for Interned<[T], C>
|
|
where
|
|
[T]: Intern<C>,
|
|
Vec<T>: Deserialize<'de>,
|
|
{
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
Vec::<T>::deserialize(deserializer).map(Intern::intern_owned)
|
|
}
|
|
}
|
|
|
|
impl<'de, C: BitSliceInternContext<AllContextsAreIdentical = ConstBool<true>> + Default>
|
|
Deserialize<'de> for Interned<BitSlice, C>
|
|
where
|
|
BitSlice: Intern<C>,
|
|
{
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
BitVec::deserialize(deserializer).map(Intern::intern_owned)
|
|
}
|
|
}
|
|
|
|
impl<'de, C: InternContext<AllContextsAreIdentical = ConstBool<true>> + Default> Deserialize<'de>
|
|
for Interned<str, C>
|
|
where
|
|
str: Intern<C>,
|
|
{
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
String::deserialize(deserializer).map(Intern::intern_owned)
|
|
}
|
|
}
|
|
|
|
pub struct Guard<T: ?Sized + 'static + Send + Sync, C: InternContext = GlobalContext> {
|
|
inner: C::InternedGuardImpl<T>,
|
|
_phantom: PhantomData<&'static C>,
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync, C: InternContext> Guard<T, C> {
|
|
pub fn cast_unchecked<U: ?Sized + 'static + Send + Sync>(
|
|
this: Self,
|
|
f: impl FnOnce(C::InternedGuardImpl<T>) -> C::InternedGuardImpl<U>,
|
|
) -> Guard<U, C> {
|
|
Guard {
|
|
inner: f(this.inner),
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
pub fn try_cast_unchecked<U: ?Sized + 'static + Send + Sync, E>(
|
|
this: Self,
|
|
f: impl FnOnce(C::InternedGuardImpl<T>) -> Result<C::InternedGuardImpl<U>, E>,
|
|
) -> Result<Guard<U, C>, E> {
|
|
Ok(Guard {
|
|
inner: f(this.inner)?,
|
|
_phantom: PhantomData,
|
|
})
|
|
}
|
|
pub fn into_inner(this: Self) -> C::InternedGuardImpl<T> {
|
|
this.inner
|
|
}
|
|
pub fn get_ref(this: &Self) -> &C::InternedGuardImpl<T> {
|
|
&this.inner
|
|
}
|
|
pub fn unguard(&self) -> Interned<T, C> {
|
|
Interned {
|
|
inner: C::unguard(&self.inner),
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync, C: InternContext> Clone for Guard<T, C> {
|
|
fn clone(&self) -> Self {
|
|
Guard {
|
|
inner: self.inner.clone(),
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync, C: InternContext> Copy for Guard<T, C> where
|
|
C::InternedGuardImpl<T>: Copy
|
|
{
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync, C: InternContext> Deref for Guard<T, C> {
|
|
type Target = T;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
self.inner.borrow()
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync + InternedCompare, C: InternContext> PartialEq
|
|
for Guard<T, C>
|
|
{
|
|
fn eq(&self, other: &Self) -> bool {
|
|
T::interned_compare_key_ref(self.inner.borrow())
|
|
== T::interned_compare_key_ref(other.inner.borrow())
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync + InternedCompare, C: InternContext> Eq for Guard<T, C> {}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync + InternedCompare, C: InternContext> PartialOrd
|
|
for Guard<T, C>
|
|
{
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync + InternedCompare, C: InternContext> Ord for Guard<T, C> {
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
T::interned_compare_key_ref(self.inner.borrow())
|
|
.cmp(&T::interned_compare_key_ref(other.inner.borrow()))
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + 'static + Send + Sync + InternedCompare, C: InternContext> Hash for Guard<T, C> {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
T::interned_compare_key_ref(self.inner.borrow()).hash(state);
|
|
}
|
|
}
|
|
|
|
impl<T: Clone + Send + Sync + 'static + Hash + Eq, C: InternContext> Intern<C> for T {
|
|
fn intern_with_ctx(&self, context: &C) -> Interned<Self, C> {
|
|
Self::intern_cow_with_ctx(Cow::Borrowed(self), context)
|
|
}
|
|
|
|
fn intern_owned_with_ctx(this: <Self as ToOwned>::Owned, context: &C) -> Interned<Self, C>
|
|
where
|
|
Self: ToOwned,
|
|
{
|
|
Self::intern_cow_with_ctx(Cow::Owned(this), context)
|
|
}
|
|
|
|
fn intern_cow_with_ctx(this: Cow<'_, Self>, context: &C) -> Interned<Self, C>
|
|
where
|
|
Self: ToOwned,
|
|
{
|
|
context.interner().intern_sized(context, this)
|
|
}
|
|
}
|
|
|
|
impl<T: Clone + Send + Sync + 'static + Hash + Eq, C: InternContext> Intern<C> for [T] {
|
|
fn intern_with_ctx(&self, context: &C) -> Interned<Self, C> {
|
|
Self::intern_cow_with_ctx(Cow::Borrowed(self), context)
|
|
}
|
|
|
|
fn intern_owned_with_ctx(this: <Self as ToOwned>::Owned, context: &C) -> Interned<Self, C>
|
|
where
|
|
Self: ToOwned,
|
|
{
|
|
Self::intern_cow_with_ctx(Cow::Owned(this), context)
|
|
}
|
|
|
|
fn intern_cow_with_ctx(this: Cow<'_, Self>, context: &C) -> Interned<Self, C>
|
|
where
|
|
Self: ToOwned,
|
|
{
|
|
context.interner().intern_slice(context, this)
|
|
}
|
|
}
|
|
|
|
impl<C: BitSliceInternContext> Intern<C> for BitSlice {
|
|
fn intern_with_ctx(&self, context: &C) -> Interned<Self, C> {
|
|
Self::intern_cow_with_ctx(Cow::Borrowed(self), context)
|
|
}
|
|
|
|
fn intern_owned_with_ctx(this: <Self as ToOwned>::Owned, context: &C) -> Interned<Self, C>
|
|
where
|
|
Self: ToOwned,
|
|
{
|
|
Self::intern_cow_with_ctx(Cow::Owned(this), context)
|
|
}
|
|
|
|
fn intern_cow_with_ctx(this: Cow<'_, Self>, context: &C) -> Interned<Self, C>
|
|
where
|
|
Self: ToOwned,
|
|
{
|
|
context.interner().intern_bit_slice(context, this)
|
|
}
|
|
}
|
|
|
|
impl<C: InternContext> Intern<C> for str {
|
|
fn intern_with_ctx(&self, context: &C) -> Interned<Self, C> {
|
|
Self::intern_cow_with_ctx(Cow::Borrowed(self), context)
|
|
}
|
|
|
|
fn intern_owned_with_ctx(this: <Self as ToOwned>::Owned, context: &C) -> Interned<Self, C>
|
|
where
|
|
Self: ToOwned,
|
|
{
|
|
Self::intern_cow_with_ctx(Cow::Owned(this), context)
|
|
}
|
|
|
|
fn intern_cow_with_ctx(this: Cow<'_, Self>, context: &C) -> Interned<Self, C>
|
|
where
|
|
Self: ToOwned,
|
|
{
|
|
context.interner().intern_str(context, this)
|
|
}
|
|
}
|
|
|
|
pub trait MemoizeGeneric: 'static + Send + Sync + Hash + Eq + Copy {
|
|
type InputRef<'a>: 'a + Send + Sync + Hash + Copy;
|
|
type InputOwned: 'static + Send + Sync;
|
|
type InputCow<'a>: 'a;
|
|
type Output: 'static + Send + Sync + Clone;
|
|
fn input_eq(a: Self::InputRef<'_>, b: Self::InputRef<'_>) -> bool;
|
|
fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_>;
|
|
fn input_cow_into_owned(input: Self::InputCow<'_>) -> Self::InputOwned;
|
|
fn input_cow_borrow<'a>(input: &'a Self::InputCow<'_>) -> Self::InputRef<'a>;
|
|
fn input_cow_from_owned<'a>(input: Self::InputOwned) -> Self::InputCow<'a>;
|
|
fn input_cow_from_ref(input: Self::InputRef<'_>) -> Self::InputCow<'_>;
|
|
fn inner(self, input: Self::InputRef<'_>) -> Self::Output;
|
|
fn get_cow(self, input: Self::InputCow<'_>) -> Self::Output {
|
|
static TYPE_ID_MAP: TypeIdMap = TypeIdMap::new();
|
|
let map: &RwLock<(
|
|
hashbrown::hash_map::DefaultHashBuilder,
|
|
HashTable<(Self, Self::InputOwned, Self::Output)>,
|
|
)> = TYPE_ID_MAP.get_or_insert_default();
|
|
fn hash_eq_key<'a, 'b, T: MemoizeGeneric>(
|
|
this: &'a T,
|
|
input: T::InputRef<'b>,
|
|
) -> (&'a T, T::InputRef<'b>) {
|
|
(this, input)
|
|
}
|
|
fn hash_eq_key_eq<T: MemoizeGeneric>(
|
|
key: (&T, T::InputRef<'_>),
|
|
this: &T,
|
|
input: T::InputRef<'_>,
|
|
) -> bool {
|
|
let other = hash_eq_key(this, input);
|
|
key.0 == other.0 && T::input_eq(key.1, other.1)
|
|
}
|
|
let key = hash_eq_key(&self, Self::input_cow_borrow(&input));
|
|
let hash;
|
|
{
|
|
let read = map.read().unwrap();
|
|
let (hasher, map) = &*read;
|
|
hash = hasher.hash_one(key);
|
|
if let Some((_, _, output)) = map.find(hash, |(this2, input2, _)| {
|
|
hash_eq_key_eq(key, this2, Self::input_borrow(input2))
|
|
}) {
|
|
return output.clone();
|
|
}
|
|
drop(read);
|
|
}
|
|
// make sure to call inner while map isn't locked since inner may call get_cow again
|
|
let output = self.inner(Self::input_cow_borrow(&input));
|
|
let mut write = map.write().unwrap();
|
|
let (hasher, map) = &mut *write;
|
|
map.entry(
|
|
hash,
|
|
|(this2, input2, _)| hash_eq_key_eq(key, this2, Self::input_borrow(input2)),
|
|
|(this2, input2, _)| hasher.hash_one(hash_eq_key(this2, Self::input_borrow(input2))),
|
|
)
|
|
.or_insert_with(|| (self, Self::input_cow_into_owned(input), output))
|
|
.get()
|
|
.2
|
|
.clone()
|
|
}
|
|
fn get_owned(self, input: Self::InputOwned) -> Self::Output {
|
|
self.get_cow(Self::input_cow_from_owned(input))
|
|
}
|
|
fn get(self, input: Self::InputRef<'_>) -> Self::Output {
|
|
self.get_cow(Self::input_cow_from_ref(input))
|
|
}
|
|
}
|
|
|
|
pub trait Memoize: 'static + Send + Sync + Hash + Eq + Copy {
|
|
type Input: ?Sized + 'static + Send + Sync + ToOwned<Owned = Self::InputOwned> + Hash + Eq;
|
|
type InputOwned: 'static + Send + Sync + Borrow<Self::Input>;
|
|
type Output: 'static + Send + Sync + Clone;
|
|
fn inner(self, input: &Self::Input) -> Self::Output;
|
|
fn get_cow(self, input: Cow<'_, Self::Input>) -> Self::Output {
|
|
#[derive(Hash, Eq, PartialEq, Copy, Clone)]
|
|
struct MemoizeGenericWrapper<T: Memoize>(T);
|
|
impl<T: Memoize> MemoizeGeneric for MemoizeGenericWrapper<T> {
|
|
type InputRef<'a> = &'a T::Input;
|
|
type InputOwned = T::InputOwned;
|
|
type InputCow<'a> = Cow<'a, T::Input>;
|
|
type Output = T::Output;
|
|
|
|
fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_> {
|
|
input.borrow()
|
|
}
|
|
|
|
fn input_eq(a: Self::InputRef<'_>, b: Self::InputRef<'_>) -> bool {
|
|
a == b
|
|
}
|
|
|
|
fn input_cow_into_owned(input: Self::InputCow<'_>) -> Self::InputOwned {
|
|
input.into_owned()
|
|
}
|
|
|
|
fn input_cow_borrow<'a>(input: &'a Self::InputCow<'_>) -> Self::InputRef<'a> {
|
|
&**input
|
|
}
|
|
|
|
fn input_cow_from_owned<'a>(input: Self::InputOwned) -> Self::InputCow<'a> {
|
|
Cow::Owned(input)
|
|
}
|
|
|
|
fn input_cow_from_ref(input: Self::InputRef<'_>) -> Self::InputCow<'_> {
|
|
Cow::Borrowed(input)
|
|
}
|
|
|
|
fn inner(self, input: Self::InputRef<'_>) -> Self::Output {
|
|
self.0.inner(input)
|
|
}
|
|
}
|
|
|
|
MemoizeGenericWrapper(self).get_cow(input)
|
|
}
|
|
fn get_owned(self, input: Self::InputOwned) -> Self::Output {
|
|
self.get_cow(Cow::Owned(input))
|
|
}
|
|
fn get(self, input: &Self::Input) -> Self::Output {
|
|
self.get_cow(Cow::Borrowed(input))
|
|
}
|
|
}
|