bevy/crates/bevy_reflect/derive/src/serialization.rs
Clar Fon efda7f3f9c
Simpler lint fixes: makes ci lints work but disables a lint for now (#15376)
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
```
2024-09-24 11:42:59 +00:00

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 })
}
}