Skip to content

Commit be18a8f

Browse files
committed
Replace custom_where attribute with where
1 parent 76cb513 commit be18a8f

File tree

7 files changed

+63
-56
lines changed

7 files changed

+63
-56
lines changed

crates/bevy_asset/src/handle.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ impl std::fmt::Debug for StrongHandle {
122122
/// [`Handle::Strong`] also provides access to useful [`Asset`] metadata, such as the [`AssetPath`] (if it exists).
123123
#[derive(Component, Reflect)]
124124
#[reflect(Component)]
125-
#[reflect(custom_where(A: Asset))]
125+
#[reflect(where A: Asset)]
126126
pub enum Handle<A: Asset> {
127127
/// A "strong" reference to a live (or loading) [`Asset`]. If a [`Handle`] is [`Handle::Strong`], the [`Asset`] will be kept
128128
/// alive until the [`Handle`] is dropped. Strong handles also provide access to additional asset metadata.

crates/bevy_asset/src/id.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use thiserror::Error;
1717
///
1818
/// For an "untyped" / "generic-less" id, see [`UntypedAssetId`].
1919
#[derive(Reflect)]
20-
#[reflect(custom_where(A: Asset))]
20+
#[reflect(where A: Asset)]
2121
pub enum AssetId<A: Asset> {
2222
/// A small / efficient runtime identifier that can be used to efficiently look up an asset stored in [`Assets`]. This is
2323
/// the "default" identifier used for assets. The alternative(s) (ex: [`AssetId::Uuid`]) will only be used if assets are

crates/bevy_reflect/bevy_reflect_derive/src/container_attributes.rs

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
88
use crate::utility;
99
use bevy_macro_utils::fq_std::{FQAny, FQOption};
10-
use proc_macro2::{Ident, Span};
10+
use proc_macro2::{Ident, Span, TokenTree};
1111
use quote::quote_spanned;
1212
use syn::parse::{Parse, ParseStream};
1313
use syn::punctuated::Punctuated;
1414
use syn::spanned::Spanned;
1515
use syn::token::Comma;
16-
use syn::{Expr, LitBool, Meta, Path, Token, WherePredicate};
16+
use syn::{Expr, LitBool, Meta, MetaList, Path, WhereClause};
1717

1818
// The "special" trait idents that are used internally for reflection.
1919
// Received via attributes like `#[reflect(PartialEq, Hash, ...)]`
@@ -31,9 +31,6 @@ const FROM_REFLECT_ATTR: &str = "from_reflect";
3131
// Attributes for `TypePath` implementation
3232
const TYPE_PATH_ATTR: &str = "type_path";
3333

34-
// Attributes for `Reflect` implementation
35-
const CUSTOM_WHERE_ATTR: &str = "custom_where";
36-
3734
// The error message to show when a trait/type is specified multiple times
3835
const CONFLICTING_TYPE_DATA_MESSAGE: &str = "conflicting type data registration";
3936

@@ -214,12 +211,29 @@ pub(crate) struct ReflectTraits {
214211
partial_eq: TraitImpl,
215212
from_reflect_attrs: FromReflectAttrs,
216213
type_path_attrs: TypePathAttrs,
217-
custom_where: Option<Punctuated<WherePredicate, Token![,]>>,
214+
custom_where: Option<WhereClause>,
218215
idents: Vec<Ident>,
219216
}
220217

221218
impl ReflectTraits {
222-
pub fn from_metas(
219+
pub fn from_meta_list(
220+
meta: &MetaList,
221+
is_from_reflect_derive: bool,
222+
) -> Result<Self, syn::Error> {
223+
match meta.tokens.clone().into_iter().next() {
224+
// Handles `#[reflect(where T: Trait, U::Assoc: Trait)]`
225+
Some(TokenTree::Ident(ident)) if ident == "where" => Ok(Self {
226+
custom_where: Some(meta.parse_args::<WhereClause>()?),
227+
..Self::default()
228+
}),
229+
_ => Self::from_metas(
230+
meta.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)?,
231+
is_from_reflect_derive,
232+
),
233+
}
234+
}
235+
236+
fn from_metas(
223237
metas: Punctuated<Meta, Comma>,
224238
is_from_reflect_derive: bool,
225239
) -> Result<Self, syn::Error> {
@@ -257,12 +271,6 @@ impl ReflectTraits {
257271
}
258272
}
259273
}
260-
// Handles `#[reflect(custom_where(T: Trait, U::Assoc: Trait))]`
261-
Meta::List(list) if list.path.is_ident(CUSTOM_WHERE_ATTR) => {
262-
let predicate: Punctuated<WherePredicate, Token![,]> =
263-
list.parse_args_with(Punctuated::parse_terminated)?;
264-
traits.merge_custom_where(Some(predicate));
265-
}
266274
// Handles `#[reflect( Debug(custom_debug_fn) )]`
267275
Meta::List(list) if list.path.is_ident(DEBUG_ATTR) => {
268276
let ident = list.path.get_ident().unwrap();
@@ -290,7 +298,9 @@ impl ReflectTraits {
290298
Meta::List(list) => {
291299
return Err(syn::Error::new_spanned(
292300
list,
293-
format!("expected one of [{DEBUG_ATTR:?}, {PARTIAL_EQ_ATTR:?}, {HASH_ATTR:?}, {CUSTOM_WHERE_ATTR:?}]")
301+
format!(
302+
"expected one of [{DEBUG_ATTR:?}, {PARTIAL_EQ_ATTR:?}, {HASH_ATTR:?}]"
303+
),
294304
));
295305
}
296306
Meta::NameValue(pair) => {
@@ -408,7 +418,7 @@ impl ReflectTraits {
408418
}
409419
}
410420

411-
pub fn custom_where(&self) -> Option<&Punctuated<WherePredicate, Token![,]>> {
421+
pub fn custom_where(&self) -> Option<&WhereClause> {
412422
self.custom_where.as_ref()
413423
}
414424

@@ -430,10 +440,10 @@ impl ReflectTraits {
430440
Ok(())
431441
}
432442

433-
fn merge_custom_where(&mut self, other: Option<Punctuated<WherePredicate, Token![,]>>) {
443+
fn merge_custom_where(&mut self, other: Option<WhereClause>) {
434444
match (&mut self.custom_where, other) {
435445
(Some(this), Some(other)) => {
436-
this.extend(other);
446+
this.predicates.extend(other.predicates);
437447
}
438448
(None, Some(other)) => {
439449
self.custom_where = Some(other);

crates/bevy_reflect/bevy_reflect_derive/src/derive_data.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,8 @@ impl<'a> ReflectDerive<'a> {
167167
}
168168

169169
reflect_mode = Some(ReflectMode::Normal);
170-
let new_traits = ReflectTraits::from_metas(
171-
meta_list.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)?,
172-
is_from_reflect_derive,
173-
)?;
170+
let new_traits =
171+
ReflectTraits::from_meta_list(meta_list, is_from_reflect_derive)?;
174172
traits.merge(new_traits)?;
175173
}
176174
Meta::List(meta_list) if meta_list.path.is_ident(REFLECT_VALUE_ATTRIBUTE_NAME) => {
@@ -182,10 +180,8 @@ impl<'a> ReflectDerive<'a> {
182180
}
183181

184182
reflect_mode = Some(ReflectMode::Value);
185-
let new_traits = ReflectTraits::from_metas(
186-
meta_list.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)?,
187-
is_from_reflect_derive,
188-
)?;
183+
let new_traits =
184+
ReflectTraits::from_meta_list(meta_list, is_from_reflect_derive)?;
189185
traits.merge(new_traits)?;
190186
}
191187
Meta::Path(path) if path.is_ident(REFLECT_VALUE_ATTRIBUTE_NAME) => {

crates/bevy_reflect/bevy_reflect_derive/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ pub(crate) static TYPE_NAME_ATTRIBUTE_NAME: &str = "type_name";
131131
/// This is useful for when a type can't or shouldn't implement `TypePath`,
132132
/// or if a manual implementation is desired.
133133
///
134-
/// ## `#[reflect(custom_where(T: Trait, U::Assoc: Trait, ...))]`
134+
/// ## `#[reflect(where T: Trait, U::Assoc: Trait, ...)]`
135135
///
136136
/// By default, the derive macro will automatically add certain trait bounds to all generic type parameters
137137
/// in order to make them compatible with reflection without the user needing to add them manually.
@@ -147,7 +147,7 @@ pub(crate) static TYPE_NAME_ATTRIBUTE_NAME: &str = "type_name";
147147
/// in general.
148148
///
149149
/// This means that if you want to opt-out of the default bounds for _all_ type parameters,
150-
/// you can add `#[reflect(custom_where())]` to the container item to indicate
150+
/// you can add `#[reflect(where)]` to the container item to indicate
151151
/// that an empty `where` clause should be used.
152152
///
153153
/// ### Example
@@ -158,7 +158,7 @@ pub(crate) static TYPE_NAME_ATTRIBUTE_NAME: &str = "type_name";
158158
/// }
159159
///
160160
/// #[derive(Reflect)]
161-
/// #[reflect(custom_where(T::Assoc: FromReflect))]
161+
/// #[reflect(where T::Assoc: FromReflect)]
162162
/// struct Foo<T: Trait> where T::Assoc: Default {
163163
/// value: T::Assoc,
164164
/// }
@@ -192,7 +192,7 @@ pub(crate) static TYPE_NAME_ATTRIBUTE_NAME: &str = "type_name";
192192
/// or allowing the use of types that do not implement `Reflect` within the container.
193193
///
194194
/// If the field contains a generic type parameter, you will likely need to add a
195-
/// [`#[reflect(custom_where())]`](#reflectcustom_wheret-trait-uassoc-trait-)
195+
/// [`#[reflect(where)]`](#reflectwheret-trait-uassoc-trait-)
196196
/// attribute to the container in order to avoid the default bounds being applied to the type parameter.
197197
///
198198
/// ## `#[reflect(skip_serializing)]`

crates/bevy_reflect/bevy_reflect_derive/src/utility.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ impl<'a, 'b> WhereClauseOptions<'a, 'b> {
112112
///
113113
/// This will only add bounds for generic type parameters.
114114
///
115-
/// If the container has a `#[reflect(custom_where(...))]` attribute,
115+
/// If the container has a `#[reflect(where)]` attribute,
116116
/// this method will extend the type parameters with the _required_ bounds.
117117
/// If the attribute is not present, it will extend the type parameters with the _additional_ bounds.
118118
///
@@ -138,7 +138,7 @@ impl<'a, 'b> WhereClauseOptions<'a, 'b> {
138138
///
139139
/// It has type parameters `T` and `U`.
140140
///
141-
/// Since there is no `#[reflect(custom_where(...))]` attribute, this method will extend the type parameters
141+
/// Since there is no `#[reflect(where)]` attribute, this method will extend the type parameters
142142
/// with the additional bounds:
143143
///
144144
/// ```ignore (bevy_reflect is not accessible from this crate)
@@ -150,15 +150,15 @@ impl<'a, 'b> WhereClauseOptions<'a, 'b> {
150150
/// If we had this struct:
151151
/// ```ignore (bevy_reflect is not accessible from this crate)
152152
/// #[derive(Reflect)]
153-
/// #[reflect(custom_where(T: FromReflect + Default))]
153+
/// #[reflect(where T: FromReflect + Default)]
154154
/// struct Foo<T, U> {
155155
/// a: T,
156156
/// #[reflect(ignore)]
157157
/// b: U
158158
/// }
159159
/// ```
160160
///
161-
/// Since there is a `#[reflect(custom_where(...))]` attribute, this method will extend the type parameters
161+
/// Since there is a `#[reflect(where)]` attribute, this method will extend the type parameters
162162
/// with _just_ the required bounds along with the predicates specified in the attribute:
163163
///
164164
/// ```ignore (bevy_reflect is not accessible from this crate)
@@ -181,7 +181,11 @@ impl<'a, 'b> WhereClauseOptions<'a, 'b> {
181181

182182
// Add additional reflection trait bounds
183183
let types = self.type_param_idents();
184-
let custom_where = self.meta.traits().custom_where();
184+
let custom_where = self
185+
.meta
186+
.traits()
187+
.custom_where()
188+
.map(|clause| &clause.predicates);
185189
let trait_bounds = self.trait_bounds();
186190

187191
generic_where_clause.extend(quote! {

crates/bevy_reflect/src/lib.rs

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,7 @@ mod tests {
541541
ser::{to_string_pretty, PrettyConfig},
542542
Deserializer,
543543
};
544+
use static_assertions::{assert_impl_all, assert_not_impl_all};
544545
use std::{
545546
any::TypeId,
546547
borrow::Cow,
@@ -1866,47 +1867,46 @@ bevy_reflect::tests::Test {
18661867
#[test]
18671868
fn should_allow_custom_where() {
18681869
#[derive(Reflect)]
1869-
#[reflect(custom_where(T: Default))]
1870+
#[reflect(where T: Default)]
18701871
struct Foo<T>(String, #[reflect(ignore)] PhantomData<T>);
18711872

18721873
#[derive(Default, TypePath)]
18731874
struct Bar;
18741875

1875-
#[derive(Reflect)]
1876-
struct Baz {
1877-
a: Foo<Bar>,
1878-
b: Foo<usize>,
1879-
}
1876+
#[derive(TypePath)]
1877+
struct Baz;
1878+
1879+
assert_impl_all!(Foo<Bar>: Reflect);
1880+
assert_not_impl_all!(Foo<Baz>: Reflect);
18801881
}
18811882

18821883
#[test]
18831884
fn should_allow_empty_custom_where() {
18841885
#[derive(Reflect)]
1885-
#[reflect(custom_where())]
1886+
#[reflect(where)]
18861887
struct Foo<T>(String, #[reflect(ignore)] PhantomData<T>);
18871888

18881889
#[derive(TypePath)]
18891890
struct Bar;
18901891

1891-
#[derive(Reflect)]
1892-
struct Baz {
1893-
a: Foo<Bar>,
1894-
b: Foo<usize>,
1895-
}
1892+
assert_impl_all!(Foo<Bar>: Reflect);
18961893
}
18971894

18981895
#[test]
18991896
fn should_allow_multiple_custom_where() {
19001897
#[derive(Reflect)]
1901-
#[reflect(custom_where(T: Default + FromReflect))]
1902-
#[reflect(custom_where(U: std::ops::Add<T> + FromReflect))]
1898+
#[reflect(where T: Default + FromReflect)]
1899+
#[reflect(where U: std::ops::Add<T> + FromReflect)]
19031900
struct Foo<T, U>(T, U);
19041901

19051902
#[derive(Reflect)]
19061903
struct Baz {
19071904
a: Foo<i32, i32>,
19081905
b: Foo<u32, u32>,
19091906
}
1907+
1908+
assert_impl_all!(Foo<i32, i32>: Reflect);
1909+
assert_not_impl_all!(Foo<i32, usize>: Reflect);
19101910
}
19111911

19121912
#[test]
@@ -1917,7 +1917,7 @@ bevy_reflect::tests::Test {
19171917

19181918
// We don't need `T` to be `Reflect` since we only care about `T::Assoc`
19191919
#[derive(Reflect)]
1920-
#[reflect(custom_where(T::Assoc: FromReflect))]
1920+
#[reflect(where T::Assoc: FromReflect)]
19211921
struct Foo<T: Trait>(T::Assoc);
19221922

19231923
#[derive(TypePath)]
@@ -1927,10 +1927,7 @@ bevy_reflect::tests::Test {
19271927
type Assoc = usize;
19281928
}
19291929

1930-
#[derive(Reflect)]
1931-
struct Baz {
1932-
a: Foo<Bar>,
1933-
}
1930+
assert_impl_all!(Foo<Bar>: Reflect);
19341931
}
19351932

19361933
#[test]
@@ -1969,7 +1966,7 @@ bevy_reflect::tests::Test {
19691966
fn can_opt_out_type_path() {
19701967
#[derive(Reflect)]
19711968
#[reflect(type_path = false)]
1972-
#[reflect(custom_where())]
1969+
#[reflect(where)]
19731970
struct Foo<T> {
19741971
#[reflect(ignore)]
19751972
_marker: PhantomData<T>,

0 commit comments

Comments
 (0)