diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/trait_reflection.rs b/crates/bevy_reflect/bevy_reflect_derive/src/trait_reflection.rs index fe4d4a6bb2..7d16bfb01c 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/trait_reflection.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/trait_reflection.rs @@ -21,6 +21,10 @@ impl Parse for TraitInfo { } } +/// A trait attribute macro that allows a reflected type to be downcast to a trait object. +/// +/// This generates a struct that takes the form `ReflectMyTrait`. An instance of this struct can then be +/// used to perform the conversion. pub(crate) fn reflect_trait(_args: &TokenStream, input: TokenStream) -> TokenStream { let trait_info = parse_macro_input!(input as TraitInfo); let item_trait = &trait_info.item_trait; @@ -28,23 +32,51 @@ pub(crate) fn reflect_trait(_args: &TokenStream, input: TokenStream) -> TokenStr let trait_vis = &item_trait.vis; let reflect_trait_ident = crate::utility::get_reflect_ident(&item_trait.ident.to_string()); let bevy_reflect_path = BevyManifest::default().get_path("bevy_reflect"); + + let struct_doc = format!( + " A type generated by the #[reflect_trait] macro for the `{}` trait.\n\n This allows casting from `dyn Reflect` to `dyn {}`.", + trait_ident, + trait_ident + ); + let get_doc = format!( + " Downcast a `&dyn Reflect` type to `&dyn {}`.\n\n If the type cannot be downcast, `None` is returned.", + trait_ident, + ); + let get_mut_doc = format!( + " Downcast a `&mut dyn Reflect` type to `&mut dyn {}`.\n\n If the type cannot be downcast, `None` is returned.", + trait_ident, + ); + let get_box_doc = format!( + " Downcast a `Box` type to `Box`.\n\n If the type cannot be downcast, this will return `Err(Box)`.", + trait_ident, + ); + TokenStream::from(quote! { #item_trait + #[doc = #struct_doc] #[derive(Clone)] #trait_vis struct #reflect_trait_ident { get_func: fn(&dyn #bevy_reflect_path::Reflect) -> Option<&dyn #trait_ident>, get_mut_func: fn(&mut dyn #bevy_reflect_path::Reflect) -> Option<&mut dyn #trait_ident>, + get_boxed_func: fn(Box) -> Result, Box>, } impl #reflect_trait_ident { + #[doc = #get_doc] pub fn get<'a>(&self, reflect_value: &'a dyn #bevy_reflect_path::Reflect) -> Option<&'a dyn #trait_ident> { (self.get_func)(reflect_value) } + #[doc = #get_mut_doc] pub fn get_mut<'a>(&self, reflect_value: &'a mut dyn #bevy_reflect_path::Reflect) -> Option<&'a mut dyn #trait_ident> { (self.get_mut_func)(reflect_value) } + + #[doc = #get_box_doc] + pub fn get_boxed(&self, reflect_value: Box) -> Result, Box> { + (self.get_boxed_func)(reflect_value) + } } impl #bevy_reflect_path::FromType for #reflect_trait_ident { @@ -55,6 +87,9 @@ pub(crate) fn reflect_trait(_args: &TokenStream, input: TokenStream) -> TokenStr }, get_mut_func: |reflect_value| { reflect_value.downcast_mut::().map(|value| value as &mut dyn #trait_ident) + }, + get_boxed_func: |reflect_value| { + reflect_value.downcast::().map(|value| value as Box) } } }