extendr_macros/
list_struct.rsuse proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{Data, DeriveInput};
pub fn derive_try_from_robj(item: TokenStream) -> syn::parse::Result<TokenStream> {
let ast = syn::parse::<DeriveInput>(item)?;
let inside = if let Data::Struct(inner) = ast.data {
inner
} else {
return Err(syn::Error::new_spanned(ast, "Only struct is supported"));
};
let struct_name = ast.ident;
let mut tokens = Vec::<TokenStream2>::with_capacity(inside.fields.len());
for field in inside.fields {
let field_name = field.ident.as_ref().unwrap();
let field_str = field_name.to_string();
tokens.push(quote!(
#field_name: value.dollar(#field_str)?.try_into()?
));
}
Ok(TokenStream::from(quote!(
impl std::convert::TryFrom<&extendr_api::Robj> for #struct_name {
type Error = extendr_api::Error;
fn try_from(value: &extendr_api::Robj) -> extendr_api::Result<Self> {
Ok(#struct_name {
#(#tokens),*
})
}
}
impl std::convert::TryFrom<extendr_api::Robj> for #struct_name {
type Error = extendr_api::Error;
fn try_from(value: extendr_api::Robj) -> extendr_api::Result<Self> {
Ok(#struct_name {
#(#tokens),*
})
}
}
)))
}
pub fn derive_into_robj(item: TokenStream) -> syn::parse::Result<TokenStream> {
let ast = syn::parse::<DeriveInput>(item)?;
let inside = if let Data::Struct(inner) = ast.data {
inner
} else {
return Err(syn::Error::new_spanned(ast, "Only struct is supported"));
};
let struct_name = ast.ident;
let mut tokens = Vec::<TokenStream2>::with_capacity(inside.fields.len());
for field in inside.fields {
let field_name = field.ident.as_ref().unwrap();
let field_str = field_name.to_string();
tokens.push(quote!(
(#field_str, (&value.#field_name).into())
));
}
Ok(TokenStream::from(quote!(
impl std::convert::From<&#struct_name> for extendr_api::Robj {
fn from(value: &#struct_name) -> Self {
extendr_api::List::from_pairs([#(#tokens),*]).into()
}
}
impl std::convert::From<#struct_name> for extendr_api::Robj {
fn from(value: #struct_name) -> Self {
extendr_api::List::from_pairs([#(#tokens),*]).into()
}
}
)))
}