
Takes the first two commits from #15375 and adds suggestions from this comment: https://github.com/bevyengine/bevy/pull/15375#issuecomment-2366968300 See #15375 for more reasoning/motivation. ## Rebasing (rerunning) ```rust git switch simpler-lint-fixes git reset --hard main cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate cargo fmt --all git add --update git commit --message "rustfmt" cargo clippy --workspace --all-targets --all-features --fix cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate cargo fmt --all git add --update git commit --message "clippy" git cherry-pick e6c0b94f6795222310fb812fa5c4512661fc7887 ```
93 lines
3.0 KiB
Rust
93 lines
3.0 KiB
Rust
use crate::{
|
|
derive_data::StructField,
|
|
field_attributes::{DefaultBehavior, ReflectIgnoreBehavior},
|
|
};
|
|
use bevy_macro_utils::fq_std::{FQBox, FQDefault};
|
|
use quote::quote;
|
|
use std::collections::HashMap;
|
|
use syn::{spanned::Spanned, Path};
|
|
|
|
type ReflectionIndex = usize;
|
|
|
|
/// Collected serialization data used to generate a `SerializationData` type.
|
|
pub(crate) struct SerializationDataDef {
|
|
/// Maps a field's _reflection_ index to its [`SkippedFieldDef`] if marked as `#[reflect(skip_serializing)]`.
|
|
skipped: HashMap<ReflectionIndex, SkippedFieldDef>,
|
|
}
|
|
|
|
impl SerializationDataDef {
|
|
/// Attempts to create a new `SerializationDataDef` from the given collection of fields.
|
|
///
|
|
/// Returns `Ok(Some(data))` if there are any fields needing to be skipped during serialization.
|
|
/// Otherwise, returns `Ok(None)`.
|
|
pub fn new(fields: &[StructField<'_>]) -> Result<Option<Self>, syn::Error> {
|
|
let mut skipped = HashMap::default();
|
|
|
|
for field in fields {
|
|
match field.attrs.ignore {
|
|
ReflectIgnoreBehavior::IgnoreSerialization => {
|
|
skipped.insert(
|
|
field.reflection_index.ok_or_else(|| {
|
|
syn::Error::new(
|
|
field.data.span(),
|
|
"internal error: field is missing a reflection index",
|
|
)
|
|
})?,
|
|
SkippedFieldDef::new(field)?,
|
|
);
|
|
}
|
|
_ => continue,
|
|
}
|
|
}
|
|
|
|
if skipped.is_empty() {
|
|
Ok(None)
|
|
} else {
|
|
Ok(Some(Self { skipped }))
|
|
}
|
|
}
|
|
|
|
/// Returns a `TokenStream` containing an initialized `SerializationData` type.
|
|
pub fn as_serialization_data(&self, bevy_reflect_path: &Path) -> proc_macro2::TokenStream {
|
|
let fields =
|
|
self.skipped
|
|
.iter()
|
|
.map(|(reflection_index, SkippedFieldDef { default_fn })| {
|
|
quote! {(
|
|
#reflection_index,
|
|
#bevy_reflect_path::serde::SkippedField::new(#default_fn)
|
|
)}
|
|
});
|
|
quote! {
|
|
#bevy_reflect_path::serde::SerializationData::new(
|
|
::core::iter::IntoIterator::into_iter([#(#fields),*])
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Collected field data used to generate a `SkippedField` type.
|
|
pub(crate) struct SkippedFieldDef {
|
|
/// The default function for this field.
|
|
///
|
|
/// This is of type `fn() -> Box<dyn Reflect>`.
|
|
default_fn: proc_macro2::TokenStream,
|
|
}
|
|
|
|
impl SkippedFieldDef {
|
|
pub fn new(field: &StructField<'_>) -> Result<Self, syn::Error> {
|
|
let ty = &field.data.ty;
|
|
|
|
let default_fn = match &field.attrs.default {
|
|
DefaultBehavior::Func(func) => quote! {
|
|
|| { #FQBox::new(#func()) }
|
|
},
|
|
_ => quote! {
|
|
|| { #FQBox::new(<#ty as #FQDefault>::default()) }
|
|
},
|
|
};
|
|
|
|
Ok(Self { default_fn })
|
|
}
|
|
}
|