bevy_reflect_derive/impls/
structs.rs

1use crate::{
2    impls::{common_partial_reflect_methods, impl_full_reflect, impl_type_path, impl_typed},
3    struct_utility::FieldAccessors,
4    ReflectStruct,
5};
6use bevy_macro_utils::fq_std::{FQDefault, FQOption, FQResult};
7use quote::{quote, ToTokens};
8
9/// Implements `Struct`, `GetTypeRegistration`, and `Reflect` for the given derive data.
10pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenStream {
11    let fqoption = FQOption.into_token_stream();
12
13    let bevy_reflect_path = reflect_struct.meta().bevy_reflect_path();
14    let struct_path = reflect_struct.meta().type_path();
15
16    let field_names = reflect_struct
17        .active_fields()
18        .map(|field| {
19            field
20                .data
21                .ident
22                .as_ref()
23                .map(ToString::to_string)
24                .unwrap_or_else(|| field.declaration_index.to_string())
25        })
26        .collect::<Vec<String>>();
27
28    let FieldAccessors {
29        fields_ref,
30        fields_mut,
31        field_indices,
32        field_count,
33        ..
34    } = FieldAccessors::new(reflect_struct);
35
36    let where_clause_options = reflect_struct.where_clause_options();
37    let typed_impl = impl_typed(&where_clause_options, reflect_struct.to_info_tokens(false));
38
39    let type_path_impl = impl_type_path(reflect_struct.meta());
40    let full_reflect_impl = impl_full_reflect(&where_clause_options);
41    let common_methods = common_partial_reflect_methods(
42        reflect_struct.meta(),
43        || Some(quote!(#bevy_reflect_path::struct_partial_eq)),
44        || None,
45    );
46    let clone_fn = reflect_struct.get_clone_impl();
47
48    #[cfg(not(feature = "functions"))]
49    let function_impls = None::<proc_macro2::TokenStream>;
50    #[cfg(feature = "functions")]
51    let function_impls = crate::impls::impl_function_traits(&where_clause_options);
52
53    let get_type_registration_impl = reflect_struct.get_type_registration(&where_clause_options);
54
55    let (impl_generics, ty_generics, where_clause) = reflect_struct
56        .meta()
57        .type_path()
58        .generics()
59        .split_for_impl();
60
61    #[cfg(not(feature = "auto_register"))]
62    let auto_register = None::<proc_macro2::TokenStream>;
63    #[cfg(feature = "auto_register")]
64    let auto_register = crate::impls::reflect_auto_registration(reflect_struct.meta());
65
66    let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);
67
68    quote! {
69        #get_type_registration_impl
70
71        #typed_impl
72
73        #type_path_impl
74
75        #full_reflect_impl
76
77        #function_impls
78
79        #auto_register
80
81        impl #impl_generics #bevy_reflect_path::Struct for #struct_path #ty_generics #where_reflect_clause {
82            fn field(&self, name: &str) -> #FQOption<&dyn #bevy_reflect_path::PartialReflect> {
83                match name {
84                    #(#field_names => #fqoption::Some(#fields_ref),)*
85                    _ => #FQOption::None,
86                }
87            }
88
89            fn field_mut(&mut self, name: &str) -> #FQOption<&mut dyn #bevy_reflect_path::PartialReflect> {
90                match name {
91                    #(#field_names => #fqoption::Some(#fields_mut),)*
92                    _ => #FQOption::None,
93                }
94            }
95
96            fn field_at(&self, index: usize) -> #FQOption<&dyn #bevy_reflect_path::PartialReflect> {
97                match index {
98                    #(#field_indices => #fqoption::Some(#fields_ref),)*
99                    _ => #FQOption::None,
100                }
101            }
102
103            fn field_at_mut(&mut self, index: usize) -> #FQOption<&mut dyn #bevy_reflect_path::PartialReflect> {
104                match index {
105                    #(#field_indices => #fqoption::Some(#fields_mut),)*
106                    _ => #FQOption::None,
107                }
108            }
109
110            fn name_at(&self, index: usize) -> #FQOption<&str> {
111                match index {
112                    #(#field_indices => #fqoption::Some(#field_names),)*
113                    _ => #FQOption::None,
114                }
115            }
116
117            fn field_len(&self) -> usize {
118                #field_count
119            }
120
121            fn iter_fields(&self) -> #bevy_reflect_path::FieldIter {
122                #bevy_reflect_path::FieldIter::new(self)
123            }
124
125            fn to_dynamic_struct(&self) -> #bevy_reflect_path::DynamicStruct {
126                let mut dynamic: #bevy_reflect_path::DynamicStruct = #FQDefault::default();
127                dynamic.set_represented_type(#bevy_reflect_path::PartialReflect::get_represented_type_info(self));
128                #(dynamic.insert_boxed(#field_names, #bevy_reflect_path::PartialReflect::to_dynamic(#fields_ref));)*
129                dynamic
130            }
131        }
132
133        impl #impl_generics #bevy_reflect_path::PartialReflect for #struct_path #ty_generics #where_reflect_clause {
134            #[inline]
135            fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {
136                #FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
137            }
138
139            #[inline]
140            fn try_apply(
141                &mut self,
142                value: &dyn #bevy_reflect_path::PartialReflect
143            ) -> #FQResult<(), #bevy_reflect_path::ApplyError> {
144                if let #bevy_reflect_path::ReflectRef::Struct(struct_value)
145                    = #bevy_reflect_path::PartialReflect::reflect_ref(value) {
146                    for (i, value) in ::core::iter::Iterator::enumerate(#bevy_reflect_path::Struct::iter_fields(struct_value)) {
147                        let name = #bevy_reflect_path::Struct::name_at(struct_value, i).unwrap();
148                        if let #FQOption::Some(v) = #bevy_reflect_path::Struct::field_mut(self, name) {
149                           #bevy_reflect_path::PartialReflect::try_apply(v, value)?;
150                        }
151                    }
152                } else {
153                    return #FQResult::Err(
154                        #bevy_reflect_path::ApplyError::MismatchedKinds {
155                            from_kind: #bevy_reflect_path::PartialReflect::reflect_kind(value),
156                            to_kind: #bevy_reflect_path::ReflectKind::Struct
157                        }
158                    );
159                }
160                #FQResult::Ok(())
161            }
162            #[inline]
163            fn reflect_kind(&self) -> #bevy_reflect_path::ReflectKind {
164                #bevy_reflect_path::ReflectKind::Struct
165            }
166            #[inline]
167            fn reflect_ref(&self) -> #bevy_reflect_path::ReflectRef {
168                #bevy_reflect_path::ReflectRef::Struct(self)
169            }
170            #[inline]
171            fn reflect_mut(&mut self) -> #bevy_reflect_path::ReflectMut {
172                #bevy_reflect_path::ReflectMut::Struct(self)
173            }
174            #[inline]
175            fn reflect_owned(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::ReflectOwned {
176                #bevy_reflect_path::ReflectOwned::Struct(self)
177            }
178
179            #common_methods
180
181            #clone_fn
182        }
183    }
184}