use {
crate::{
construct::{Construct, Decomposition},
reflection::{AlgebraicTypeFormer, Erased, PrecomputedTypeFormer, info},
},
core::mem,
};
#[inline]
pub fn shrink<T: Construct>(t: T) -> Box<dyn Iterator<Item = T>> {
let info = info::<T>();
let AlgebraicTypeFormer {
all_constructors: ref ctors,
eliminator,
..
} = *match info.type_former {
PrecomputedTypeFormer::Algebraic(ref alg) => alg,
PrecomputedTypeFormer::Literal { shrink, .. } => {
let shrink = unsafe {
mem::transmute::<
fn(Erased) -> Box<dyn Iterator<Item = Erased>>,
fn(T) -> Box<dyn Iterator<Item = T>>,
>(shrink)
};
return shrink(t);
}
};
let ctors = ctors.clone();
let eliminator = unsafe { eliminator.unerase::<T>() };
let Decomposition { ctor_idx, fields } = eliminator(t.clone());
#[expect(
clippy::indexing_slicing,
reason = "internal invariants; violation should panic"
)]
let (orig_ctor_fn, orig_ctor_deps) = ctors[ctor_idx.get() - 1].clone();
let orig_ctor_fn = unsafe { orig_ctor_fn.unerase::<T>() };
let nested_selves = t
.visit_deep::<T>()
.skip(1) .collect::<Vec<_>>();
let shrink_fields = fields
.clone()
.shrink()
.map(move |mut fields| orig_ctor_fn(&mut fields));
let try_smaller_ctors = ctors
.into_iter()
.filter(move |&(_, ref deps)| {
let ctor_info = &deps.constructor;
ctor_info
.immediate
.is_subset_of(&orig_ctor_deps.constructor.immediate)
.is_some_and(|strict| {
strict || {
ctor_info.index < orig_ctor_deps.constructor.index
}
})
})
.map(move |(f, _)| {
let f = unsafe { f.unerase::<T>() };
f(&mut fields.clone())
});
Box::new(
nested_selves
.into_iter()
.chain(try_smaller_ctors)
.chain(shrink_fields),
)
}