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