extendr_macros/
dataframe.rs1use proc_macro::TokenStream;
2use proc_macro2::Span;
3use quote::quote;
4use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Ident};
5
6fn parse_struct(input: &DeriveInput, datastruct: &DataStruct) -> TokenStream {
7 let structname = &input.ident;
8 let mut a = Vec::new();
9 for f in &datastruct.fields {
10 a.push(f.ident.clone());
11 }
12 let row = Ident::new("row", Span::mixed_site());
13 let caller = Ident::new("caller", Span::mixed_site());
14 let res = Ident::new("res", Span::mixed_site());
15 quote! {
16 impl extendr_api::wrapper::IntoDataFrameRow<#structname> for Vec<#structname>
17 {
18 fn into_dataframe(self) -> extendr_api::Result<extendr_api::wrapper::Dataframe<#structname>> {
19 #(let mut #a = Vec::with_capacity(self.len());)*
20 for #row in self {
21 #(#a.push(#row.#a);)*
22 }
23 let #caller = extendr_api::functions::eval_string("data.frame")?;
24 let #res = #caller.call(extendr_api::wrapper::Pairlist::from_pairs(&[
25 #((stringify!(#a), extendr_api::robj::Robj::from(#a))),*
26 ]))?;
27 #res.try_into()
28 }
29 }
30
31 impl<I> extendr_api::wrapper::IntoDataFrameRow<#structname> for (I,)
32 where
33 I : ExactSizeIterator<Item=#structname>,
34 {
35 fn into_dataframe(self) -> extendr_api::Result<extendr_api::wrapper::Dataframe<#structname>> {
37 #(let mut #a = Vec::with_capacity(self.0.len());)*
38 for #row in self.0 {
39 #(#a.push(#row.#a);)*
40 }
41 let #caller = extendr_api::functions::eval_string("data.frame")?;
42 let #res = #caller.call(extendr_api::wrapper::Pairlist::from_pairs(&[
43 #((stringify!(#a), extendr_api::robj::Robj::from(#a))),*
44 ]))?;
45 #res.try_into()
46 }
47 }
48 }
49 .into()
50}
51
52pub fn derive_into_dataframe(item: TokenStream) -> TokenStream {
53 let input: DeriveInput = parse_macro_input!(item as DeriveInput);
54
55 match &input.data {
56 Data::Struct(datastruct) => parse_struct(&input, datastruct),
57 _ => quote!(compile_error("IntoDataFrameRow expected a struct.")).into(),
58 }
59}