haste_reflect_derive/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{Attribute, Data, DeriveInput, Expr, Field, Lit, Meta, parse_macro_input};
4
5fn get_attribute_rename(attrs: &[Attribute]) -> Option<String> {
6 attrs.iter().find_map(|attr| match &attr.meta {
7 Meta::NameValue(name_value) => {
8 if name_value.path.is_ident("rename_field") {
9 match &name_value.value {
10 Expr::Lit(lit) => match &lit.lit {
11 Lit::Str(lit) => Some(lit.value()),
12 _ => panic!("Expected a string literal"),
13 },
14 _ => panic!("Expected a string literal"),
15 }
16 } else {
17 None
18 }
19 }
20 _ => None,
21 })
22}
23
24fn is_optional(field: &Field) -> bool {
25 if let syn::Type::Path(type_path) = &field.ty {
26 if let Some(segment) = type_path.path.segments.first() {
27 return segment.ident == "Option";
28 }
29 }
30 false
31}
32
33#[proc_macro_derive(Reflect, attributes(rename_field))]
34pub fn haste_reflect(input: TokenStream) -> TokenStream {
35 let input = parse_macro_input!(input as DeriveInput);
37
38 match input.data {
39 Data::Struct(data) => {
40 let all_fields = data
41 .fields
42 .iter()
43 .map(|field| field.ident.to_owned().unwrap().to_string());
44
45 let name = input.ident;
46 let name_str = name.to_string();
47
48 let accessors = data.fields.iter().map(|field| {
49 let renamed = get_attribute_rename(&field.attrs);
50 let name = if let Some(renamed_field) = renamed {
51 renamed_field
52 } else {
53 field.ident.to_owned().unwrap().to_string()
54 };
55
56 let accessor = field.ident.to_owned().unwrap();
57 if is_optional(field) {
58 quote! {
59 #name => if let Some(v) = self.#accessor.as_ref() {
60 Some(v)
61 } else {
62 None
63 }
64 }
65 } else {
66 quote! {
67 #name => Some(&self.#accessor)
68 }
69 }
70 });
71
72 let mutable_accessor = data.fields.iter().map(|field| {
73 let renamed = get_attribute_rename(&field.attrs);
74 let name = if let Some(renamed_field) = renamed {
75 renamed_field
76 } else {
77 field.ident.to_owned().unwrap().to_string()
78 };
79
80 let accessor = field.ident.to_owned().unwrap();
81 quote! {
84 #name => Some(&mut self.#accessor)
85 }
86 });
87
88 let expanded = quote! {
89 impl haste_reflect::MetaValue for #name {
90 fn fields(&self) -> Vec<&'static str> {
91 vec![
92 #(#all_fields),*
93 ]
94 }
95
96 fn get_field<'a>(&'a self, field: &str) -> Option<&'a dyn MetaValue> {
97 match field {
98 #(#accessors),*
99 ,_ => None,
100 }
101 }
102
103 fn get_field_mut<'a>(&'a mut self, field: &str) -> Option<&'a mut dyn MetaValue> {
104 match field {
105 #(#mutable_accessor),*
106 ,_ => None,
107 }
108 }
109
110 fn get_index_mut<'a>(&'a mut self, index: usize) -> Option<&'a mut dyn MetaValue> {
111 None
112 }
113
114 fn get_index<'a>(&'a self, _index: usize) -> Option<&'a dyn MetaValue> {
115 None
116 }
117
118 fn typename(&self) -> &'static str {
119 #name_str
120 }
121
122 fn as_any(&self) -> &dyn std::any::Any {
123 self
124 }
125
126 fn flatten(&self) -> Vec<&dyn MetaValue> {
127 vec![self]
128 }
129
130 fn is_many(&self) -> bool {
131 false
132 }
133
134 }
135 };
136
137 expanded.into()
138 }
139
140 Data::Enum(data) => {
141 let enum_name = input.ident;
142
143 let variants_fields = data.variants.iter().map(|variant| {
144 let name = variant.ident.to_owned();
145 quote! {
146 Self::#name(k) => k.fields()
147 }
148 });
149
150 let variants_get_field = data.variants.iter().map(|variant| {
151 let name = variant.ident.to_owned();
152 quote! {
153 Self::#name(k) => k.get_field(field)
154 }
155 });
156
157 let variants_get_index = data.variants.iter().map(|variant| {
158 let name = variant.ident.to_owned();
159 quote! {
160 Self::#name(k) => k.get_index(field)
161 }
162 });
163
164 let variants_get_field_mut = data.variants.iter().map(|variant| {
165 let name = variant.ident.to_owned();
166 quote! {
167 Self::#name(k) => k.get_field_mut(field)
168 }
169 });
170
171 let variants_get_index_mut = data.variants.iter().map(|variant| {
172 let name = variant.ident.to_owned();
173 quote! {
174 Self::#name(k) => k.get_index_mut(index)
175 }
176 });
177
178 let variants_typename = data.variants.iter().map(|variant| {
179 let name = variant.ident.to_owned();
180 quote! {
181 Self::#name(k) => k.typename()
182 }
183 });
184
185 let variants_as_any = data.variants.iter().map(|variant| {
186 let name = variant.ident.to_owned();
187 quote! {
188 Self::#name(k) => k.as_any()
189 }
190 });
191
192 let variants_flatten = data.variants.iter().map(|variant| {
193 let name = variant.ident.to_owned();
194 quote! {
195 Self::#name(k) => k.flatten()
196 }
197 });
198
199 let expanded = quote! {
200 impl haste_reflect::MetaValue for #enum_name {
201 fn fields(&self) -> Vec<&'static str> {
202 match self {
203 #(#variants_fields),*
204 }
205 }
206
207 fn get_field<'a>(&'a self, field: &str) -> Option<&'a dyn MetaValue> {
208 match self {
209 #(#variants_get_field),*
210 }
211 }
212
213 fn get_index<'a>(&'a self, field: usize) -> Option<&'a dyn MetaValue> {
214 match self {
215 #(#variants_get_index),*
216 }
217 }
218
219 fn get_field_mut<'a>(&'a mut self, field: &str) -> Option<&'a mut dyn MetaValue> {
220 match self {
221 #(#variants_get_field_mut),*
222 }
223 }
224
225 fn get_index_mut<'a>(&'a mut self, index: usize) -> Option<&'a mut dyn MetaValue> {
226 match self {
227 #(#variants_get_index_mut),*
228 }
229 }
230
231 fn typename(&self) -> &'static str {
232 match self {
233 #(#variants_typename),*
234 }
235 }
236
237 fn as_any(&self) -> &dyn std::any::Any {
238 match self {
239 #(#variants_as_any),*
240 }
241 }
242
243 fn flatten(&self) -> Vec<&dyn MetaValue> {
244 match self {
245 #(#variants_flatten),*
246 }
247 }
248
249 fn is_many(&self) -> bool {
250 false
251 }
252 }
253 };
254
255 expanded.into()
258 }
259
260 Data::Union(_data) => {
261 todo!("Union not supported");
262 }
263 }
264}