use std::{
any::{Any, TypeId},
sync::LazyLock,
};
use rustc_hash::FxHashMap;
pub fn any_to_trait<T: ?Sized + 'static>(r: &dyn Any) -> Option<&T> {
TRAIT_CASTERS_MAP
.get(&(r.type_id(), TypeId::of::<T>()))
.and_then(|caster| {
(**caster)
.downcast_ref::<for<'a> fn(&'a (dyn Any + 'static)) -> Option<&'a T>>()
.and_then(|caster| caster(r))
})
}
#[doc(hidden)]
pub struct TraitCasterInfo {
pub from: TypeId,
pub to: TypeId,
pub caster: &'static (dyn Any + Sync + Send),
}
#[cfg(not(target_family = "wasm"))]
pub mod statics {
use super::*;
#[::pliron::linkme::distributed_slice]
pub static TRAIT_CASTERS: [TraitCasterInfo] = [..];
pub fn get_trait_casters() -> impl Iterator<Item = &'static TraitCasterInfo> {
TRAIT_CASTERS.iter()
}
}
#[cfg(target_family = "wasm")]
pub mod statics {
use super::*;
::pliron::inventory::collect!(&'static TraitCasterInfo);
pub fn get_trait_casters() -> impl Iterator<Item = &'static &'static TraitCasterInfo> {
::pliron::inventory::iter::<&'static TraitCasterInfo>()
}
}
pub use statics::*;
#[doc(hidden)]
static TRAIT_CASTERS_MAP: LazyLock<FxHashMap<(TypeId, TypeId), &'static (dyn Any + Sync + Send)>> =
LazyLock::new(|| {
get_trait_casters()
.map(|lazy| ((lazy.from, lazy.to), lazy.caster))
.collect()
});
#[macro_export]
macro_rules! type_to_trait {
($ty_name:ty, $to_trait_name:path) => {
const _: () = {
#[cfg_attr(
not(target_family = "wasm"),
::pliron::linkme::distributed_slice
($crate::utils::trait_cast::TRAIT_CASTERS), linkme(crate = ::pliron::linkme)
)]
static CAST_TO_TRAIT: $crate::utils::trait_cast::TraitCasterInfo =
$crate::utils::trait_cast::TraitCasterInfo {
from: std::any::TypeId::of::<$ty_name>(),
to: std::any::TypeId::of::<dyn $to_trait_name>(),
caster: &(cast_to_trait
as for<'a> fn(
&'a (dyn std::any::Any + 'static),
)
-> Option<&'a (dyn $to_trait_name + 'static)>)
as &'static (dyn std::any::Any + Sync + Send),
};
#[cfg(target_family = "wasm")]
::pliron::inventory::submit! {
&CAST_TO_TRAIT
}
fn cast_to_trait<'a>(
r: &'a (dyn std::any::Any + 'static),
) -> Option<&'a (dyn $to_trait_name + 'static)> {
r.downcast_ref::<$ty_name>()
.map(|s| s as &dyn $to_trait_name)
}
};
};
}