-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
bevy_reflect: Reflection-based cloning #13432
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
Changes from all commits
9ce39b6
5856176
ef7e8f6
512c4ee
d021b60
f7616a9
a49e03d
bc00927
fb7c647
b3b5147
1a2f5b3
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::{ | |
attribute_parser::terminated_parser, custom_attributes::CustomAttributes, | ||
derive_data::ReflectTraitToImpl, | ||
}; | ||
use bevy_macro_utils::fq_std::{FQAny, FQOption}; | ||
use bevy_macro_utils::fq_std::{FQAny, FQClone, FQOption, FQResult}; | ||
use proc_macro2::{Ident, Span}; | ||
use quote::quote_spanned; | ||
use syn::{ | ||
|
@@ -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); | ||
syn::custom_keyword!(opaque); | ||
} | ||
|
@@ -175,6 +176,7 @@ impl TypePathAttrs { | |
/// > __Note:__ Registering a custom function only works for special traits. | ||
#[derive(Default, Clone)] | ||
pub(crate) struct ContainerAttributes { | ||
clone: TraitImpl, | ||
debug: TraitImpl, | ||
hash: TraitImpl, | ||
partial_eq: TraitImpl, | ||
|
@@ -236,12 +238,14 @@ impl ContainerAttributes { | |
self.parse_opaque(input) | ||
} 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 { | ||
|
@@ -274,6 +278,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: | ||
|
@@ -523,6 +547,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<#bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>, #bevy_reflect_path::ReflectCloneError> { | ||
#FQResult::Ok(#bevy_reflect_path::__macro_exports::alloc_utils::Box::new(#FQClone::clone(self))) | ||
} | ||
}), | ||
&TraitImpl::Custom(ref impl_fn, span) => Some(quote_spanned! {span=> | ||
#[inline] | ||
fn reflect_clone(&self) -> #FQResult<#bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>, #bevy_reflect_path::ReflectCloneError> { | ||
#FQResult::Ok(#bevy_reflect_path::__macro_exports::alloc_utils::Box::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.