extendr_macros/
list_struct.rs
1use proc_macro::TokenStream;
2use proc_macro2::TokenStream as TokenStream2;
3use quote::quote;
4use syn::{Data, DeriveInput};
5
6pub fn derive_try_from_robj(item: TokenStream) -> syn::parse::Result<TokenStream> {
8 let ast = syn::parse::<DeriveInput>(item)?;
10 let inside = if let Data::Struct(inner) = ast.data {
11 inner
12 } else {
13 return Err(syn::Error::new_spanned(ast, "Only struct is supported"));
14 };
15 let struct_name = ast.ident;
16
17 let mut tokens = Vec::<TokenStream2>::with_capacity(inside.fields.len());
19 for field in inside.fields {
20 let field_name = field.ident.as_ref().unwrap();
21 let field_str = field_name.to_string();
22 tokens.push(quote!(
24 #field_name: value.dollar(#field_str)?.try_into()?
25 ));
26 }
27
28 Ok(TokenStream::from(quote!(
30 impl std::convert::TryFrom<&extendr_api::Robj> for #struct_name {
31 type Error = extendr_api::Error;
32
33 fn try_from(value: &extendr_api::Robj) -> extendr_api::Result<Self> {
34 Ok(#struct_name {
35 #(#tokens),*
36 })
37 }
38 }
39
40 impl std::convert::TryFrom<extendr_api::Robj> for #struct_name {
41 type Error = extendr_api::Error;
42
43 fn try_from(value: extendr_api::Robj) -> extendr_api::Result<Self> {
44 Ok(#struct_name {
45 #(#tokens),*
46 })
47 }
48 }
49 )))
50}
51
52pub fn derive_into_robj(item: TokenStream) -> syn::parse::Result<TokenStream> {
54 let ast = syn::parse::<DeriveInput>(item)?;
56 let inside = if let Data::Struct(inner) = ast.data {
57 inner
58 } else {
59 return Err(syn::Error::new_spanned(ast, "Only struct is supported"));
60 };
61 let struct_name = ast.ident;
62
63 let mut tokens = Vec::<TokenStream2>::with_capacity(inside.fields.len());
66
67 for field in inside.fields {
68 let field_name = field.ident.as_ref().unwrap();
69 let field_str = field_name.to_string();
70 tokens.push(quote!(
71 (#field_str, (&value.#field_name).into())
72 ));
73 }
74
75 Ok(TokenStream::from(quote!(
77 impl std::convert::From<&#struct_name> for extendr_api::Robj {
78 fn from(value: &#struct_name) -> Self {
79 extendr_api::List::from_pairs([#(#tokens),*]).into()
80 }
81 }
82 impl std::convert::From<#struct_name> for extendr_api::Robj {
83 fn from(value: #struct_name) -> Self {
84 extendr_api::List::from_pairs([#(#tokens),*]).into()
85 }
86 }
87 )))
88}