Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/derive/src/field_attributes.rs
6849 views
1
//! Contains code related to field attributes for reflected types.
2
//!
3
//! A field attribute is an attribute which applies to particular field or variant
4
//! as opposed to an entire struct or enum. An example of such an attribute is
5
//! the derive helper attribute for `Reflect`, which looks like: `#[reflect(ignore)]`.
6
7
use crate::{custom_attributes::CustomAttributes, REFLECT_ATTRIBUTE_NAME};
8
use bevy_macro_utils::terminated_parser;
9
use quote::ToTokens;
10
use syn::{parse::ParseStream, Attribute, LitStr, Meta, Token, Type};
11
12
mod kw {
13
syn::custom_keyword!(ignore);
14
syn::custom_keyword!(skip_serializing);
15
syn::custom_keyword!(clone);
16
syn::custom_keyword!(default);
17
syn::custom_keyword!(remote);
18
}
19
20
pub(crate) const IGNORE_SERIALIZATION_ATTR: &str = "skip_serializing";
21
pub(crate) const IGNORE_ALL_ATTR: &str = "ignore";
22
23
pub(crate) const DEFAULT_ATTR: &str = "default";
24
pub(crate) const CLONE_ATTR: &str = "clone";
25
26
/// Stores data about if the field should be visible via the Reflect and serialization interfaces
27
///
28
/// Note the relationship between serialization and reflection is such that a member must be reflected in order to be serialized.
29
/// In boolean logic this is described as: `is_serialized -> is_reflected`, this means we can reflect something without serializing it but not the other way round.
30
/// The `is_reflected` predicate is provided as `self.is_active()`
31
#[derive(Default, Clone, Copy, PartialEq, Eq)]
32
pub(crate) enum ReflectIgnoreBehavior {
33
/// Don't ignore, appear to all systems
34
#[default]
35
None,
36
/// Ignore when serializing but not when reflecting
37
IgnoreSerialization,
38
/// Ignore both when serializing and reflecting
39
IgnoreAlways,
40
}
41
42
impl ReflectIgnoreBehavior {
43
/// Returns `true` if the ignoring behavior implies member is included in the reflection API, and false otherwise.
44
pub fn is_active(self) -> bool {
45
match self {
46
ReflectIgnoreBehavior::None | ReflectIgnoreBehavior::IgnoreSerialization => true,
47
ReflectIgnoreBehavior::IgnoreAlways => false,
48
}
49
}
50
51
/// The exact logical opposite of `self.is_active()` returns true iff this member is not part of the reflection API whatsoever (neither serialized nor reflected)
52
pub fn is_ignored(self) -> bool {
53
!self.is_active()
54
}
55
}
56
57
#[derive(Default, Clone)]
58
pub(crate) enum CloneBehavior {
59
#[default]
60
Default,
61
Trait,
62
Func(syn::ExprPath),
63
}
64
65
/// Controls how the default value is determined for a field.
66
#[derive(Default, Clone)]
67
pub(crate) enum DefaultBehavior {
68
/// Field is required.
69
#[default]
70
Required,
71
/// Field can be defaulted using `Default::default()`.
72
Default,
73
/// Field can be created using the given function name.
74
///
75
/// This assumes the function is in scope, is callable with zero arguments,
76
/// and returns the expected type.
77
Func(syn::ExprPath),
78
}
79
80
/// A container for attributes defined on a reflected type's field.
81
#[derive(Default, Clone)]
82
pub(crate) struct FieldAttributes {
83
/// Determines how this field should be ignored if at all.
84
pub ignore: ReflectIgnoreBehavior,
85
/// Sets the clone behavior of this field.
86
pub clone: CloneBehavior,
87
/// Sets the default behavior of this field.
88
pub default: DefaultBehavior,
89
/// Custom attributes created via `#[reflect(@...)]`.
90
pub custom_attributes: CustomAttributes,
91
/// For defining the remote wrapper type that should be used in place of the field for reflection logic.
92
pub remote: Option<Type>,
93
}
94
95
impl FieldAttributes {
96
/// Parse all field attributes marked "reflect" (such as `#[reflect(ignore)]`).
97
pub fn parse_attributes(attrs: &[Attribute]) -> syn::Result<Self> {
98
let mut args = FieldAttributes::default();
99
100
attrs
101
.iter()
102
.filter_map(|attr| {
103
if !attr.path().is_ident(REFLECT_ATTRIBUTE_NAME) {
104
// Not a reflect attribute -> skip
105
return None;
106
}
107
108
let Meta::List(meta) = &attr.meta else {
109
return Some(syn::Error::new_spanned(attr, "expected meta list"));
110
};
111
112
// Parse all attributes inside the list, collecting any errors
113
meta.parse_args_with(terminated_parser(Token![,], |stream| {
114
args.parse_field_attribute(stream)
115
}))
116
.err()
117
})
118
.reduce(|mut acc, err| {
119
acc.combine(err);
120
acc
121
})
122
.map_or(Ok(args), Err)
123
}
124
125
/// Parses a single field attribute.
126
fn parse_field_attribute(&mut self, input: ParseStream) -> syn::Result<()> {
127
let lookahead = input.lookahead1();
128
if lookahead.peek(Token![@]) {
129
self.parse_custom_attribute(input)
130
} else if lookahead.peek(kw::ignore) {
131
self.parse_ignore(input)
132
} else if lookahead.peek(kw::skip_serializing) {
133
self.parse_skip_serializing(input)
134
} else if lookahead.peek(kw::clone) {
135
self.parse_clone(input)
136
} else if lookahead.peek(kw::default) {
137
self.parse_default(input)
138
} else if lookahead.peek(kw::remote) {
139
self.parse_remote(input)
140
} else {
141
Err(lookahead.error())
142
}
143
}
144
145
/// Parse `ignore` attribute.
146
///
147
/// Examples:
148
/// - `#[reflect(ignore)]`
149
fn parse_ignore(&mut self, input: ParseStream) -> syn::Result<()> {
150
if self.ignore != ReflectIgnoreBehavior::None {
151
return Err(input.error(format!(
152
"only one of {:?} is allowed",
153
[IGNORE_ALL_ATTR, IGNORE_SERIALIZATION_ATTR]
154
)));
155
}
156
157
input.parse::<kw::ignore>()?;
158
self.ignore = ReflectIgnoreBehavior::IgnoreAlways;
159
Ok(())
160
}
161
162
/// Parse `skip_serializing` attribute.
163
///
164
/// Examples:
165
/// - `#[reflect(skip_serializing)]`
166
fn parse_skip_serializing(&mut self, input: ParseStream) -> syn::Result<()> {
167
if self.ignore != ReflectIgnoreBehavior::None {
168
return Err(input.error(format!(
169
"only one of {:?} is allowed",
170
[IGNORE_ALL_ATTR, IGNORE_SERIALIZATION_ATTR]
171
)));
172
}
173
174
input.parse::<kw::skip_serializing>()?;
175
self.ignore = ReflectIgnoreBehavior::IgnoreSerialization;
176
Ok(())
177
}
178
179
/// Parse `clone` attribute.
180
///
181
/// Examples:
182
/// - `#[reflect(clone)]`
183
/// - `#[reflect(clone = "path::to::func")]`
184
fn parse_clone(&mut self, input: ParseStream) -> syn::Result<()> {
185
if !matches!(self.clone, CloneBehavior::Default) {
186
return Err(input.error(format!("only one of {:?} is allowed", [CLONE_ATTR])));
187
}
188
189
input.parse::<kw::clone>()?;
190
191
if input.peek(Token![=]) {
192
input.parse::<Token![=]>()?;
193
194
let lit = input.parse::<LitStr>()?;
195
self.clone = CloneBehavior::Func(lit.parse()?);
196
} else {
197
self.clone = CloneBehavior::Trait;
198
}
199
200
Ok(())
201
}
202
203
/// Parse `default` attribute.
204
///
205
/// Examples:
206
/// - `#[reflect(default)]`
207
/// - `#[reflect(default = "path::to::func")]`
208
fn parse_default(&mut self, input: ParseStream) -> syn::Result<()> {
209
if !matches!(self.default, DefaultBehavior::Required) {
210
return Err(input.error(format!("only one of {:?} is allowed", [DEFAULT_ATTR])));
211
}
212
213
input.parse::<kw::default>()?;
214
215
if input.peek(Token![=]) {
216
input.parse::<Token![=]>()?;
217
218
let lit = input.parse::<LitStr>()?;
219
self.default = DefaultBehavior::Func(lit.parse()?);
220
} else {
221
self.default = DefaultBehavior::Default;
222
}
223
224
Ok(())
225
}
226
227
/// Parse `@` (custom attribute) attribute.
228
///
229
/// Examples:
230
/// - `#[reflect(@(foo = "bar"))]`
231
/// - `#[reflect(@(min = 0.0, max = 1.0))]`
232
fn parse_custom_attribute(&mut self, input: ParseStream) -> syn::Result<()> {
233
self.custom_attributes.parse_custom_attribute(input)
234
}
235
236
/// Parse `remote` attribute.
237
///
238
/// Examples:
239
/// - `#[reflect(remote = path::to::RemoteType)]`
240
fn parse_remote(&mut self, input: ParseStream) -> syn::Result<()> {
241
if let Some(remote) = self.remote.as_ref() {
242
return Err(input.error(format!(
243
"remote type already specified as {}",
244
remote.to_token_stream()
245
)));
246
}
247
248
input.parse::<kw::remote>()?;
249
input.parse::<Token![=]>()?;
250
251
self.remote = Some(input.parse()?);
252
253
Ok(())
254
}
255
256
/// Returns `Some(true)` if the field has a generic remote type.
257
///
258
/// If the remote type is not generic, returns `Some(false)`.
259
///
260
/// If the field does not have a remote type, returns `None`.
261
pub fn is_remote_generic(&self) -> Option<bool> {
262
if let Type::Path(type_path) = self.remote.as_ref()? {
263
type_path
264
.path
265
.segments
266
.last()
267
.map(|segment| !segment.arguments.is_empty())
268
} else {
269
Some(false)
270
}
271
}
272
}
273
274