Skip to content

Commit

Permalink
data.frame: First, rename trait IntoDataFrameRow to IntoDataframe
Browse files Browse the repository at this point in the history
First, using `isFrame` for Robj conversion.

Keep `IntoDataFrameRow` as a derive-macro.

Add a note about missing features.

Added `IntoRobj` for `Dataframe<T>`
  • Loading branch information
CGMossa committed Apr 6, 2024
1 parent 62269d1 commit 2c6cc19
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 13 deletions.
2 changes: 1 addition & 1 deletion extendr-api/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub use super::thread_safety::{catch_r_error, handle_panic, single_threaded, thr

pub use super::wrapper::{
Complexes, Dataframe, Doubles, EnvIter, Environment, Expressions, ExternalPtr, FromList,
Function, Integers, IntoDataFrameRow, Language, List, ListIter, Logicals, Nullable, Pairlist,
Function, Integers, IntoDataframe, Language, List, ListIter, Logicals, Nullable, Pairlist,
Primitive, Promise, Raw, Rstr, Strings, Symbol,
};

Expand Down
29 changes: 20 additions & 9 deletions extendr-api/src/wrapper/dataframe.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
//! This provides an abstraction for R's `data.frame`-constructor in Rust.
//! For a given `struct` say `CustomRow`, one may implement or derive [`IntoDataFrameRow`],
//! thus being able to convert `Vec<CustomRow>` to an instance of `Dataframe<CustomRow>`,
//! see [`Dataframe`].
//!
//!
//! [`IntoDataFrameRow`]: ::extendr_macros::IntoDataFrameRow
use super::*;

pub trait IntoDataFrameRow<T> {
/// A trait to convert a collection of `IntoDataFrameRow` into
/// [`Dataframe`]. Typical usage involves using the derive-macro [`IntoDataFrameRow`]
/// on a struct, which would generate `impl IntoDataframe<T> for Vec<T>`.
///
/// [`IntoDataFrameRow`]: ::extendr_macros::IntoDataFrameRow
pub trait IntoDataframe<T> {
fn into_dataframe(self) -> Result<Dataframe<T>>;
}

Expand All @@ -14,14 +26,13 @@ impl<T> std::convert::TryFrom<&Robj> for Dataframe<T> {
type Error = Error;
fn try_from(robj: &Robj) -> Result<Self> {
// TODO: check type using derived trait.
if robj.is_list() && robj.inherits("data.frame") {
Ok(Dataframe {
robj: robj.clone(),
marker: std::marker::PhantomData,
})
} else {
Err(Error::ExpectedDataframe(robj.clone()))
if !robj.is_frame() {
return Err(Error::ExpectedDataframe(robj.clone()));
}
Ok(Dataframe {
robj: robj.clone(),
marker: std::marker::PhantomData,
})
}
}

Expand All @@ -34,7 +45,7 @@ impl<T> std::convert::TryFrom<Robj> for Dataframe<T> {

impl<T> Dataframe<T> {
/// Use `#[derive(IntoDataFrameRow)]` to use this.
pub fn try_from_values<I: IntoDataFrameRow<T>>(iter: I) -> Result<Self> {
pub fn try_from_values<I: IntoDataframe<T>>(iter: I) -> Result<Self> {
iter.into_dataframe()
}
}
Expand Down
2 changes: 1 addition & 1 deletion extendr-api/src/wrapper/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub use altrep::{
AltrepImpl,
};
pub use complexes::Complexes;
pub use dataframe::{Dataframe, IntoDataFrameRow};
pub use dataframe::{Dataframe, IntoDataframe};
pub use doubles::Doubles;
pub use environment::{EnvIter, Environment};
pub use expr::Expressions;
Expand Down
12 changes: 10 additions & 2 deletions extendr-macros/src/dataframe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@ use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DataStruct, DeriveInput};

//TODO: Add these options to the macro:
// data.frame(..., row.names = NULL, check.rows = FALSE,
// check.names = TRUE, fix.empty.names = TRUE,
// stringsAsFactors = FALSE)
//
// First, ensure that these names aren't fields in the struct.
// Then include them.

fn derive_struct_into_dataframe(input: &DeriveInput, datastruct: &DataStruct) -> TokenStream {
let structname = &input.ident;
let mut a = Vec::new();
for f in &datastruct.fields {
a.push(f.ident.clone());
}
quote! {
impl IntoDataFrameRow<#structname> for Vec<#structname>
impl IntoDataframe<#structname> for Vec<#structname>
{
fn into_dataframe(self) -> Result<Dataframe<#structname>> {
#(let mut #a = Vec::with_capacity(self.len());)*
Expand All @@ -24,7 +32,7 @@ fn derive_struct_into_dataframe(input: &DeriveInput, datastruct: &DataStruct) ->
}
}

impl<I> IntoDataFrameRow<#structname> for (I,)
impl<I> IntoDataframe<#structname> for (I,)
where
I: ExactSizeIterator<Item = #structname>,
{
Expand Down

0 comments on commit 2c6cc19

Please sign in to comment.