1use proc_macro::TokenStream;
38use quote::{format_ident, quote};
39use syn::{parse_macro_input, Attribute, Data, DeriveInput, Fields, Meta};
40
41fn get_crate_path(attrs: &[Attribute]) -> proc_macro2::TokenStream {
44 for attr in attrs {
45 if attr.path().is_ident("graph") {
46 if let Meta::List(list) = &attr.meta {
47 let tokens = list.tokens.to_string();
48 if let Some(rest) = tokens.strip_prefix("crate") {
50 let rest = rest.trim();
51 if let Some(rest) = rest.strip_prefix('=') {
52 let rest = rest.trim();
53 if rest.starts_with('"') && rest.ends_with('"') {
54 let path_str = &rest[1..rest.len() - 1];
55 let path: syn::Path =
57 syn::parse_str(path_str).expect("Invalid crate path");
58 return quote! { #path };
59 }
60 }
61 }
62 }
63 }
64 }
65 quote! { packr_abi }
67}
68
69#[proc_macro_derive(GraphValue, attributes(graph))]
102pub fn derive_graph_value(input: TokenStream) -> TokenStream {
103 let input = parse_macro_input!(input as DeriveInput);
104 let crate_path = get_crate_path(&input.attrs);
105
106 let expanded = match &input.data {
107 Data::Struct(data) => derive_struct(&input, data, &crate_path),
108 Data::Enum(data) => derive_enum(&input, data, &crate_path),
109 Data::Union(_) => {
110 return syn::Error::new_spanned(&input, "GraphValue cannot be derived for unions")
111 .to_compile_error()
112 .into();
113 }
114 };
115
116 expanded.into()
117}
118
119fn derive_struct(
120 input: &DeriveInput,
121 data: &syn::DataStruct,
122 krate: &proc_macro2::TokenStream,
123) -> proc_macro2::TokenStream {
124 let name = &input.ident;
125 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
126
127 match &data.fields {
128 Fields::Named(fields) => {
129 let field_from_value: Vec<_> = fields.named.iter().map(|f| {
131 let field_name = f.ident.as_ref().unwrap();
132 let field_name_str = get_rename(&f.attrs).unwrap_or_else(|| field_name.to_string());
133 let field_type = &f.ty;
134 quote! {
135 #field_name: {
136 let field_value = fields.iter()
137 .find(|(name, _)| name == #field_name_str)
138 .map(|(_, v)| v.clone())
139 .ok_or_else(|| #krate::ConversionError::MissingField(
140 #krate::__private::String::from(#field_name_str)
141 ))?;
142 <#field_type as #krate::__private::TryFrom<#krate::Value>>::try_from(field_value)
143 .map_err(|e| #krate::ConversionError::FieldError(
144 #krate::__private::String::from(#field_name_str),
145 #krate::__private::Box::new(e)
146 ))?
147 }
148 }
149 }).collect();
150
151 let field_count = fields.named.len();
152
153 let field_accessors: Vec<_> = fields
155 .named
156 .iter()
157 .map(|f| {
158 let field_name = f.ident.as_ref().unwrap();
159 let field_name_str =
160 get_rename(&f.attrs).unwrap_or_else(|| field_name.to_string());
161 quote! {
162 (
163 #krate::__private::String::from(#field_name_str),
164 #krate::Value::from(value.#field_name)
165 )
166 }
167 })
168 .collect();
169
170 let type_name_str = name.to_string();
171
172 quote! {
173 impl #impl_generics #krate::__private::From<#name #ty_generics> for #krate::Value #where_clause {
174 fn from(value: #name #ty_generics) -> #krate::Value {
175 #krate::Value::Record {
176 type_name: #krate::__private::String::from(#type_name_str),
177 fields: #krate::__private::vec![
178 #(#field_accessors),*
179 ],
180 }
181 }
182 }
183
184 impl #impl_generics #krate::__private::TryFrom<#krate::Value> for #name #ty_generics #where_clause {
185 type Error = #krate::ConversionError;
186
187 fn try_from(value: #krate::Value) -> #krate::__private::Result<Self, Self::Error> {
188 match value {
189 #krate::Value::Record { fields, .. } => {
190 if fields.len() != #field_count {
191 return #krate::__private::Err(#krate::ConversionError::WrongFieldCount {
192 expected: #field_count,
193 got: fields.len(),
194 });
195 }
196 #krate::__private::Ok(Self {
197 #(#field_from_value),*
198 })
199 }
200 other => #krate::__private::Err(#krate::ConversionError::ExpectedRecord(
201 #krate::__private::format!("{:?}", other)
202 )),
203 }
204 }
205 }
206 }
207 }
208 Fields::Unnamed(fields) => {
209 let field_indices: Vec<_> = (0..fields.unnamed.len()).map(syn::Index::from).collect();
211
212 let field_from_value: Vec<_> = fields.unnamed.iter().enumerate().map(|(i, f)| {
213 let field_type = &f.ty;
214 quote! {
215 <#field_type as #krate::__private::TryFrom<#krate::Value>>::try_from(
216 fields.get(#i).cloned().ok_or_else(|| #krate::ConversionError::MissingIndex(#i))?
217 ).map_err(|e| #krate::ConversionError::IndexError(#i, #krate::__private::Box::new(e)))?
218 }
219 }).collect();
220
221 let field_count = fields.unnamed.len();
222
223 quote! {
224 impl #impl_generics #krate::__private::From<#name #ty_generics> for #krate::Value #where_clause {
225 fn from(value: #name #ty_generics) -> #krate::Value {
226 #krate::Value::Tuple(#krate::__private::vec![
227 #(#krate::Value::from(value.#field_indices)),*
228 ])
229 }
230 }
231
232 impl #impl_generics #krate::__private::TryFrom<#krate::Value> for #name #ty_generics #where_clause {
233 type Error = #krate::ConversionError;
234
235 fn try_from(value: #krate::Value) -> #krate::__private::Result<Self, Self::Error> {
236 match value {
237 #krate::Value::Tuple(fields) => {
238 if fields.len() != #field_count {
239 return #krate::__private::Err(#krate::ConversionError::WrongFieldCount {
240 expected: #field_count,
241 got: fields.len(),
242 });
243 }
244 #krate::__private::Ok(Self(
245 #(#field_from_value),*
246 ))
247 }
248 other => #krate::__private::Err(#krate::ConversionError::ExpectedTuple(
249 #krate::__private::format!("{:?}", other)
250 )),
251 }
252 }
253 }
254 }
255 }
256 Fields::Unit => {
257 quote! {
259 impl #impl_generics #krate::__private::From<#name #ty_generics> for #krate::Value #where_clause {
260 fn from(_: #name #ty_generics) -> #krate::Value {
261 #krate::Value::Tuple(#krate::__private::vec![])
262 }
263 }
264
265 impl #impl_generics #krate::__private::TryFrom<#krate::Value> for #name #ty_generics #where_clause {
266 type Error = #krate::ConversionError;
267
268 fn try_from(value: #krate::Value) -> #krate::__private::Result<Self, Self::Error> {
269 match value {
270 #krate::Value::Tuple(fields) if fields.is_empty() => {
271 #krate::__private::Ok(Self)
272 }
273 #krate::Value::Tuple(fields) => {
274 #krate::__private::Err(#krate::ConversionError::WrongFieldCount {
275 expected: 0,
276 got: fields.len(),
277 })
278 }
279 other => #krate::__private::Err(#krate::ConversionError::ExpectedTuple(
280 #krate::__private::format!("{:?}", other)
281 )),
282 }
283 }
284 }
285 }
286 }
287 }
288}
289
290fn derive_enum(
291 input: &DeriveInput,
292 data: &syn::DataEnum,
293 krate: &proc_macro2::TokenStream,
294) -> proc_macro2::TokenStream {
295 let name = &input.ident;
296 let type_name_str = name.to_string();
297 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
298
299 let to_value_arms: Vec<_> = data
301 .variants
302 .iter()
303 .enumerate()
304 .map(|(default_tag, variant)| {
305 let variant_name = &variant.ident;
306 let case_name_str = variant_name.to_string();
307 let tag = get_tag(&variant.attrs).unwrap_or(default_tag);
308
309 match &variant.fields {
310 Fields::Named(fields) => {
311 let field_names: Vec<_> = fields
312 .named
313 .iter()
314 .map(|f| f.ident.as_ref().unwrap())
315 .collect();
316 let field_to_value: Vec<_> = fields
318 .named
319 .iter()
320 .map(|f| {
321 let field_name = f.ident.as_ref().unwrap();
322 let field_name_str =
323 get_rename(&f.attrs).unwrap_or_else(|| field_name.to_string());
324 quote! {
325 (
326 #krate::__private::String::from(#field_name_str),
327 #krate::Value::from(#field_name)
328 )
329 }
330 })
331 .collect();
332
333 quote! {
334 #name::#variant_name { #(#field_names),* } => {
335 #krate::Value::Variant {
336 type_name: #krate::__private::String::from(#type_name_str),
337 case_name: #krate::__private::String::from(#case_name_str),
338 tag: #tag,
339 payload: #krate::__private::vec![
340 #krate::Value::Record {
341 type_name: #krate::__private::String::from(#case_name_str),
342 fields: #krate::__private::vec![#(#field_to_value),*],
343 }
344 ],
345 }
346 }
347 }
348 }
349 Fields::Unnamed(fields) => {
350 let field_names: Vec<_> = (0..fields.unnamed.len())
351 .map(|i| format_ident!("f{}", i))
352 .collect();
353
354 quote! {
356 #name::#variant_name(#(#field_names),*) => {
357 #krate::Value::Variant {
358 type_name: #krate::__private::String::from(#type_name_str),
359 case_name: #krate::__private::String::from(#case_name_str),
360 tag: #tag,
361 payload: #krate::__private::vec![
362 #(#krate::Value::from(#field_names)),*
363 ],
364 }
365 }
366 }
367 }
368 Fields::Unit => {
369 quote! {
370 #name::#variant_name => {
371 #krate::Value::Variant {
372 type_name: #krate::__private::String::from(#type_name_str),
373 case_name: #krate::__private::String::from(#case_name_str),
374 tag: #tag,
375 payload: #krate::__private::vec![],
376 }
377 }
378 }
379 }
380 }
381 })
382 .collect();
383
384 let from_value_arms: Vec<_> = data.variants.iter().enumerate().map(|(default_tag, variant)| {
386 let variant_name = &variant.ident;
387 let tag = get_tag(&variant.attrs).unwrap_or(default_tag);
388
389 match &variant.fields {
390 Fields::Named(fields) => {
391 let field_from_value: Vec<_> = fields.named.iter().map(|f| {
392 let field_name = f.ident.as_ref().unwrap();
393 let field_name_str = get_rename(&f.attrs).unwrap_or_else(|| field_name.to_string());
394 let field_type = &f.ty;
395 quote! {
396 #field_name: {
397 let field_value = record_fields.iter()
398 .find(|(name, _)| name == #field_name_str)
399 .map(|(_, v)| v.clone())
400 .ok_or_else(|| #krate::ConversionError::MissingField(
401 #krate::__private::String::from(#field_name_str)
402 ))?;
403 <#field_type as #krate::__private::TryFrom<#krate::Value>>::try_from(field_value)
404 .map_err(|e| #krate::ConversionError::FieldError(
405 #krate::__private::String::from(#field_name_str),
406 #krate::__private::Box::new(e)
407 ))?
408 }
409 }
410 }).collect();
411
412 quote! {
413 #tag => {
414 if payload.len() != 1 {
416 return #krate::__private::Err(#krate::ConversionError::WrongFieldCount {
417 expected: 1,
418 got: payload.len(),
419 });
420 }
421 match &payload[0] {
422 #krate::Value::Record { fields: record_fields, .. } => {
423 #krate::__private::Ok(#name::#variant_name {
424 #(#field_from_value),*
425 })
426 }
427 other => #krate::__private::Err(#krate::ConversionError::ExpectedRecord(
428 #krate::__private::format!("{:?}", other)
429 )),
430 }
431 }
432 }
433 }
434 Fields::Unnamed(fields) => {
435 let field_count = fields.unnamed.len();
436 let field_conversions: Vec<_> = fields.unnamed.iter().enumerate().map(|(i, f)| {
437 let field_type = &f.ty;
438 quote! {
439 <#field_type as #krate::__private::TryFrom<#krate::Value>>::try_from(
440 payload.get(#i).cloned().ok_or_else(|| #krate::ConversionError::MissingIndex(#i))?
441 ).map_err(|e| #krate::ConversionError::IndexError(#i, #krate::__private::Box::new(e)))?
442 }
443 }).collect();
444
445 quote! {
446 #tag => {
447 if payload.len() != #field_count {
448 return #krate::__private::Err(#krate::ConversionError::WrongFieldCount {
449 expected: #field_count,
450 got: payload.len(),
451 });
452 }
453 #krate::__private::Ok(#name::#variant_name(
454 #(#field_conversions),*
455 ))
456 }
457 }
458 }
459 Fields::Unit => {
460 quote! {
461 #tag => {
462 if !payload.is_empty() {
463 return #krate::__private::Err(#krate::ConversionError::UnexpectedPayload);
464 }
465 #krate::__private::Ok(#name::#variant_name)
466 }
467 }
468 }
469 }
470 }).collect();
471
472 let variant_count = data.variants.len();
473
474 quote! {
475 impl #impl_generics #krate::__private::From<#name #ty_generics> for #krate::Value #where_clause {
476 fn from(value: #name #ty_generics) -> #krate::Value {
477 match value {
478 #(#to_value_arms),*
479 }
480 }
481 }
482
483 impl #impl_generics #krate::__private::TryFrom<#krate::Value> for #name #ty_generics #where_clause {
484 type Error = #krate::ConversionError;
485
486 fn try_from(value: #krate::Value) -> #krate::__private::Result<Self, Self::Error> {
487 match value {
488 #krate::Value::Variant { tag, payload, .. } => {
489 match tag {
490 #(#from_value_arms),*
491 other => #krate::__private::Err(#krate::ConversionError::UnknownTag {
492 tag: other,
493 max: #variant_count,
494 }),
495 }
496 }
497 other => #krate::__private::Err(#krate::ConversionError::ExpectedVariant(
498 #krate::__private::format!("{:?}", other)
499 )),
500 }
501 }
502 }
503 }
504}
505
506fn get_rename(attrs: &[Attribute]) -> Option<String> {
508 for attr in attrs {
509 if attr.path().is_ident("graph") {
510 if let Meta::List(list) = &attr.meta {
511 let tokens = list.tokens.to_string();
512 if let Some(rest) = tokens.strip_prefix("rename") {
514 let rest = rest.trim();
515 if let Some(rest) = rest.strip_prefix('=') {
516 let rest = rest.trim();
517 if rest.starts_with('"') && rest.ends_with('"') {
518 return Some(rest[1..rest.len() - 1].to_string());
519 }
520 }
521 }
522 }
523 }
524 }
525 None
526}
527
528fn get_tag(attrs: &[Attribute]) -> Option<usize> {
530 for attr in attrs {
531 if attr.path().is_ident("graph") {
532 if let Meta::List(list) = &attr.meta {
533 let tokens = list.tokens.to_string();
534 if let Some(rest) = tokens.strip_prefix("tag") {
536 let rest = rest.trim();
537 if let Some(rest) = rest.strip_prefix('=') {
538 let rest = rest.trim();
539 return rest.parse().ok();
540 }
541 }
542 }
543 }
544 }
545 None
546}