A nice idea that I did not use in the end: // // ///////////////////////////////////////////////////////////////////////////// // // Super Simple Trait Reflection // // ///////////////////////////////////////////////////////////////////////////// use smallvec::{smallvec, SmallVec}; use std::any::TypeId; /// should only be implemented for `dyn MyTrait` pub trait DynTrait: 'static { fn id() -> TypeId { TypeId::of::() } fn name() -> &'static str { std::any::type_name::() } } pub trait Implementor: Sized + 'static { unsafe fn dyn_traits() -> &'static [VTablePtrWithMeta]; } impl Implementor for () { unsafe fn dyn_traits() -> &'static [VTablePtrWithMeta] { &[] } } // ///////////////////////////////////////////////////////////////////////////// // Multi Traits // ///////////////////////////////////////////////////////////////////////////// pub type VTablePtr = *const (); #[repr(C)] pub struct VTable { pub data: *const (), pub ptr: VTablePtr, } #[derive(Debug, Clone, Copy)] pub struct VTablePtrWithMeta { /// The second half of a trait object. pub ptr: VTablePtr, /// type id of dyn MyTrait. pub dyn_trait_id: TypeId, /// type name of the dyn trait: e.g. "dyn vert::trait_reflection::types::Render" pub dyn_trait_name: &'static str, } unsafe impl Sync for VTablePtrWithMeta {} unsafe impl Send for VTablePtrWithMeta {} pub fn vtable_pointer() -> Option { let dyn_trait_id = T::id(); unsafe { C::dyn_traits() .iter() .find(|e| e.dyn_trait_id == dyn_trait_id) .cloned() } } pub trait MultipleReflectedTraits { unsafe fn vtable_pointers() -> SmallVec<[(TypeId, Option); 4]>; } impl DynTrait for () {} impl MultipleReflectedTraits for T { unsafe fn vtable_pointers() -> SmallVec<[(TypeId, Option); 4]> { let dyn_trait_id = Self::id(); let dyn_trait_name = Self::name(); let c_vtable_ptr_with_meta = ::dyn_traits().iter().find_map(|v| { if dyn_trait_id == v.dyn_trait_id { assert_eq!(dyn_trait_name, v.dyn_trait_name); Some(*v) } else { None } }); smallvec![(dyn_trait_id, c_vtable_ptr_with_meta)] } } macro_rules! multi_implements_impl_for_tuples { ($a:ident,$($x:ident),+) => { impl<$a: MultipleReflectedTraits, $($x : MultipleReflectedTraits,)+> MultipleReflectedTraits for ($a, $($x,)+){ unsafe fn vtable_pointers() -> SmallVec<[(TypeId, Option); 4]> { let mut a = $a::vtable_pointers::(); $( let o = $x::vtable_pointers::(); a.extend(o); )+ a } } }; } multi_implements_impl_for_tuples!(A, B); multi_implements_impl_for_tuples!(A, B, C); multi_implements_impl_for_tuples!(A, B, C, D); multi_implements_impl_for_tuples!(A, B, C, D, E); multi_implements_impl_for_tuples!(A, B, C, D, E, F); multi_implements_impl_for_tuples!(A, B, C, D, E, F, G); multi_implements_impl_for_tuples!(A, B, C, D, E, F, G, H); multi_implements_impl_for_tuples!(A, B, C, D, E, F, G, H, I); multi_implements_impl_for_tuples!(A, B, C, D, E, F, G, H, I, J); // ///////////////////////////////////////////////////////////////////////////// // Macros! // ///////////////////////////////////////////////////////////////////////////// /// This macro can be applied to traits or specifying a struct and some traits it implements: /// ### Use on traits: /// ```rust,no_run,ignore /// use vert_core::prelude::*; /// trait Render { } /// reflect!(Render) /// ``` /// which expands to: /// ```rust,no_run,ignore /// trait Render { } /// impl DynTrait for dyn Render {} /// ``` /// /// ### Use on structs, specifying traits: /// ```rust,no_run,ignore /// use vert_core::prelude::*; /// /// trait Render { } /// struct Circle; /// reflect!(Circle: Render) /// ``` /// which expands to: /// ```rust,no_run,ignore /// /// impl Implementor for Circle { /// unsafe fn dyn_traits() -> &'static [VTablePtrWithMeta] { /// const UNINIT: Circle = /// unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; /// const IMPLS: &'static [VTablePtrWithMeta] = &[{ /// const RENDER: &'static dyn Render = &UNINIT as &'static dyn Render; /// if std::mem::size_of::<&dyn Render>() != std::mem::size_of::() * 2 { /// panic!("Error in Implementor::dyn_traits, invalid fat pointer") /// } /// let vtable = &RENDER as *const _ as *const VTable; /// VTablePtrWithMeta { /// ptr: unsafe { (*vtable).ptr }, /// dyn_trait_id: TypeId::of::(), /// dyn_trait_name: std::any::type_name::(), /// } /// }]; /// IMPLS /// } /// } /// ``` #[macro_export] macro_rules! reflect { ($trait:ident) => { impl DynTrait for dyn $trait {} }; ($component:ident : $($trait:ident),* ) => { impl Implementor for $component { unsafe fn dyn_traits() -> &'static [VTablePtrWithMeta]{ use std::sync::OnceLock; static ONCE: OnceLock> = OnceLock::new(); ONCE.get_or_init(||{ #[allow(invalid_value)] let uninit: $component = unsafe { std::mem::MaybeUninit::<$component>::uninit().assume_init() }; let impls = vec![ $( { let trait_obj: &dyn $trait = &uninit as &dyn $trait; // if std::mem::size_of::<&dyn $trait>() != std::mem::size_of::() * 2 { // panic!("Error in Implementor::dyn_traits, invalid fat pointer...") // } let vtable = &trait_obj as *const _ as *const VTable; VTablePtrWithMeta { ptr: unsafe { (*vtable).ptr }, dyn_trait_id: std::any::TypeId::of::(), dyn_trait_name: std::any::type_name::(), } } ),* ]; std::mem::forget(uninit); impls.into() }) } } }; } // // ///////////////////////////////////////////////////////////////////////////// // // Some example structs/traits // // ///////////////////////////////////////////////////////////////////////////// #[cfg(test)] mod tests { use crate::{prelude::*, trait_reflection::vtable_pointer}; #[test] fn test_macros() { struct Circle; struct Rect; struct Point; pub trait Render {} reflect!(Render); pub trait Log {} reflect!(Log); pub trait Update {} reflect!(Update); impl Render for Circle {} impl Render for Rect {} impl Log for Rect {} impl Render for Point {} impl Log for Point {} impl Update for Point {} reflect!(Circle: Render); reflect!(Rect: Render, Log); reflect!(Point: Render, Log, Update); // ///////////////////////////////////////////////////////////////////////////// // Examples of trait implementation. // Xi are traits, the shapes are structs. // // Render Log Update // Circle x // Rect x x // Point x x x // // ///////////////////////////////////////////////////////////////////////////// assert!(vtable_pointer::().is_some()); assert!(vtable_pointer::().is_none()); assert!(vtable_pointer::().is_none()); assert!(vtable_pointer::().is_some()); assert!(vtable_pointer::().is_some()); assert!(vtable_pointer::().is_none()); assert!(vtable_pointer::().is_some()); assert!(vtable_pointer::().is_some()); assert!(vtable_pointer::().is_some()); } }