Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - bevy_reflect: Added get_boxed method to reflect_trait #4120

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 35 additions & 0 deletions crates/bevy_reflect/bevy_reflect_derive/src/trait_reflection.rs
Expand Up @@ -21,30 +21,62 @@ 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;
let trait_ident = &item_trait.ident;
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<dyn Reflect>` type to `Box<dyn {}>`.\n\n If the type cannot be downcast, this will return `Err(Box<dyn Reflect>)`.",
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<dyn #bevy_reflect_path::Reflect>) -> Result<Box<dyn #trait_ident>, Box<dyn #bevy_reflect_path::Reflect>>,
}

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<dyn #bevy_reflect_path::Reflect>) -> Result<Box<dyn #trait_ident>, Box<dyn #bevy_reflect_path::Reflect>> {
(self.get_boxed_func)(reflect_value)
}
}

impl<T: #trait_ident + #bevy_reflect_path::Reflect> #bevy_reflect_path::FromType<T> for #reflect_trait_ident {
Expand All @@ -55,6 +87,9 @@ pub(crate) fn reflect_trait(_args: &TokenStream, input: TokenStream) -> TokenStr
},
get_mut_func: |reflect_value| {
reflect_value.downcast_mut::<T>().map(|value| value as &mut dyn #trait_ident)
},
get_boxed_func: |reflect_value| {
reflect_value.downcast::<T>().map(|value| value as Box<dyn #trait_ident>)
}
}
}
Expand Down