use {
crate::{
Pbt, fields::Store, hash::map, instantiability, multiset::Multiset,
registration::Registration, shrink,
},
ahash::HashMap,
alloc::{collections::BTreeMap, sync::Arc},
core::{
any::{TypeId, type_name},
cmp,
hash::{Hash, Hasher},
iter,
marker::PhantomData,
mem,
num::NonZero,
ptr,
},
std::{collections::hash_map, sync::RwLock},
wyrand::WyRand,
};
static BUCKET_OPS: RwLock<HashMap<TypeId, BucketOps<Erased>>> = RwLock::new(map());
static NAIVE_VARIANTS: RwLock<BTreeMap<TypeId, Constructors<Erased>>> =
RwLock::new(BTreeMap::new());
#[non_exhaustive]
#[derive(Clone, Copy)]
pub(crate) struct BucketOps<SelfType> {
pub(crate) _phantom: PhantomData<SelfType>,
pub(crate) clone: fn(ptr::NonNull<Erased>) -> ptr::NonNull<Erased>,
pub(crate) clone_vec: fn(&Vec<Erased>) -> Vec<Erased>,
pub(crate) deconstruct: fn(ptr::NonNull<Erased>) -> Parts<Store>,
pub(crate) deserialize: fn(&Vec<serde_json::Value>) -> Option<Vec<Erased>>,
pub(crate) drop: fn(ptr::NonNull<Erased>),
pub(crate) drop_vec: fn(Vec<Erased>),
pub(crate) empty: fn() -> Vec<Erased>,
pub(crate) get: fn(&Vec<Erased>, usize) -> Option<ptr::NonNull<Erased>>,
pub(crate) name: fn() -> &'static str,
pub(crate) pop: fn(&mut Vec<Erased>) -> Option<ptr::NonNull<Erased>>,
pub(crate) push: fn(&mut Vec<Erased>, ptr::NonNull<Erased>),
pub(crate) serialize: fn(Vec<Erased>) -> Vec<serde_json::Value>,
pub(crate) shrink: fn(ptr::NonNull<Erased>) -> Box<dyn Iterator<Item = ptr::NonNull<Erased>>>,
pub(crate) swap_remove: fn(&mut Vec<Erased>, usize) -> ptr::NonNull<Erased>,
}
#[derive(Debug)]
#[non_exhaustive]
pub(crate) enum Constructors<SelfType> {
Algebraic(Arc<[Constructor]>),
Literal {
deserialize: fn(&serde_json::Value) -> Option<SelfType>,
generators: Arc<[fn(&mut WyRand) -> SelfType]>,
serialize: fn(&SelfType) -> serde_json::Value,
shrink: fn(SelfType) -> Box<dyn Iterator<Item = SelfType>>,
},
}
#[derive(Debug)]
#[non_exhaustive]
pub(crate) struct Constructor {
pub(crate) field_types: Multiset<TypeId>,
pub(crate) index: NonZero<usize>,
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug)]
pub(crate) enum Erased {}
#[expect(
clippy::exhaustive_structs,
reason = "`derive(Pbt)` must construct and destructure this across crate boundaries"
)]
pub struct Parts<F> {
pub fields: F,
pub variant_index: Option<NonZero<usize>>,
}
#[derive(Debug)]
#[non_exhaustive]
pub struct Uninstantiable;
#[derive(Debug)]
#[expect(
clippy::exhaustive_structs,
reason = "`derive(Pbt)` must construct this across crate boundaries"
)]
pub struct Variant {
pub field_types: Multiset<TypeId>,
}
#[derive(Debug)]
#[non_exhaustive]
pub enum Variants<SelfType> {
Algebraic(Vec<Variant>),
Literal {
deserialize: fn(&serde_json::Value) -> Option<SelfType>,
generators: Vec<fn(&mut WyRand) -> SelfType>,
serialize: fn(&SelfType) -> serde_json::Value,
shrink: fn(SelfType) -> Box<dyn Iterator<Item = SelfType>>,
},
}
impl<T> BucketOps<T> {
#[inline]
#[must_use]
pub(crate) const fn erase(self) -> BucketOps<Erased> {
unsafe { mem::transmute::<BucketOps<T>, BucketOps<Erased>>(self) }
}
}
impl<T: Pbt> BucketOps<T> {
#[inline]
#[must_use]
pub(crate) const fn derive() -> Self {
Self {
clone: |erased_t: ptr::NonNull<Erased>| {
let t: &T = unsafe { erased_t.cast::<T>().as_ref() };
let cloned: Box<T> = Box::new(t.clone());
ptr::NonNull::from_mut(Box::leak(cloned)).cast()
},
clone_vec: |erased_v: &Vec<Erased>| {
let v: &Vec<T> =
unsafe { ptr::from_ref(erased_v).cast::<Vec<T>>().as_ref_unchecked() };
let cloned: Vec<T> = v.clone();
unsafe { mem::transmute::<Vec<T>, Vec<Erased>>(cloned) }
},
deconstruct: |erased_boxed| {
let boxed: Box<T> = unsafe { Box::from_raw(erased_boxed.cast::<T>().as_ptr()) };
T::deconstruct(*boxed)
},
deserialize: |jsons: &Vec<serde_json::Value>| {
let v: Vec<T> = jsons
.iter()
.map(Parts::deserialize)
.collect::<Option<Vec<T>>>()?;
Some(unsafe { mem::transmute::<Vec<T>, Vec<Erased>>(v) })
},
drop: |erased_boxed: ptr::NonNull<Erased>| {
let boxed: Box<T> = unsafe { Box::from_raw(erased_boxed.cast::<T>().as_ptr()) };
let () = drop(boxed);
},
drop_vec: |erased_v: Vec<Erased>| {
let v: Vec<T> = unsafe { mem::transmute::<Vec<Erased>, Vec<T>>(erased_v) };
let () = drop(v);
},
empty: || {
let v: Vec<T> = Vec::new();
unsafe { mem::transmute::<Vec<T>, Vec<Erased>>(v) }
},
get: |erased_v: &Vec<Erased>, index: usize| {
let v: &Vec<T> =
unsafe { ptr::from_ref(erased_v).cast::<Vec<T>>().as_ref_unchecked() };
Some(ptr::NonNull::from_ref(v.get(index)?).cast::<Erased>())
},
name: type_name::<T>,
pop: |erased_v: &mut Vec<Erased>| {
let v: &mut Vec<T> =
unsafe { ptr::from_mut(erased_v).cast::<Vec<T>>().as_mut_unchecked() };
let boxed = Box::new(v.pop()?);
Some(ptr::NonNull::from_mut(Box::leak(boxed)).cast())
},
push: |erased_v: &mut Vec<Erased>, erased_boxed: ptr::NonNull<Erased>| {
let v: &mut Vec<T> =
unsafe { ptr::from_mut(erased_v).cast::<Vec<T>>().as_mut_unchecked() };
let boxed: Box<T> = unsafe { Box::from_raw(erased_boxed.cast::<T>().as_ptr()) };
let () = v.push(*boxed);
},
serialize: |erased_v: Vec<Erased>| {
let v: Vec<T> = unsafe { mem::transmute::<Vec<Erased>, Vec<T>>(erased_v) };
if let Constructors::Literal { serialize, .. } = constructors_of(TypeId::of::<T>())
{
let serialize_typed = unsafe {
mem::transmute::<
fn(&Erased) -> serde_json::Value,
fn(&T) -> serde_json::Value,
>(serialize)
};
v.iter().map(serialize_typed).collect()
} else {
v.into_iter()
.map(|t: T| t.deconstruct().serialize())
.collect()
}
},
shrink: |erased_boxed: ptr::NonNull<Erased>| {
let unboxed: T = *unsafe { Box::from_raw(erased_boxed.cast::<T>().as_ptr()) };
let iter_over_t = shrink::candidates(unboxed);
let iter_over_erased =
iter_over_t.map(|t: T| ptr::NonNull::from_mut(Box::leak(Box::new(t))).cast());
Box::new(iter_over_erased)
},
swap_remove: |erased_v: &mut Vec<Erased>, i: usize| {
let v: &mut Vec<T> =
unsafe { ptr::from_mut(erased_v).cast::<Vec<T>>().as_mut_unchecked() };
let boxed: Box<T> = Box::new(v.swap_remove(i));
ptr::NonNull::from_mut(Box::leak(boxed)).cast()
},
_phantom: PhantomData,
}
}
}
impl<T: Pbt> Default for BucketOps<T> {
#[inline]
fn default() -> Self {
Self::derive()
}
}
impl Constructor {
#[inline]
pub(crate) fn dedup_fields(&self) -> iter::Copied<hash_map::Keys<'_, TypeId, NonZero<usize>>> {
self.field_types.iter_dedup().copied()
}
#[inline]
pub(crate) fn field_types(&self) -> &Multiset<TypeId> {
&self.field_types
}
}
impl Clone for Constructor {
#[inline]
fn clone(&self) -> Self {
let Self {
ref field_types,
index,
} = *self;
Self {
field_types: field_types.clone(),
index,
}
}
}
impl Eq for Constructor {}
impl Hash for Constructor {
#[inline]
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
let () = <NonZero<usize> as Hash>::hash(&self.index, state);
}
}
impl Ord for Constructor {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
<NonZero<usize> as Ord>::cmp(&self.index, &other.index)
}
}
impl PartialEq for Constructor {
#[inline]
fn eq(&self, other: &Self) -> bool {
<NonZero<usize> as PartialEq>::eq(&self.index, &other.index)
}
}
impl PartialOrd for Constructor {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(<Self as Ord>::cmp(self, other))
}
}
impl<SelfType> Eq for Constructors<SelfType> {}
impl<SelfType> Hash for Constructors<SelfType> {
#[inline]
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
match *self {
Self::Algebraic(ref ctors) => {
let () = 0_usize.hash(state);
let () = ctors.hash(state);
}
Self::Literal { ref generators, .. } => {
let () = 1_usize.hash(state);
let () = generators.hash(state);
}
}
}
}
impl<SelfType> Ord for Constructors<SelfType> {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
match (self, other) {
(
&Self::Literal {
generators: ref lhs,
..
},
&Self::Literal {
generators: ref rhs,
..
},
) => lhs.cmp(rhs),
(&Self::Literal { .. }, &Self::Algebraic(_)) => cmp::Ordering::Less,
(&Self::Algebraic(_), &Self::Literal { .. }) => cmp::Ordering::Greater,
(&Self::Algebraic(ref lhs), &Self::Algebraic(ref rhs)) => lhs.cmp(rhs),
}
}
}
impl<SelfType> PartialEq for Constructors<SelfType> {
#[inline]
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(
&Self::Literal {
generators: ref lhs,
..
},
&Self::Literal {
generators: ref rhs,
..
},
) => lhs.eq(rhs),
(&Self::Algebraic(ref lhs), &Self::Algebraic(ref rhs)) => lhs.eq(rhs),
_ => false,
}
}
}
impl<SelfType> PartialOrd for Constructors<SelfType> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(<Self as Ord>::cmp(self, other))
}
}
impl<SelfType> Clone for Constructors<SelfType> {
#[inline]
fn clone(&self) -> Self {
match *self {
Self::Algebraic(ref constructors) => Self::Algebraic(Arc::clone(constructors)),
Self::Literal {
deserialize,
ref generators,
serialize,
shrink,
} => Self::Literal {
deserialize,
generators: Arc::clone(generators),
serialize,
shrink,
},
}
}
}
impl<SelfType> Constructors<SelfType> {
#[inline]
#[must_use]
pub(crate) fn algebraic(&self) -> &[Constructor] {
match *self {
Self::Algebraic(ref constructors) => constructors,
Self::Literal { .. } => &[],
}
}
#[inline]
#[must_use]
pub(crate) fn is_empty(&self) -> bool {
match *self {
Self::Algebraic(ref constructors) => constructors.is_empty(),
Self::Literal { ref generators, .. } => generators.is_empty(),
}
}
}
impl Parts<Store> {
#[inline]
#[expect(
clippy::expect_used,
clippy::unwrap_in_result,
reason = "Internal invariants: violations should fail loudly."
)]
pub(crate) fn deserialize<T>(json: &serde_json::Value) -> Option<T>
where
T: Pbt,
{
let ty = TypeId::of::<T>();
let ctors = match constructors_of(ty) {
Constructors::Algebraic(ref arc_ctors) => Arc::clone(arc_ctors),
Constructors::Literal { deserialize, .. } => {
let deserialize_typed = unsafe {
mem::transmute::<
fn(&serde_json::Value) -> Option<Erased>,
fn(&serde_json::Value) -> Option<T>,
>(deserialize)
};
return deserialize_typed(json);
}
};
let serde_json::Value::Object(ref map) = *json else {
return None;
};
let variant_index: Option<NonZero<usize>> =
map.get("index").and_then(|json_index: &serde_json::Value| {
let serde_json::Value::String(ref s) = *json_index else {
return None;
};
NonZero::new(s.parse().ok()?)
});
let algebraic_variant_index = variant_index?;
let ctor = ctors
.iter()
.find(|&ctor| ctor.index == algebraic_variant_index)
.expect("INTERNAL ERROR (`pbt`): deserializing non-existent constructor");
let fields = Store::deserialize(map.get("fields")?, &ctor.field_types)?;
Some(T::construct(Self {
fields,
variant_index,
}))
}
#[inline]
#[expect(
clippy::expect_used,
clippy::panic,
reason = "Internal invariants: violations should fail loudly."
)]
pub(crate) fn serialize(self) -> serde_json::Value {
let Self {
mut fields,
variant_index,
} = self;
if let Some(index) = variant_index {
serde_json::Value::Object(
[
("fields".to_owned(), fields.serialize()),
("index".to_owned(), index.to_string().into()),
]
.into_iter()
.collect(),
)
} else {
let (ty, erased) = fields
.pop_erased()
.expect("INTERNAL ERROR (`pbt`): serializing a non-existent literal");
debug_assert!(
fields.pop_erased().is_none(),
"INTERNAL ERROR (`pbt`): serializing a literal that contains multitudes",
);
let ctors = constructors_of(ty);
let Constructors::Literal { serialize, .. } = ctors else {
panic!("INTERNAL ERROR (`pbt`): serializing a literal that think it's algebraic");
};
let serialize_ptr = unsafe {
mem::transmute::<
fn(&Erased) -> serde_json::Value,
fn(ptr::NonNull<Erased>) -> serde_json::Value,
>(serialize)
};
let json = serialize_ptr(erased);
let () = (bucket_ops_of(ty).drop)(erased);
json
}
}
}
impl<SelfType> Variants<SelfType> {
#[inline]
#[must_use]
pub(crate) fn erase(self) -> Constructors<Erased> {
match self {
Self::Algebraic(constructors) => Constructors::Algebraic(
constructors
.into_iter()
.enumerate()
.map(|(zero_indexed, Variant { field_types })| Constructor {
field_types,
#[expect(
clippy::arithmetic_side_effects,
reason = "If an index is `usize::MAX`, there are bigger issues."
)]
index: {
unsafe { NonZero::new_unchecked(zero_indexed + 1) }
},
})
.collect(),
),
Self::Literal {
deserialize,
generators,
serialize,
shrink,
} => {
let erased_generators: Arc<[fn(&mut WyRand) -> Erased]> =
generators
.into_iter()
.map(|f| {
unsafe {
mem::transmute::<
fn(&mut WyRand) -> SelfType,
fn(&mut WyRand) -> Erased,
>(f)
}
})
.collect();
let erased_deserialize = unsafe {
mem::transmute::<
fn(&serde_json::Value) -> Option<SelfType>,
fn(&serde_json::Value) -> Option<Erased>,
>(deserialize)
};
let erased_serialize = unsafe {
mem::transmute::<
fn(&SelfType) -> serde_json::Value,
fn(&Erased) -> serde_json::Value,
>(serialize)
};
let erased_shrink = unsafe {
mem::transmute::<
fn(SelfType) -> Box<dyn Iterator<Item = SelfType>>,
fn(Erased) -> Box<dyn Iterator<Item = Erased>>,
>(shrink)
};
Constructors::Literal {
deserialize: erased_deserialize,
generators: erased_generators,
serialize: erased_serialize,
shrink: erased_shrink,
}
}
}
}
}
#[inline]
#[expect(
clippy::expect_used,
reason = "Internal invariants: violations should fail loudly."
)]
pub(crate) fn bucket_ops_of(ty: TypeId) -> BucketOps<Erased> {
*BUCKET_OPS
.read()
.expect("INTERNAL ERROR (`pbt`): variants lock poisoned")
.get(&ty)
.expect("INTERNAL ERROR (`pbt`): unregistered type during bucket-ops lookup")
}
#[inline]
#[expect(
clippy::expect_used,
reason = "Internal invariants: violations should fail loudly."
)]
pub(crate) fn is_literal(ty: TypeId) -> bool {
matches!(
NAIVE_VARIANTS
.read()
.expect("INTERNAL ERROR (`pbt`): variants lock poisoned")
.get(&ty),
Some(Constructors::Literal { .. })
)
}
#[inline]
#[expect(
clippy::expect_used,
reason = "Internal invariants: violations should fail loudly."
)]
pub(crate) fn constructors_of(ty: TypeId) -> Constructors<Erased> {
static CACHE: RwLock<HashMap<TypeId, Constructors<Erased>>> = RwLock::new(map());
if let Some(cached) = CACHE
.read()
.expect("INTERNAL ERROR (`pbt`): instantiability lock poisoned")
.get(&ty)
{
return cached.clone();
}
let naive = NAIVE_VARIANTS
.read()
.expect("INTERNAL ERROR (`pbt`): variants lock poisoned");
let mut cache = CACHE
.write()
.expect("INTERNAL ERROR (`pbt`): instantiability lock poisoned");
let () = instantiability::update(ty, &naive, &mut cache);
cache
.get(&ty)
.expect("INTERNAL ERROR (`pbt`): unregistered type during instantiability analysis")
.clone()
}
#[inline]
#[expect(
clippy::expect_used,
reason = "Internal invariants: violations should fail loudly."
)]
pub(crate) fn register_globally<T>()
where
T: Pbt,
{
if NAIVE_VARIANTS
.read()
.expect("INTERNAL ERROR (`pbt`): variants lock poisoned")
.contains_key(&TypeId::of::<T>())
{
return;
}
let mut naive_variants = NAIVE_VARIANTS
.write()
.expect("INTERNAL ERROR (`pbt`): variants lock poisoned");
let mut bucket_ops = BUCKET_OPS
.write()
.expect("INTERNAL ERROR (`pbt`): variants lock poisoned");
let mut registration = Registration {
bucket_ops: &mut bucket_ops,
variants: &mut naive_variants,
};
let () = registration.register::<T>();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[expect(
clippy::todo,
reason = "the correct behavior is never to reach these `todo`s"
)]
fn literal_constructors_eq_iff_generators_eq() {
let f: for<'a> fn(&'a mut _) -> _ = |_| todo!();
let g: for<'a> fn(&'a mut _) -> _ = |_| todo!();
let ctors_f = Constructors::Literal {
deserialize: |_| todo!(),
generators: Arc::new([f]),
serialize: |_| todo!(),
shrink: |_| todo!(),
};
let ctors_g = Constructors::Literal {
deserialize: |_| todo!(),
generators: Arc::new([g]),
serialize: |_| todo!(),
shrink: |_| todo!(),
};
assert_eq!(ctors_f, ctors_f);
assert_eq!(ctors_g, ctors_g);
assert_ne!(ctors_f, ctors_g);
assert_ne!(ctors_g, ctors_f);
}
}