-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
bevy_reflect: Reflection-based cloning #13432
base: main
Are you sure you want to change the base?
Changes from all commits
abdc01e
f72ed38
07a7401
4c5e886
47bf66b
f9b37c8
74ee004
ad1146e
0a452ba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ use crate::custom_attributes::CustomAttributes; | |
use crate::derive_data::ReflectTraitToImpl; | ||
use crate::utility; | ||
use crate::utility::terminated_parser; | ||
use bevy_macro_utils::fq_std::{FQAny, FQOption}; | ||
use bevy_macro_utils::fq_std::{FQAny, FQBox, FQClone, FQOption, FQResult}; | ||
use proc_macro2::{Ident, Span}; | ||
use quote::quote_spanned; | ||
use syn::ext::IdentExt; | ||
|
@@ -23,6 +23,7 @@ mod kw { | |
syn::custom_keyword!(Debug); | ||
syn::custom_keyword!(PartialEq); | ||
syn::custom_keyword!(Hash); | ||
syn::custom_keyword!(Clone); | ||
syn::custom_keyword!(no_field_bounds); | ||
} | ||
|
||
|
@@ -181,6 +182,7 @@ impl TypePathAttrs { | |
/// | ||
#[derive(Default, Clone)] | ||
pub(crate) struct ContainerAttributes { | ||
clone: TraitImpl, | ||
debug: TraitImpl, | ||
hash: TraitImpl, | ||
partial_eq: TraitImpl, | ||
|
@@ -239,12 +241,14 @@ impl ContainerAttributes { | |
self.parse_type_path(input, trait_) | ||
} else if lookahead.peek(kw::no_field_bounds) { | ||
self.parse_no_field_bounds(input) | ||
} else if lookahead.peek(kw::Clone) { | ||
self.parse_clone(input) | ||
} else if lookahead.peek(kw::Debug) { | ||
self.parse_debug(input) | ||
} else if lookahead.peek(kw::PartialEq) { | ||
self.parse_partial_eq(input) | ||
} else if lookahead.peek(kw::Hash) { | ||
self.parse_hash(input) | ||
} else if lookahead.peek(kw::PartialEq) { | ||
self.parse_partial_eq(input) | ||
} else if lookahead.peek(Ident::peek_any) { | ||
self.parse_ident(input) | ||
} else { | ||
|
@@ -277,6 +281,26 @@ impl ContainerAttributes { | |
Ok(()) | ||
} | ||
|
||
/// Parse `clone` attribute. | ||
/// | ||
/// Examples: | ||
/// - `#[reflect(Clone)]` | ||
/// - `#[reflect(Clone(custom_clone_fn))]` | ||
fn parse_clone(&mut self, input: ParseStream) -> syn::Result<()> { | ||
let ident = input.parse::<kw::Clone>()?; | ||
|
||
if input.peek(token::Paren) { | ||
let content; | ||
parenthesized!(content in input); | ||
let path = content.parse::<Path>()?; | ||
self.clone.merge(TraitImpl::Custom(path, ident.span))?; | ||
} else { | ||
self.clone = TraitImpl::Implemented(ident.span); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Parse special `Debug` registration. | ||
/// | ||
/// Examples: | ||
|
@@ -513,6 +537,24 @@ impl ContainerAttributes { | |
} | ||
} | ||
|
||
pub fn get_clone_impl(&self, bevy_reflect_path: &Path) -> Option<proc_macro2::TokenStream> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is this used? I couldn't understand this part. Or is this the top-level impl? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's used by |
||
match &self.clone { | ||
&TraitImpl::Implemented(span) => Some(quote_spanned! {span=> | ||
#[inline] | ||
fn reflect_clone(&self) -> #FQResult<#FQBox<dyn #bevy_reflect_path::Reflect>, #bevy_reflect_path::ReflectCloneError> { | ||
#FQResult::Ok(#FQBox::new(#FQClone::clone(self))) | ||
} | ||
}), | ||
&TraitImpl::Custom(ref impl_fn, span) => Some(quote_spanned! {span=> | ||
#[inline] | ||
fn reflect_clone(&self) -> #FQResult<#FQBox<dyn #bevy_reflect_path::Reflect>, #bevy_reflect_path::ReflectCloneError> { | ||
#FQResult::Ok(#FQBox::new(#impl_fn(self))) | ||
} | ||
}), | ||
TraitImpl::NotImplemented => None, | ||
} | ||
} | ||
|
||
pub fn custom_attributes(&self) -> &CustomAttributes { | ||
&self.custom_attributes | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should use
darling
as a helper crate to parse attributes?It seems easier than what you're doing, especially if the attributes become more complex later on
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could utilize something like
darling
in the future (not this PR though). I'm not sure our parsing logic is so complex we really need it, but it's certainly worth considering.