#![expect(clippy::missing_trait_methods, reason = "left intentionally default")]
use {
crate::{
construct::{
Algebraic, Construct, CtorFn, Decomposition, ElimFn, IntroductionRule, TypeFormer,
push_arbitrary_field, visit_self,
},
reflection::{TermsOfVariousTypes, Type, register, type_of},
scc::StronglyConnectedComponents,
},
core::{
cmp, fmt,
hash::{Hash, Hasher},
iter,
marker::PhantomData,
num::NonZero,
ops::Deref,
},
std::collections::BTreeSet,
};
pub trait Predicate<T>: 'static {
type Error: fmt::Display;
fn check(candidate: &T) -> Result<(), Self::Error>;
}
#[repr(transparent)]
#[expect(clippy::partial_pub_fields, reason = "fine")]
pub struct Sigma<T, P: Predicate<T>> {
_predicate: PhantomData<P>,
pub value: T,
}
impl<T, P: Predicate<T>> Sigma<T, P> {
#[inline]
pub fn new(candidate: T) -> Result<Self, (P::Error, T)> {
match P::check(&candidate) {
Ok(()) => Ok(Self {
_predicate: PhantomData,
value: candidate,
}),
Err(e) => Err((e, candidate)),
}
}
#[inline]
pub unsafe fn new_unchecked(candidate: T) -> Self {
#[cfg(debug_assertions)]
{
match P::check(&candidate) {
Ok(()) => {}
#[expect(clippy::panic, reason = "better than unsafe values")]
Err(e) => panic!("{e}"),
}
}
Self {
_predicate: PhantomData,
value: candidate,
}
}
}
impl<T: Clone, P: Predicate<T>> Clone for Sigma<T, P> {
#[inline(always)]
fn clone(&self) -> Self {
Self {
_predicate: PhantomData,
value: <T as Clone>::clone(&self.value),
}
}
}
impl<T: Copy, P: Predicate<T>> Copy for Sigma<T, P> {}
impl<T, P: Predicate<T>> Deref for Sigma<T, P> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<T: Eq, P: Predicate<T>> Eq for Sigma<T, P> {}
impl<T: Hash, P: Predicate<T>> Hash for Sigma<T, P> {
#[inline(always)]
fn hash<H: Hasher>(&self, state: &mut H) {
<T as Hash>::hash(&self.value, state)
}
}
impl<T: Ord, P: Predicate<T>> Ord for Sigma<T, P> {
#[inline(always)]
fn cmp(&self, other: &Self) -> cmp::Ordering {
<T as Ord>::cmp(&self.value, &other.value)
}
}
impl<T: PartialEq, P: Predicate<T>> PartialEq for Sigma<T, P> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
<T as PartialEq>::eq(&self.value, &other.value)
}
}
impl<T: PartialOrd, P: Predicate<T>> PartialOrd for Sigma<T, P> {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
<T as PartialOrd>::partial_cmp(&self.value, &other.value)
}
}
impl<T: fmt::Debug, P: Predicate<T>> fmt::Debug for Sigma<T, P> {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<T as fmt::Debug>::fmt(&self.value, f)
}
}
impl<T: fmt::Display, P: Predicate<T>> fmt::Display for Sigma<T, P> {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<T as fmt::Display>::fmt(&self.value, f)
}
}
impl<T: Construct, P: Predicate<T>> Construct for Sigma<T, P> {
#[inline]
fn register_all_immediate_dependencies(
visited: &mut BTreeSet<Type>,
sccs: &mut StronglyConnectedComponents,
) {
if !visited.insert(type_of::<Self>()) {
return;
}
let () = register::<T>(visited.clone(), sccs);
}
#[inline]
fn type_former() -> TypeFormer<Self> {
TypeFormer::Algebraic(Algebraic {
elimination_rule: ElimFn::new(|Self { value, .. }| {
let mut fields = TermsOfVariousTypes::new();
let () = fields.push::<T>(value);
Decomposition {
ctor_idx: const { NonZero::new(1).unwrap() },
fields,
}
}),
introduction_rules: vec![IntroductionRule {
arbitrary_fields: |prng, mut sizes| {
let mut fields = TermsOfVariousTypes::new();
push_arbitrary_field::<T>(&mut fields, &mut sizes, prng)?;
Ok(fields)
},
call: CtorFn {
call: |terms| Self::new(terms.must_pop()).ok(),
},
immediate_dependencies: iter::once(type_of::<T>()).collect(),
}],
})
}
#[inline]
fn visit_deep<V: Construct>(&self) -> impl Iterator<Item = V> {
visit_self(self).chain(T::visit_deep(&self.value))
}
}