Path: blob/main/crates/bevy_reflect/derive/src/field_attributes.rs
6599 views
//! Contains code related to field attributes for reflected types.1//!2//! A field attribute is an attribute which applies to particular field or variant3//! as opposed to an entire struct or enum. An example of such an attribute is4//! the derive helper attribute for `Reflect`, which looks like: `#[reflect(ignore)]`.56use crate::{7attribute_parser::terminated_parser, custom_attributes::CustomAttributes,8REFLECT_ATTRIBUTE_NAME,9};10use quote::ToTokens;11use syn::{parse::ParseStream, Attribute, LitStr, Meta, Token, Type};1213mod kw {14syn::custom_keyword!(ignore);15syn::custom_keyword!(skip_serializing);16syn::custom_keyword!(clone);17syn::custom_keyword!(default);18syn::custom_keyword!(remote);19}2021pub(crate) const IGNORE_SERIALIZATION_ATTR: &str = "skip_serializing";22pub(crate) const IGNORE_ALL_ATTR: &str = "ignore";2324pub(crate) const DEFAULT_ATTR: &str = "default";25pub(crate) const CLONE_ATTR: &str = "clone";2627/// Stores data about if the field should be visible via the Reflect and serialization interfaces28///29/// Note the relationship between serialization and reflection is such that a member must be reflected in order to be serialized.30/// 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.31/// The `is_reflected` predicate is provided as `self.is_active()`32#[derive(Default, Clone, Copy, PartialEq, Eq)]33pub(crate) enum ReflectIgnoreBehavior {34/// Don't ignore, appear to all systems35#[default]36None,37/// Ignore when serializing but not when reflecting38IgnoreSerialization,39/// Ignore both when serializing and reflecting40IgnoreAlways,41}4243impl ReflectIgnoreBehavior {44/// Returns `true` if the ignoring behavior implies member is included in the reflection API, and false otherwise.45pub fn is_active(self) -> bool {46match self {47ReflectIgnoreBehavior::None | ReflectIgnoreBehavior::IgnoreSerialization => true,48ReflectIgnoreBehavior::IgnoreAlways => false,49}50}5152/// 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)53pub fn is_ignored(self) -> bool {54!self.is_active()55}56}5758#[derive(Default, Clone)]59pub(crate) enum CloneBehavior {60#[default]61Default,62Trait,63Func(syn::ExprPath),64}6566/// Controls how the default value is determined for a field.67#[derive(Default, Clone)]68pub(crate) enum DefaultBehavior {69/// Field is required.70#[default]71Required,72/// Field can be defaulted using `Default::default()`.73Default,74/// Field can be created using the given function name.75///76/// This assumes the function is in scope, is callable with zero arguments,77/// and returns the expected type.78Func(syn::ExprPath),79}8081/// A container for attributes defined on a reflected type's field.82#[derive(Default, Clone)]83pub(crate) struct FieldAttributes {84/// Determines how this field should be ignored if at all.85pub ignore: ReflectIgnoreBehavior,86/// Sets the clone behavior of this field.87pub clone: CloneBehavior,88/// Sets the default behavior of this field.89pub default: DefaultBehavior,90/// Custom attributes created via `#[reflect(@...)]`.91pub custom_attributes: CustomAttributes,92/// For defining the remote wrapper type that should be used in place of the field for reflection logic.93pub remote: Option<Type>,94}9596impl FieldAttributes {97/// Parse all field attributes marked "reflect" (such as `#[reflect(ignore)]`).98pub fn parse_attributes(attrs: &[Attribute]) -> syn::Result<Self> {99let mut args = FieldAttributes::default();100101attrs102.iter()103.filter_map(|attr| {104if !attr.path().is_ident(REFLECT_ATTRIBUTE_NAME) {105// Not a reflect attribute -> skip106return None;107}108109let Meta::List(meta) = &attr.meta else {110return Some(syn::Error::new_spanned(attr, "expected meta list"));111};112113// Parse all attributes inside the list, collecting any errors114meta.parse_args_with(terminated_parser(Token![,], |stream| {115args.parse_field_attribute(stream)116}))117.err()118})119.reduce(|mut acc, err| {120acc.combine(err);121acc122})123.map_or(Ok(args), Err)124}125126/// Parses a single field attribute.127fn parse_field_attribute(&mut self, input: ParseStream) -> syn::Result<()> {128let lookahead = input.lookahead1();129if lookahead.peek(Token![@]) {130self.parse_custom_attribute(input)131} else if lookahead.peek(kw::ignore) {132self.parse_ignore(input)133} else if lookahead.peek(kw::skip_serializing) {134self.parse_skip_serializing(input)135} else if lookahead.peek(kw::clone) {136self.parse_clone(input)137} else if lookahead.peek(kw::default) {138self.parse_default(input)139} else if lookahead.peek(kw::remote) {140self.parse_remote(input)141} else {142Err(lookahead.error())143}144}145146/// Parse `ignore` attribute.147///148/// Examples:149/// - `#[reflect(ignore)]`150fn parse_ignore(&mut self, input: ParseStream) -> syn::Result<()> {151if self.ignore != ReflectIgnoreBehavior::None {152return Err(input.error(format!(153"only one of {:?} is allowed",154[IGNORE_ALL_ATTR, IGNORE_SERIALIZATION_ATTR]155)));156}157158input.parse::<kw::ignore>()?;159self.ignore = ReflectIgnoreBehavior::IgnoreAlways;160Ok(())161}162163/// Parse `skip_serializing` attribute.164///165/// Examples:166/// - `#[reflect(skip_serializing)]`167fn parse_skip_serializing(&mut self, input: ParseStream) -> syn::Result<()> {168if self.ignore != ReflectIgnoreBehavior::None {169return Err(input.error(format!(170"only one of {:?} is allowed",171[IGNORE_ALL_ATTR, IGNORE_SERIALIZATION_ATTR]172)));173}174175input.parse::<kw::skip_serializing>()?;176self.ignore = ReflectIgnoreBehavior::IgnoreSerialization;177Ok(())178}179180/// Parse `clone` attribute.181///182/// Examples:183/// - `#[reflect(clone)]`184/// - `#[reflect(clone = "path::to::func")]`185fn parse_clone(&mut self, input: ParseStream) -> syn::Result<()> {186if !matches!(self.clone, CloneBehavior::Default) {187return Err(input.error(format!("only one of {:?} is allowed", [CLONE_ATTR])));188}189190input.parse::<kw::clone>()?;191192if input.peek(Token![=]) {193input.parse::<Token![=]>()?;194195let lit = input.parse::<LitStr>()?;196self.clone = CloneBehavior::Func(lit.parse()?);197} else {198self.clone = CloneBehavior::Trait;199}200201Ok(())202}203204/// Parse `default` attribute.205///206/// Examples:207/// - `#[reflect(default)]`208/// - `#[reflect(default = "path::to::func")]`209fn parse_default(&mut self, input: ParseStream) -> syn::Result<()> {210if !matches!(self.default, DefaultBehavior::Required) {211return Err(input.error(format!("only one of {:?} is allowed", [DEFAULT_ATTR])));212}213214input.parse::<kw::default>()?;215216if input.peek(Token![=]) {217input.parse::<Token![=]>()?;218219let lit = input.parse::<LitStr>()?;220self.default = DefaultBehavior::Func(lit.parse()?);221} else {222self.default = DefaultBehavior::Default;223}224225Ok(())226}227228/// Parse `@` (custom attribute) attribute.229///230/// Examples:231/// - `#[reflect(@(foo = "bar"))]`232/// - `#[reflect(@(min = 0.0, max = 1.0))]`233fn parse_custom_attribute(&mut self, input: ParseStream) -> syn::Result<()> {234self.custom_attributes.parse_custom_attribute(input)235}236237/// Parse `remote` attribute.238///239/// Examples:240/// - `#[reflect(remote = path::to::RemoteType)]`241fn parse_remote(&mut self, input: ParseStream) -> syn::Result<()> {242if let Some(remote) = self.remote.as_ref() {243return Err(input.error(format!(244"remote type already specified as {}",245remote.to_token_stream()246)));247}248249input.parse::<kw::remote>()?;250input.parse::<Token![=]>()?;251252self.remote = Some(input.parse()?);253254Ok(())255}256257/// Returns `Some(true)` if the field has a generic remote type.258///259/// If the remote type is not generic, returns `Some(false)`.260///261/// If the field does not have a remote type, returns `None`.262pub fn is_remote_generic(&self) -> Option<bool> {263if let Type::Path(type_path) = self.remote.as_ref()? {264type_path265.path266.segments267.last()268.map(|segment| !segment.arguments.is_empty())269} else {270Some(false)271}272}273}274275276