bevy_reflect_derive/
struct_utility.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use crate::{derive_data::StructField, ReflectStruct};
use quote::quote;

/// A helper struct for creating remote-aware field accessors.
///
/// These are "remote-aware" because when a field is a remote field, it uses a [`transmute`] internally
/// to access the field.
///
/// [`transmute`]: std::mem::transmute
pub(crate) struct FieldAccessors {
    /// The referenced field accessors, such as `&self.foo`.
    pub fields_ref: Vec<proc_macro2::TokenStream>,
    /// The mutably referenced field accessors, such as `&mut self.foo`.
    pub fields_mut: Vec<proc_macro2::TokenStream>,
    /// The ordered set of field indices (basically just the range of [0, `field_count`).
    pub field_indices: Vec<usize>,
    /// The number of fields in the reflected struct.
    pub field_count: usize,
}

impl FieldAccessors {
    pub fn new(reflect_struct: &ReflectStruct) -> Self {
        let bevy_reflect_path = reflect_struct.meta().bevy_reflect_path();
        let fields_ref = Self::get_fields(reflect_struct, |field, accessor| {
            match &field.attrs.remote {
                Some(wrapper_ty) => {
                    quote! {
                        <#wrapper_ty as #bevy_reflect_path::ReflectRemote>::as_wrapper(&#accessor)
                    }
                }
                None => quote!(& #accessor),
            }
        });
        let fields_mut = Self::get_fields(reflect_struct, |field, accessor| {
            match &field.attrs.remote {
                Some(wrapper_ty) => {
                    quote! {
                        <#wrapper_ty as #bevy_reflect_path::ReflectRemote>::as_wrapper_mut(&mut #accessor)
                    }
                }
                None => quote!(&mut #accessor),
            }
        });

        let field_count = fields_ref.len();
        let field_indices = (0..field_count).collect();

        Self {
            fields_ref,
            fields_mut,
            field_indices,
            field_count,
        }
    }

    fn get_fields<F>(
        reflect_struct: &ReflectStruct,
        mut wrapper_fn: F,
    ) -> Vec<proc_macro2::TokenStream>
    where
        F: FnMut(&StructField, proc_macro2::TokenStream) -> proc_macro2::TokenStream,
    {
        let is_remote = reflect_struct.meta().is_remote_wrapper();
        reflect_struct
            .active_fields()
            .map(|field| {
                let member = crate::ident::ident_or_index(
                    field.data.ident.as_ref(),
                    field.declaration_index,
                );
                let accessor = if is_remote {
                    quote!(self.0.#member)
                } else {
                    quote!(self.#member)
                };

                wrapper_fn(field, accessor)
            })
            .collect::<Vec<_>>()
    }
}