cgp_field_macro_lib/
field.rs1use 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}