use std::{
any::{Any, TypeId},
collections::HashMap,
sync::OnceLock,
};
use crate::analysis::cpa::state::AbstractState;
type StrengthenFn = fn(&mut dyn Any, &dyn Any);
pub struct StrengthenFactory(pub fn() -> (TypeId, TypeId, StrengthenFn));
inventory::collect!(StrengthenFactory);
#[macro_export]
macro_rules! register_strengthen {
($Target:ty, $Source:ty, $func:path) => {
const _: () = {
fn wrapper(a: &mut dyn std::any::Any, b: &dyn std::any::Any) {
let a = a.downcast_mut::<$Target>();
let b = b.downcast_ref::<$Source>();
if let Some(a) = a
&& let Some(b) = b
{
($func)(a, b);
}
}
fn factory() -> (
std::any::TypeId,
std::any::TypeId,
fn(&mut dyn std::any::Any, &dyn std::any::Any),
) {
(
std::any::TypeId::of::<$Target>(),
std::any::TypeId::of::<$Source>(),
wrapper,
)
}
inventory::submit! {
$crate::analysis::compound::strengthen::StrengthenFactory(factory)
}
};
};
}
static STRENGTHEN_REGISTRY: OnceLock<HashMap<(TypeId, TypeId), StrengthenFn>> = OnceLock::new();
fn build_strengthen_registry() -> HashMap<(TypeId, TypeId), StrengthenFn> {
let mut m = HashMap::new();
for f in inventory::iter::<StrengthenFactory> {
let (a, b, fun) = (f.0)();
m.insert((a, b), fun);
}
m
}
fn register_lookup(src: TypeId, other: TypeId) -> Option<StrengthenFn> {
let map = STRENGTHEN_REGISTRY.get_or_init(build_strengthen_registry);
map.get(&(src, other)).copied()
}
pub trait ComponentStrengthen: 'static {
fn try_strengthen(&mut self, other: &dyn Any)
where
Self: Sized,
{
if let Some(func) = register_lookup(TypeId::of::<Self>(), other.type_id()) {
func(self as &mut dyn Any, other)
}
}
}
impl<T: AbstractState> ComponentStrengthen for T where T: 'static {}