cgp_field_macro_lib/
field.rs

1use alloc::string::ToString;
2use alloc::vec::Vec;
3
4use proc_macro2::TokenStream;
5use quote::ToTokens;
6use syn::{parse_quote, Fields, ItemImpl, ItemStruct};
7
8use crate::symbol::symbol_from_string;
9
10pub fn derive_has_field_impls(item_struct: &ItemStruct) -> Vec<ItemImpl> {
11    let struct_ident = &item_struct.ident;
12
13    let (impl_generics, ty_generics, where_clause) = item_struct.generics.split_for_impl();
14
15    let mut item_impls = Vec::new();
16
17    if let Fields::Named(fields) = &item_struct.fields {
18        for field in fields.named.iter() {
19            let field_ident = field.ident.as_ref().unwrap();
20
21            let field_symbol = symbol_from_string(&field_ident.to_string());
22
23            let field_type = &field.ty;
24
25            let has_field_impl: ItemImpl = parse_quote! {
26                impl #impl_generics HasField< #field_symbol >
27                    for #struct_ident #ty_generics
28                #where_clause
29                {
30                    type Value = #field_type;
31
32                    fn get_field(
33                        &self,
34                        key: ::core::marker::PhantomData< #field_symbol >,
35                    ) -> &Self::Value
36                    {
37                        &self. #field_ident
38                    }
39                }
40            };
41
42            let has_field_mut_impl: ItemImpl = parse_quote! {
43                impl #impl_generics HasFieldMut< #field_symbol >
44                    for #struct_ident #ty_generics
45                #where_clause
46                {
47                    fn get_field_mut(
48                        &mut self,
49                        key: ::core::marker::PhantomData< #field_symbol >,
50                    ) -> &mut Self::Value
51                    {
52                        &mut self. #field_ident
53                    }
54                }
55            };
56
57            item_impls.push(has_field_impl);
58            item_impls.push(has_field_mut_impl);
59        }
60    }
61
62    item_impls
63}
64
65pub fn derive_fields(input: TokenStream) -> TokenStream {
66    let item_struct: ItemStruct = syn::parse2(input).unwrap();
67
68    let item_impls = derive_has_field_impls(&item_struct);
69
70    let mut output = TokenStream::new();
71
72    for item_impl in item_impls {
73        output.extend(item_impl.to_token_stream());
74    }
75
76    output
77}