1use alloc::string::ToString;
2use alloc::vec::Vec;
3
4use proc_macro2::TokenStream;
5use quote::quote;
6use syn::spanned::Spanned;
7use syn::{Fields, ItemImpl, ItemStruct, LitInt, parse_quote};
8
9use crate::symbol::symbol_from_string;
10
11pub fn derive_has_field_impls_from_struct(item_struct: &ItemStruct) -> Vec<ItemImpl> {
12 let struct_ident = &item_struct.ident;
13
14 let (impl_generics, ty_generics, where_clause) = item_struct.generics.split_for_impl();
15
16 let mut item_impls = Vec::new();
17
18 match &item_struct.fields {
19 Fields::Named(fields) => {
20 for field in fields.named.iter() {
21 let field_ident = field.ident.as_ref().unwrap();
22
23 let field_symbol = symbol_from_string(&field_ident.to_string());
24
25 let field_type = &field.ty;
26
27 let has_field_impl: ItemImpl = parse_quote! {
28 impl #impl_generics HasField< #field_symbol >
29 for #struct_ident #ty_generics
30 #where_clause
31 {
32 type Value = #field_type;
33
34 fn get_field(
35 &self,
36 key: ::core::marker::PhantomData< #field_symbol >,
37 ) -> &Self::Value
38 {
39 &self. #field_ident
40 }
41 }
42 };
43
44 let has_field_mut_impl: ItemImpl = parse_quote! {
45 impl #impl_generics HasFieldMut< #field_symbol >
46 for #struct_ident #ty_generics
47 #where_clause
48 {
49 fn get_field_mut(
50 &mut self,
51 key: ::core::marker::PhantomData< #field_symbol >,
52 ) -> &mut Self::Value
53 {
54 &mut self. #field_ident
55 }
56 }
57 };
58
59 item_impls.push(has_field_impl);
60 item_impls.push(has_field_mut_impl);
61 }
62 }
63 Fields::Unnamed(fields) => {
64 for (i, field) in fields.unnamed.iter().enumerate() {
65 let field_ident = LitInt::new(&format!("{i}"), field.span());
66 let field_symbol = quote! { δ< #field_ident > };
67
68 let field_type = &field.ty;
69
70 let has_field_impl: ItemImpl = parse_quote! {
71 impl #impl_generics HasField< #field_symbol >
72 for #struct_ident #ty_generics
73 #where_clause
74 {
75 type Value = #field_type;
76
77 fn get_field(
78 &self,
79 key: ::core::marker::PhantomData< #field_symbol >,
80 ) -> &Self::Value
81 {
82 &self. #field_ident
83 }
84 }
85 };
86
87 let has_field_mut_impl: ItemImpl = parse_quote! {
88 impl #impl_generics HasFieldMut< #field_symbol >
89 for #struct_ident #ty_generics
90 #where_clause
91 {
92 fn get_field_mut(
93 &mut self,
94 key: ::core::marker::PhantomData< #field_symbol >,
95 ) -> &mut Self::Value
96 {
97 &mut self. #field_ident
98 }
99 }
100 };
101
102 item_impls.push(has_field_impl);
103 item_impls.push(has_field_mut_impl);
104 }
105 }
106 _ => {}
107 }
108
109 item_impls
110}
111
112pub fn derive_has_field(input: TokenStream) -> TokenStream {
113 let item_struct: ItemStruct = syn::parse2(input).unwrap();
114
115 let item_impls = derive_has_field_impls_from_struct(&item_struct);
116
117 quote! {
118 #( #item_impls )*
119 }
120}