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