Path: blob/main/crates/bevy_reflect/derive/src/serialization.rs
6599 views
use crate::{1derive_data::StructField,2field_attributes::{DefaultBehavior, ReflectIgnoreBehavior},3};4use bevy_macro_utils::fq_std::FQDefault;5use quote::quote;6use std::collections::HashMap;7use syn::{spanned::Spanned, Path};89type ReflectionIndex = usize;1011/// Collected serialization data used to generate a `SerializationData` type.12pub(crate) struct SerializationDataDef {13/// Maps a field's _reflection_ index to its [`SkippedFieldDef`] if marked as `#[reflect(skip_serializing)]`.14skipped: HashMap<ReflectionIndex, SkippedFieldDef>,15}1617impl SerializationDataDef {18/// Attempts to create a new `SerializationDataDef` from the given collection of fields.19///20/// Returns `Ok(Some(data))` if there are any fields needing to be skipped during serialization.21/// Otherwise, returns `Ok(None)`.22pub fn new(23fields: &[StructField<'_>],24bevy_reflect_path: &Path,25) -> Result<Option<Self>, syn::Error> {26let mut skipped = <HashMap<_, _>>::default();2728for field in fields {29match field.attrs.ignore {30ReflectIgnoreBehavior::IgnoreSerialization => {31skipped.insert(32field.reflection_index.ok_or_else(|| {33syn::Error::new(34field.data.span(),35"internal error: field is missing a reflection index",36)37})?,38SkippedFieldDef::new(field, bevy_reflect_path)?,39);40}41_ => continue,42}43}4445if skipped.is_empty() {46Ok(None)47} else {48Ok(Some(Self { skipped }))49}50}5152/// Returns a `TokenStream` containing an initialized `SerializationData` type.53pub fn as_serialization_data(&self, bevy_reflect_path: &Path) -> proc_macro2::TokenStream {54let fields =55self.skipped56.iter()57.map(|(reflection_index, SkippedFieldDef { default_fn })| {58quote! {(59#reflection_index,60#bevy_reflect_path::serde::SkippedField::new(#default_fn)61)}62});63quote! {64#bevy_reflect_path::serde::SerializationData::new(65::core::iter::IntoIterator::into_iter([#(#fields),*])66)67}68}69}7071/// Collected field data used to generate a `SkippedField` type.72pub(crate) struct SkippedFieldDef {73/// The default function for this field.74///75/// This is of type `fn() -> Box<dyn Reflect>`.76default_fn: proc_macro2::TokenStream,77}7879impl SkippedFieldDef {80pub fn new(field: &StructField<'_>, bevy_reflect_path: &Path) -> Result<Self, syn::Error> {81let ty = &field.data.ty;8283let default_fn = match &field.attrs.default {84DefaultBehavior::Func(func) => quote! {85|| { #bevy_reflect_path::__macro_exports::alloc_utils::Box::new(#func()) }86},87_ => quote! {88|| { #bevy_reflect_path::__macro_exports::alloc_utils::Box::new(<#ty as #FQDefault>::default()) }89},90};9192Ok(Self { default_fn })93}94}959697