Path: blob/main/crates/bevy_reflect/derive/src/trait_reflection.rs
6599 views
use bevy_macro_utils::fq_std::{FQClone, FQOption, FQResult};1use proc_macro::TokenStream;2use quote::quote;3use syn::{parse::Parse, parse_macro_input, Attribute, ItemTrait, Token};45pub(crate) struct TraitInfo {6item_trait: ItemTrait,7}89impl Parse for TraitInfo {10fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {11let attrs = input.call(Attribute::parse_outer)?;12let lookahead = input.lookahead1();13if lookahead.peek(Token![pub]) || lookahead.peek(Token![trait]) {14let mut item_trait: ItemTrait = input.parse()?;15item_trait.attrs = attrs;16Ok(TraitInfo { item_trait })17} else {18Err(lookahead.error())19}20}21}2223/// A trait attribute macro that allows a reflected type to be downcast to a trait object.24///25/// This generates a struct that takes the form `ReflectMyTrait`. An instance of this struct can then be26/// used to perform the conversion.27pub(crate) fn reflect_trait(_args: &TokenStream, input: TokenStream) -> TokenStream {28let trait_info = parse_macro_input!(input as TraitInfo);29let item_trait = &trait_info.item_trait;30let trait_ident = &item_trait.ident;31let trait_vis = &item_trait.vis;32let reflect_trait_ident = crate::ident::get_reflect_ident(&item_trait.ident.to_string());33let bevy_reflect_path = crate::meta::get_bevy_reflect_path();3435let struct_doc = format!(36" A type generated by the #[reflect_trait] macro for the `{trait_ident}` trait.\n\n This allows casting from `dyn Reflect` to `dyn {trait_ident}`.",37);38let get_doc = format!(39" Downcast a `&dyn Reflect` type to `&dyn {trait_ident}`.\n\n If the type cannot be downcast, `None` is returned.",40);41let get_mut_doc = format!(42" Downcast a `&mut dyn Reflect` type to `&mut dyn {trait_ident}`.\n\n If the type cannot be downcast, `None` is returned.",43);44let get_box_doc = format!(45" Downcast a `Box<dyn Reflect>` type to `Box<dyn {trait_ident}>`.\n\n If the type cannot be downcast, this will return `Err(Box<dyn Reflect>)`.",46);4748TokenStream::from(quote! {49#item_trait5051#[doc = #struct_doc]52#[derive(#FQClone)]53#trait_vis struct #reflect_trait_ident {54get_func: fn(&dyn #bevy_reflect_path::Reflect) -> #FQOption<&dyn #trait_ident>,55get_mut_func: fn(&mut dyn #bevy_reflect_path::Reflect) -> #FQOption<&mut dyn #trait_ident>,56get_boxed_func: fn(#bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>) -> #FQResult<#bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #trait_ident>, #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>>,57}5859impl #reflect_trait_ident {60#[doc = #get_doc]61pub fn get<'a>(&self, reflect_value: &'a dyn #bevy_reflect_path::Reflect) -> #FQOption<&'a dyn #trait_ident> {62(self.get_func)(reflect_value)63}6465#[doc = #get_mut_doc]66pub fn get_mut<'a>(&self, reflect_value: &'a mut dyn #bevy_reflect_path::Reflect) -> #FQOption<&'a mut dyn #trait_ident> {67(self.get_mut_func)(reflect_value)68}6970#[doc = #get_box_doc]71pub fn get_boxed(&self, reflect_value: #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>) -> #FQResult<#bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #trait_ident>, #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>> {72(self.get_boxed_func)(reflect_value)73}74}7576impl<T: #trait_ident + #bevy_reflect_path::Reflect> #bevy_reflect_path::FromType<T> for #reflect_trait_ident {77fn from_type() -> Self {78Self {79get_func: |reflect_value| {80<dyn #bevy_reflect_path::Reflect>::downcast_ref::<T>(reflect_value).map(|value| value as &dyn #trait_ident)81},82get_mut_func: |reflect_value| {83<dyn #bevy_reflect_path::Reflect>::downcast_mut::<T>(reflect_value).map(|value| value as &mut dyn #trait_ident)84},85get_boxed_func: |reflect_value| {86<dyn #bevy_reflect_path::Reflect>::downcast::<T>(reflect_value).map(|value| value as #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #trait_ident>)87}88}89}90}91})92}939495