Path: blob/main/crates/bevy_reflect/derive/src/field_attributes.rs
6849 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::{custom_attributes::CustomAttributes, REFLECT_ATTRIBUTE_NAME};7use bevy_macro_utils::terminated_parser;8use quote::ToTokens;9use syn::{parse::ParseStream, Attribute, LitStr, Meta, Token, Type};1011mod kw {12syn::custom_keyword!(ignore);13syn::custom_keyword!(skip_serializing);14syn::custom_keyword!(clone);15syn::custom_keyword!(default);16syn::custom_keyword!(remote);17}1819pub(crate) const IGNORE_SERIALIZATION_ATTR: &str = "skip_serializing";20pub(crate) const IGNORE_ALL_ATTR: &str = "ignore";2122pub(crate) const DEFAULT_ATTR: &str = "default";23pub(crate) const CLONE_ATTR: &str = "clone";2425/// Stores data about if the field should be visible via the Reflect and serialization interfaces26///27/// Note the relationship between serialization and reflection is such that a member must be reflected in order to be serialized.28/// 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.29/// The `is_reflected` predicate is provided as `self.is_active()`30#[derive(Default, Clone, Copy, PartialEq, Eq)]31pub(crate) enum ReflectIgnoreBehavior {32/// Don't ignore, appear to all systems33#[default]34None,35/// Ignore when serializing but not when reflecting36IgnoreSerialization,37/// Ignore both when serializing and reflecting38IgnoreAlways,39}4041impl ReflectIgnoreBehavior {42/// Returns `true` if the ignoring behavior implies member is included in the reflection API, and false otherwise.43pub fn is_active(self) -> bool {44match self {45ReflectIgnoreBehavior::None | ReflectIgnoreBehavior::IgnoreSerialization => true,46ReflectIgnoreBehavior::IgnoreAlways => false,47}48}4950/// 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)51pub fn is_ignored(self) -> bool {52!self.is_active()53}54}5556#[derive(Default, Clone)]57pub(crate) enum CloneBehavior {58#[default]59Default,60Trait,61Func(syn::ExprPath),62}6364/// Controls how the default value is determined for a field.65#[derive(Default, Clone)]66pub(crate) enum DefaultBehavior {67/// Field is required.68#[default]69Required,70/// Field can be defaulted using `Default::default()`.71Default,72/// Field can be created using the given function name.73///74/// This assumes the function is in scope, is callable with zero arguments,75/// and returns the expected type.76Func(syn::ExprPath),77}7879/// A container for attributes defined on a reflected type's field.80#[derive(Default, Clone)]81pub(crate) struct FieldAttributes {82/// Determines how this field should be ignored if at all.83pub ignore: ReflectIgnoreBehavior,84/// Sets the clone behavior of this field.85pub clone: CloneBehavior,86/// Sets the default behavior of this field.87pub default: DefaultBehavior,88/// Custom attributes created via `#[reflect(@...)]`.89pub custom_attributes: CustomAttributes,90/// For defining the remote wrapper type that should be used in place of the field for reflection logic.91pub remote: Option<Type>,92}9394impl FieldAttributes {95/// Parse all field attributes marked "reflect" (such as `#[reflect(ignore)]`).96pub fn parse_attributes(attrs: &[Attribute]) -> syn::Result<Self> {97let mut args = FieldAttributes::default();9899attrs100.iter()101.filter_map(|attr| {102if !attr.path().is_ident(REFLECT_ATTRIBUTE_NAME) {103// Not a reflect attribute -> skip104return None;105}106107let Meta::List(meta) = &attr.meta else {108return Some(syn::Error::new_spanned(attr, "expected meta list"));109};110111// Parse all attributes inside the list, collecting any errors112meta.parse_args_with(terminated_parser(Token![,], |stream| {113args.parse_field_attribute(stream)114}))115.err()116})117.reduce(|mut acc, err| {118acc.combine(err);119acc120})121.map_or(Ok(args), Err)122}123124/// Parses a single field attribute.125fn parse_field_attribute(&mut self, input: ParseStream) -> syn::Result<()> {126let lookahead = input.lookahead1();127if lookahead.peek(Token![@]) {128self.parse_custom_attribute(input)129} else if lookahead.peek(kw::ignore) {130self.parse_ignore(input)131} else if lookahead.peek(kw::skip_serializing) {132self.parse_skip_serializing(input)133} else if lookahead.peek(kw::clone) {134self.parse_clone(input)135} else if lookahead.peek(kw::default) {136self.parse_default(input)137} else if lookahead.peek(kw::remote) {138self.parse_remote(input)139} else {140Err(lookahead.error())141}142}143144/// Parse `ignore` attribute.145///146/// Examples:147/// - `#[reflect(ignore)]`148fn parse_ignore(&mut self, input: ParseStream) -> syn::Result<()> {149if self.ignore != ReflectIgnoreBehavior::None {150return Err(input.error(format!(151"only one of {:?} is allowed",152[IGNORE_ALL_ATTR, IGNORE_SERIALIZATION_ATTR]153)));154}155156input.parse::<kw::ignore>()?;157self.ignore = ReflectIgnoreBehavior::IgnoreAlways;158Ok(())159}160161/// Parse `skip_serializing` attribute.162///163/// Examples:164/// - `#[reflect(skip_serializing)]`165fn parse_skip_serializing(&mut self, input: ParseStream) -> syn::Result<()> {166if self.ignore != ReflectIgnoreBehavior::None {167return Err(input.error(format!(168"only one of {:?} is allowed",169[IGNORE_ALL_ATTR, IGNORE_SERIALIZATION_ATTR]170)));171}172173input.parse::<kw::skip_serializing>()?;174self.ignore = ReflectIgnoreBehavior::IgnoreSerialization;175Ok(())176}177178/// Parse `clone` attribute.179///180/// Examples:181/// - `#[reflect(clone)]`182/// - `#[reflect(clone = "path::to::func")]`183fn parse_clone(&mut self, input: ParseStream) -> syn::Result<()> {184if !matches!(self.clone, CloneBehavior::Default) {185return Err(input.error(format!("only one of {:?} is allowed", [CLONE_ATTR])));186}187188input.parse::<kw::clone>()?;189190if input.peek(Token![=]) {191input.parse::<Token![=]>()?;192193let lit = input.parse::<LitStr>()?;194self.clone = CloneBehavior::Func(lit.parse()?);195} else {196self.clone = CloneBehavior::Trait;197}198199Ok(())200}201202/// Parse `default` attribute.203///204/// Examples:205/// - `#[reflect(default)]`206/// - `#[reflect(default = "path::to::func")]`207fn parse_default(&mut self, input: ParseStream) -> syn::Result<()> {208if !matches!(self.default, DefaultBehavior::Required) {209return Err(input.error(format!("only one of {:?} is allowed", [DEFAULT_ATTR])));210}211212input.parse::<kw::default>()?;213214if input.peek(Token![=]) {215input.parse::<Token![=]>()?;216217let lit = input.parse::<LitStr>()?;218self.default = DefaultBehavior::Func(lit.parse()?);219} else {220self.default = DefaultBehavior::Default;221}222223Ok(())224}225226/// Parse `@` (custom attribute) attribute.227///228/// Examples:229/// - `#[reflect(@(foo = "bar"))]`230/// - `#[reflect(@(min = 0.0, max = 1.0))]`231fn parse_custom_attribute(&mut self, input: ParseStream) -> syn::Result<()> {232self.custom_attributes.parse_custom_attribute(input)233}234235/// Parse `remote` attribute.236///237/// Examples:238/// - `#[reflect(remote = path::to::RemoteType)]`239fn parse_remote(&mut self, input: ParseStream) -> syn::Result<()> {240if let Some(remote) = self.remote.as_ref() {241return Err(input.error(format!(242"remote type already specified as {}",243remote.to_token_stream()244)));245}246247input.parse::<kw::remote>()?;248input.parse::<Token![=]>()?;249250self.remote = Some(input.parse()?);251252Ok(())253}254255/// Returns `Some(true)` if the field has a generic remote type.256///257/// If the remote type is not generic, returns `Some(false)`.258///259/// If the field does not have a remote type, returns `None`.260pub fn is_remote_generic(&self) -> Option<bool> {261if let Type::Path(type_path) = self.remote.as_ref()? {262type_path263.path264.segments265.last()266.map(|segment| !segment.arguments.is_empty())267} else {268Some(false)269}270}271}272273274