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 }
131 };
132
133 expanded.into()
134 }
135
136 Data::Enum(data) => {
137 let enum_name = input.ident;
138
139 let variants_fields = data.variants.iter().map(|variant| {
140 let name = variant.ident.to_owned();
141 quote! {
142 Self::#name(k) => k.fields()
143 }
144 });
145
146 let variants_get_field = data.variants.iter().map(|variant| {
147 let name = variant.ident.to_owned();
148 quote! {
149 Self::#name(k) => k.get_field(field)
150 }
151 });
152
153 let variants_get_index = data.variants.iter().map(|variant| {
154 let name = variant.ident.to_owned();
155 quote! {
156 Self::#name(k) => k.get_index(field)
157 }
158 });
159
160 let variants_get_field_mut = data.variants.iter().map(|variant| {
161 let name = variant.ident.to_owned();
162 quote! {
163 Self::#name(k) => k.get_field_mut(field)
164 }
165 });
166
167 let variants_get_index_mut = data.variants.iter().map(|variant| {
168 let name = variant.ident.to_owned();
169 quote! {
170 Self::#name(k) => k.get_index_mut(index)
171 }
172 });
173
174 let variants_typename = data.variants.iter().map(|variant| {
175 let name = variant.ident.to_owned();
176 quote! {
177 Self::#name(k) => k.typename()
178 }
179 });
180
181 let variants_as_any = data.variants.iter().map(|variant| {
182 let name = variant.ident.to_owned();
183 quote! {
184 Self::#name(k) => k.as_any()
185 }
186 });
187
188 let variants_flatten = data.variants.iter().map(|variant| {
189 let name = variant.ident.to_owned();
190 quote! {
191 Self::#name(k) => k.flatten()
192 }
193 });
194
195 let expanded = quote! {
196 impl haste_reflect::MetaValue for #enum_name {
197 fn fields(&self) -> Vec<&'static str> {
198 match self {
199 #(#variants_fields),*
200 }
201 }
202
203 fn get_field<'a>(&'a self, field: &str) -> Option<&'a dyn MetaValue> {
204 match self {
205 #(#variants_get_field),*
206 }
207 }
208
209 fn get_index<'a>(&'a self, field: usize) -> Option<&'a dyn MetaValue> {
210 match self {
211 #(#variants_get_index),*
212 }
213 }
214
215 fn get_field_mut<'a>(&'a mut self, field: &str) -> Option<&'a mut dyn MetaValue> {
216 match self {
217 #(#variants_get_field_mut),*
218 }
219 }
220
221 fn get_index_mut<'a>(&'a mut self, index: usize) -> Option<&'a mut dyn MetaValue> {
222 match self {
223 #(#variants_get_index_mut),*
224 }
225 }
226
227 fn typename(&self) -> &'static str {
228 match self {
229 #(#variants_typename),*
230 }
231 }
232
233 fn as_any(&self) -> &dyn std::any::Any {
234 match self {
235 #(#variants_as_any),*
236 }
237 }
238
239 fn flatten(&self) -> Vec<&dyn MetaValue> {
240 match self {
241 #(#variants_flatten),*
242 }
243 }
244 }
245 };
246
247 expanded.into()
250 }
251
252 Data::Union(_data) => {
253 todo!("Union not supported");
254 }
255 }
256}