// 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::DefaultBuildHasher}; use bitvec::{ptr::BitPtr, slice::BitSlice, vec::BitVec}; use hashbrown::HashTable; use once_cell::race::OnceRef; use serde::{Deserialize, Serialize}; use std::{ any::{Any, TypeId}, borrow::{Borrow, Cow}, cell::RefCell, cmp::Ordering, ffi::{OsStr, OsString}, fmt, hash::{BuildHasher, Hash, Hasher}, iter::FusedIterator, ops::Deref, path::{Path, PathBuf}, sync::RwLock, }; mod interner; mod type_map; /// invariant: T must be zero-sized, `type_id` is unique for every possible T value. struct LazyInternedLazyInner { type_id: TypeId, value: T, } impl Hash for LazyInternedLazyInner { fn hash(&self, state: &mut H) { let Self { type_id, value: _ } = self; type_id.hash(state); } } impl PartialEq for LazyInternedLazyInner { fn eq(&self, other: &Self) -> bool { let Self { type_id, value: _ } = self; *type_id == other.type_id } } impl Eq for LazyInternedLazyInner {} impl fmt::Debug for LazyInternedLazyInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("LazyInternedLazyInner") .finish_non_exhaustive() } } impl LazyInternedLazyInner { const fn new(value: T) -> Self where T: Sized, { const { assert!(size_of::() == 0) }; Self { type_id: TypeId::of::(), value, } } } pub struct LazyInternedLazy( &'static LazyInternedLazyInner Interned + Send + Sync>, ); impl LazyInternedLazy { pub const fn new_const>>() -> Self { Self(&const { LazyInternedLazyInner::new(|| V::default().into()) }) } pub const fn new_const_default() -> Self where Interned: Default, { Self::new_const::>() } pub fn interned(self) -> Interned { struct Map(hashbrown::HashTable<(TypeId, &'static (dyn Any + Send + Sync))>); impl Map { const EMPTY: Self = Self(hashbrown::HashTable::new()); fn get( &self, lazy_interned_lazy: LazyInternedLazy, hash: u64, ) -> Option<&'static Interned> { let &(_, v) = self.0.find(hash, |v| v.0 == lazy_interned_lazy.0.type_id)?; let Some(retval) = v.downcast_ref::>() else { unreachable!(); }; Some(retval) } fn get_or_insert( &mut self, lazy_interned_lazy: LazyInternedLazy, hash: u64, v: &'static Interned, ) -> &'static Interned { let entry = self .0 .entry( hash, |&(k, _)| k == lazy_interned_lazy.0.type_id, |&(k, _)| type_map::TypeIdBuildHasher.hash_one(k), ) .or_insert_with(|| (lazy_interned_lazy.0.type_id, v)); let &(_, v) = entry.get(); let Some(retval) = v.downcast_ref::>() else { unreachable!(); }; retval } } static GLOBAL_CACHE: RwLock = RwLock::new(Map::EMPTY); #[cold] fn insert_in_thread_local_cache( cache: &RefCell, this: LazyInternedLazy, hash: u64, ) -> Interned { let read_lock = GLOBAL_CACHE.read().unwrap(); let v = read_lock.get(this, hash); drop(read_lock); let v = v.unwrap_or_else(|| { let v = Box::leak(Box::new((this.0.value)())); GLOBAL_CACHE.write().unwrap().get_or_insert(this, hash, v) }); *cache.borrow_mut().get_or_insert(this, hash, v) } thread_local! { static THREAD_LOCAL_CACHE: RefCell = const { RefCell::new(Map::EMPTY) }; } let hash = type_map::TypeIdBuildHasher.hash_one(self.0.type_id); THREAD_LOCAL_CACHE.with(|cache| { let borrow = cache.borrow(); if let Some(v) = borrow.get(self, hash) { *v } else { drop(borrow); insert_in_thread_local_cache(cache, self, hash) } }) } } impl Copy for LazyInternedLazy {} impl Clone for LazyInternedLazy { fn clone(&self) -> Self { *self } } impl Hash for LazyInternedLazy { fn hash(&self, state: &mut H) { self.0.hash(state); } } impl Eq for LazyInternedLazy {} impl PartialEq for LazyInternedLazy { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } pub enum LazyInterned { Interned(Interned), Lazy(LazyInternedLazy), } impl LazyInterned { pub const fn new_const>>() -> Self { Self::Lazy(LazyInternedLazy::new_const::()) } pub const fn new_const_default() -> Self where Interned: Default, { Self::new_const::>() } pub fn interned(self) -> Interned { match self { Self::Interned(retval) => retval, Self::Lazy(retval) => retval.interned(), } } } impl Clone for LazyInterned { fn clone(&self) -> Self { *self } } impl Copy for LazyInterned {} impl Deref for LazyInterned { type Target = T; fn deref(&self) -> &Self::Target { Interned::into_inner(self.interned()) } } impl Eq for LazyInterned where Interned: Eq {} impl PartialEq for LazyInterned where Interned: PartialEq, { fn eq(&self, other: &Self) -> bool { self.interned() == other.interned() } } impl Ord for LazyInterned where Interned: Ord, { fn cmp(&self, other: &Self) -> Ordering { self.interned().cmp(&other.interned()) } } impl PartialOrd for LazyInterned where Interned: PartialOrd, { fn partial_cmp(&self, other: &Self) -> Option { self.interned().partial_cmp(&other.interned()) } } impl Hash for LazyInterned where Interned: Hash, { fn hash(&self, state: &mut H) { self.interned().hash(state); } } pub trait InternedCompare { type InternedCompareKey: Ord + Hash; fn interned_compare_key_ref(this: &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(pub *const T); impl Copy for PtrEqWithMetadata {} impl Clone for PtrEqWithMetadata { fn clone(&self) -> Self { *self } } impl PartialEq for PtrEqWithMetadata { fn eq(&self, other: &Self) -> bool { std::ptr::eq(self.0, other.0) } } impl Eq for PtrEqWithMetadata {} impl PartialOrd for PtrEqWithMetadata { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for PtrEqWithMetadata { fn cmp(&self, other: &Self) -> Ordering { #[allow(ambiguous_wide_pointer_comparisons)] self.0.cmp(&other.0) } } impl Hash for PtrEqWithMetadata { fn hash(&self, state: &mut H) { self.0.hash(state); } } impl fmt::Debug for PtrEqWithMetadata { 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 sealed::SupportsPtrEqWithTypeIdSealed for T {} impl SupportsPtrEqWithTypeId for T { fn get_ptr_eq_with_type_id(&self) -> PtrEqWithTypeId { PtrEqWithTypeId(self as *const Self as *const (), TypeId::of::()) } } impl InternedCompare for T { type InternedCompareKey = PtrEqWithMetadata; fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { PtrEqWithMetadata(this) } } impl InternedCompare for [T] { type InternedCompareKey = PtrEqWithMetadata; fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { PtrEqWithMetadata(this) } } #[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()) } } /// Safety: `as_bytes` and `from_bytes_unchecked` must return the same pointer as the input. /// all values returned by `as_bytes` must be valid to pass to `from_bytes_unchecked`. /// `into_bytes` must return the exact same thing as `as_bytes`. /// `Interned` must contain the exact same references as `Interned<[u8]>`, /// so they can be safely interconverted without needing re-interning. unsafe trait InternStrLike: ToOwned { fn as_bytes(this: &Self) -> &[u8]; fn into_bytes(this: Self::Owned) -> Vec; /// Safety: `bytes` must be a valid sequence of bytes for this type. All UTF-8 sequences are valid. unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self; } macro_rules! impl_intern_str_like { ($ty:ty, owned = $Owned:ty) => { impl InternedCompare for $ty { type InternedCompareKey = PtrEqWithMetadata<[u8]>; fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { PtrEqWithMetadata(InternStrLike::as_bytes(this)) } } impl Intern for $ty { fn intern(&self) -> Interned { Self::intern_cow(Cow::Borrowed(self)) } fn intern_cow(this: Cow<'_, Self>) -> Interned { Interned::cast_unchecked( <[u8]>::intern_cow(match this { Cow::Borrowed(v) => Cow::Borrowed(::as_bytes(v)), Cow::Owned(v) => { // verify $Owned is correct let v: $Owned = v; Cow::Owned(::into_bytes(v)) } }), // Safety: guaranteed safe because we got the bytes from `as_bytes`/`into_bytes` |v| unsafe { ::from_bytes_unchecked(v) }, ) } } impl Default for Interned<$ty> { fn default() -> Self { // Safety: safe because the empty sequence is valid UTF-8 unsafe { <$ty as InternStrLike>::from_bytes_unchecked(&[]) }.intern() } } impl<'de> Deserialize<'de> for Interned<$ty> { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { Cow::<'de, $ty>::deserialize(deserializer).map(Intern::intern_cow) } } impl From<$Owned> for Interned<$ty> { fn from(v: $Owned) -> Self { v.intern_deref() } } impl From> for $Owned { fn from(v: Interned<$ty>) -> Self { Interned::into_inner(v).into() } } impl From> for Box<$ty> { fn from(v: Interned<$ty>) -> Self { Interned::into_inner(v).into() } } }; } // Safety: satisfies `InternStrLike`'s requirements where the valid sequences for `from_bytes_unchecked` matches `str` unsafe impl InternStrLike for str { fn as_bytes(this: &Self) -> &[u8] { this.as_bytes() } fn into_bytes(this: Self::Owned) -> Vec { this.into_bytes() } unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { // Safety: `bytes` is guaranteed UTF-8 by the caller unsafe { str::from_utf8_unchecked(bytes) } } } impl_intern_str_like!(str, owned = String); // Safety: satisfies `InternStrLike`'s requirements where the valid sequences for `from_bytes_unchecked` matches `OsStr` unsafe impl InternStrLike for OsStr { fn as_bytes(this: &Self) -> &[u8] { this.as_encoded_bytes() } fn into_bytes(this: Self::Owned) -> Vec { this.into_encoded_bytes() } unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { // Safety: `bytes` is guaranteed valid for `OsStr` by the caller unsafe { OsStr::from_encoded_bytes_unchecked(bytes) } } } impl_intern_str_like!(OsStr, owned = OsString); // Safety: satisfies `InternStrLike`'s requirements where the valid sequences for `from_bytes_unchecked` matches `OsStr` unsafe impl InternStrLike for Path { fn as_bytes(this: &Self) -> &[u8] { this.as_os_str().as_encoded_bytes() } fn into_bytes(this: Self::Owned) -> Vec { this.into_os_string().into_encoded_bytes() } unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { // Safety: `bytes` is guaranteed valid for `OsStr` by the caller unsafe { Path::new(OsStr::from_encoded_bytes_unchecked(bytes)) } } } impl_intern_str_like!(Path, owned = PathBuf); impl Interned { pub fn from_utf8(v: Interned<[u8]>) -> Result { Interned::try_cast_unchecked(v, str::from_utf8) } pub fn as_interned_bytes(self) -> Interned<[u8]> { Interned::cast_unchecked(self, str::as_bytes) } pub fn as_interned_os_str(self) -> Interned { Interned::cast_unchecked(self, AsRef::as_ref) } pub fn as_interned_path(self) -> Interned { Interned::cast_unchecked(self, AsRef::as_ref) } } impl From> for Interned { fn from(value: Interned) -> Self { value.as_interned_os_str() } } impl From> for Interned { fn from(value: Interned) -> Self { value.as_interned_path() } } impl Interned { pub fn as_interned_encoded_bytes(self) -> Interned<[u8]> { Interned::cast_unchecked(self, OsStr::as_encoded_bytes) } pub fn to_interned_str(self) -> Option> { Interned::try_cast_unchecked(self, |v| v.to_str().ok_or(())).ok() } pub fn display(self) -> std::ffi::os_str::Display<'static> { Self::into_inner(self).display() } pub fn as_interned_path(self) -> Interned { Interned::cast_unchecked(self, AsRef::as_ref) } } impl From> for Interned { fn from(value: Interned) -> Self { value.as_interned_path() } } impl Interned { pub fn as_interned_os_str(self) -> Interned { Interned::cast_unchecked(self, AsRef::as_ref) } pub fn to_interned_str(self) -> Option> { Interned::try_cast_unchecked(self, |v| v.to_str().ok_or(())).ok() } pub fn display(self) -> std::path::Display<'static> { Self::into_inner(self).display() } pub fn interned_file_name(self) -> Option> { Some(self.file_name()?.intern()) } } impl From> for Interned { fn from(value: Interned) -> Self { value.as_interned_os_str() } } pub trait InternSlice: Sized { type Element: 'static + Send + Sync + Clone + Hash + Eq; fn intern_slice(self) -> Interned<[Self::Element]>; } impl InternSlice for Box<[T]> { type Element = T; fn intern_slice(self) -> Interned<[Self::Element]> { self.into_vec().intern_slice() } } impl InternSlice for Vec { type Element = T; fn intern_slice(self) -> Interned<[Self::Element]> { self.intern_deref() } } impl InternSlice for &'_ [T] { type Element = T; fn intern_slice(self) -> Interned<[Self::Element]> { self.intern() } } impl InternSlice for &'_ mut [T] { type Element = T; fn intern_slice(self) -> Interned<[Self::Element]> { self.intern() } } impl InternSlice for [T; N] { type Element = T; fn intern_slice(self) -> Interned<[Self::Element]> { (&self).intern_slice() } } impl InternSlice for Box<[T; N]> { type Element = T; fn intern_slice(self) -> Interned<[Self::Element]> { let this: Box<[T]> = self; this.intern_slice() } } impl InternSlice for &'_ [T; N] { type Element = T; fn intern_slice(self) -> Interned<[Self::Element]> { let this: &[T] = self; this.intern() } } impl InternSlice for &'_ mut [T; N] { type Element = T; fn intern_slice(self) -> Interned<[Self::Element]> { let this: &[T] = self; this.intern() } } pub trait Intern: Any + Send + Sync { fn intern(&self) -> Interned; fn intern_deref(self) -> Interned where Self: Sized + Deref>, { Self::Target::intern_owned(self) } fn intern_sized(self) -> Interned where Self: Clone, { Self::intern_owned(self) } fn intern_owned(this: ::Owned) -> Interned where Self: ToOwned, { Self::intern_cow(Cow::Owned(this)) } fn intern_cow(this: Cow<'_, Self>) -> Interned where Self: ToOwned, { this.intern() } } impl From> for Interned { fn from(value: Cow<'_, T>) -> Self { Intern::intern_cow(value) } } impl From<&'_ T> for Interned { fn from(value: &'_ T) -> Self { Intern::intern(value) } } impl From for Interned { fn from(value: T) -> Self { Intern::intern_sized(value) } } impl From> for Cow<'_, T> { fn from(value: Interned) -> Self { Cow::Borrowed(Interned::into_inner(value)) } } pub struct Interned { inner: &'static T, } macro_rules! forward_fmt_trait { ($Tr:ident) => { impl fmt::$Tr for LazyInterned { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { T::fmt(&**self, f) } } impl fmt::$Tr for Interned { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.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); impl, U: ?Sized> AsRef for Interned { fn as_ref(&self) -> &U { T::as_ref(self) } } #[derive(Clone, Debug)] pub struct InternedSliceIter { iter: std::iter::Cloned>, } impl Default for InternedSliceIter { fn default() -> Self { Self { iter: [].iter().cloned(), } } } impl Iterator for InternedSliceIter { type Item = T; fn next(&mut self) -> Option { self.iter.next() } fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } fn count(self) -> usize { self.iter.count() } fn last(mut self) -> Option { self.next_back() } fn nth(&mut self, n: usize) -> Option { self.iter.nth(n) } fn fold(self, init: B, f: F) -> B where F: FnMut(B, Self::Item) -> B, { self.iter.fold(init, f) } } impl DoubleEndedIterator for InternedSliceIter { fn next_back(&mut self) -> Option { self.iter.next_back() } fn nth_back(&mut self, n: usize) -> Option { self.iter.nth_back(n) } fn rfold(self, init: B, f: F) -> B where F: FnMut(B, Self::Item) -> B, { self.iter.rfold(init, f) } } impl FusedIterator for InternedSliceIter {} impl ExactSizeIterator for InternedSliceIter {} impl IntoIterator for Interned<[T]> { type Item = T; type IntoIter = InternedSliceIter; fn into_iter(self) -> Self::IntoIter { InternedSliceIter { iter: Interned::into_inner(self).iter().cloned(), } } } impl<'a, T: 'static + Send + Sync> IntoIterator for &'a Interned<[T]> { type Item = &'a T; type IntoIter = std::slice::Iter<'a, T>; fn into_iter(self) -> Self::IntoIter { self.inner.iter() } } impl<'a, T: 'static + Send + Sync> IntoIterator for &'a mut Interned<[T]> { type Item = &'a T; type IntoIter = std::slice::Iter<'a, T>; fn into_iter(self) -> Self::IntoIter { self.inner.iter() } } impl FromIterator for Interned<[I]> where [I]: Intern, { fn from_iter>(iter: T) -> Self { Intern::intern_owned(Vec::from_iter(iter)) } } impl FromIterator for Interned where String: FromIterator, { fn from_iter>(iter: T) -> Self { String::from_iter(iter).intern_deref() } } impl FromIterator for Interned where PathBuf: FromIterator, { fn from_iter>(iter: T) -> Self { PathBuf::from_iter(iter).intern_deref() } } impl FromIterator for Interned where OsString: FromIterator, { fn from_iter>(iter: T) -> Self { OsString::from_iter(iter).intern_deref() } } impl From> for clap::builder::Str { fn from(value: Interned) -> Self { Interned::into_inner(value).into() } } impl From> for clap::builder::OsStr { fn from(value: Interned) -> Self { Interned::into_inner(value).into() } } impl From> for clap::builder::StyledStr { fn from(value: Interned) -> Self { Interned::into_inner(value).into() } } impl From> for clap::Id { fn from(value: Interned) -> Self { Interned::into_inner(value).into() } } impl From> for Vec { fn from(value: Interned<[T]>) -> Self { Vec::from(&*value) } } impl From> for Box<[T]> { fn from(value: Interned<[T]>) -> Self { Box::from(&*value) } } impl Default for Interned<[I]> where [I]: Intern, { fn default() -> Self { Intern::intern(&[]) } } impl Default for Interned { fn default() -> Self { <&BitSlice>::default().intern() } } impl Default for Interned where I: Intern, { fn default() -> Self { I::default().intern() } } impl Interned { pub fn cast_unchecked( this: Self, f: impl FnOnce(&'static T) -> &'static U, ) -> Interned { Interned { inner: f(this.inner), } } pub fn try_cast_unchecked( this: Self, f: impl FnOnce(&'static T) -> Result<&'static U, E>, ) -> Result, E> { Ok(Interned { inner: f(this.inner)?, }) } pub fn into_inner(this: Self) -> &'static T { this.inner } pub fn get_ref(this: &Self) -> &&'static T { &this.inner } } impl Clone for Interned { fn clone(&self) -> Self { *self } } impl Copy for Interned where &'static T: Copy {} impl Deref for Interned where &'static T: Borrow, { type Target = T; fn deref(&self) -> &Self::Target { self.inner } } impl PartialEq for Interned { fn eq(&self, other: &Self) -> bool { T::interned_compare_key_ref(self.inner) == T::interned_compare_key_ref(other.inner) } } impl Eq for Interned {} impl PartialOrd for Interned { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for Interned { fn cmp(&self, other: &Self) -> Ordering { T::interned_compare_key_ref(self.inner).cmp(&T::interned_compare_key_ref(other.inner)) } } impl Hash for Interned { fn hash(&self, state: &mut H) { T::interned_compare_key_ref(self.inner).hash(state); } } impl Serialize for Interned { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { T::serialize(self, serializer) } } impl<'de, T: 'static + Send + Sync + Deserialize<'de> + Clone + Intern> Deserialize<'de> for Interned { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { T::deserialize(deserializer).map(Intern::intern_sized) } } impl<'de, T: 'static + Send + Sync + Clone> Deserialize<'de> for Interned<[T]> where [T]: Intern, Vec: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { Vec::::deserialize(deserializer).map(Intern::intern_owned) } } impl<'de> Deserialize<'de> for Interned { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { BitVec::deserialize(deserializer).map(Intern::intern_owned) } } impl Intern for T { fn intern(&self) -> Interned { Self::intern_cow(Cow::Borrowed(self)) } fn intern_owned(this: ::Owned) -> Interned where Self: ToOwned, { Self::intern_cow(Cow::Owned(this)) } fn intern_cow(this: Cow<'_, Self>) -> Interned where Self: ToOwned, { interner::Interner::get().intern_sized(this) } } impl Intern for [T] { fn intern(&self) -> Interned { Self::intern_cow(Cow::Borrowed(self)) } fn intern_owned(this: ::Owned) -> Interned where Self: ToOwned, { Self::intern_cow(Cow::Owned(this)) } fn intern_cow(this: Cow<'_, Self>) -> Interned where Self: ToOwned, { interner::Interner::get().intern_slice(this) } } impl Intern for BitSlice { fn intern(&self) -> Interned { Self::intern_cow(Cow::Borrowed(self)) } fn intern_owned(this: ::Owned) -> Interned where Self: ToOwned, { Self::intern_cow(Cow::Owned(this)) } fn intern_cow(this: Cow<'_, Self>) -> Interned where Self: ToOwned, { interner::Interner::get().intern_bit_slice(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(); thread_local! { static TYPE_ID_MAP_CACHE: TypeIdMap = const { TypeIdMap::new() }; } let map: &RwLock<( DefaultBuildHasher, HashTable<(Self, Self::InputOwned, Self::Output)>, )> = TYPE_ID_MAP_CACHE.with(|cache| { cache.get_or_insert_with(|| { TYPE_ID_MAP.get_or_insert_with(|| Box::leak(Default::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( 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 + Hash + Eq; type InputOwned: 'static + Send + Sync + Borrow; 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); impl MemoizeGeneric for MemoizeGenericWrapper { 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)) } } /// like `once_cell::race::OnceBox` but for `Interned` instead of `Box` pub struct OnceInterned(OnceRef<'static, T>); impl fmt::Debug for OnceInterned { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("OnceInterned").field(&self.get()).finish() } } impl Default for OnceInterned { fn default() -> Self { Self::new() } } impl OnceInterned { pub const fn new() -> Self { Self(OnceRef::new()) } pub fn set(&self, v: Interned) -> Result<(), ()> { self.0.set(v.inner) } pub fn get(&self) -> Option> { self.0.get().map(|inner| Interned { inner }) } pub fn get_or_init Interned>(&self, f: F) -> Interned { Interned { inner: self.0.get_or_init(|| f().inner), } } }