extendr_macros::extendr_impl

Function extendr_impl

Source
pub(crate) fn extendr_impl(
    item_impl: ItemImpl,
    opts: &ExtendrOptions,
) -> Result<TokenStream>
Expand description

Make inherent implementations available to R

The extendr_impl function is used to make inherent implementations available to R as an environment. By adding the [macro@extendr] attribute macro to an impl block (supported with enums and structs), the methods in the impl block are made available as functions in an environment.

On the R side, an environment with the same name of the inherent implementation is created. The environment has functions within it that correspond to each method in the impl block. Note that in order for an impl block to be compatible with extendr (and thus R), its return type must be able to be returned to R. For example, any struct that might be returned must also have an #[extendr] annotated impl block.

Example:

use extendr_api::prelude::*;

// a struct that will be used internal the People struct
#[derive(Clone, Debug, IntoDataFrameRow)]
struct Person {
    name: String,
    age: i32,
}

// This will collect people in the struct
#[extendr]
#[derive(Clone, Debug)]
struct People(Vec<Person>);

#[extendr]
/// @export
impl People {
    // instantiate a new struct with an empty vector
    fn new() -> Self {
        let vec: Vec<Person> = Vec::new();
        Self(vec)
    }

    // add a person to the internal vector
    fn add_person(&mut self, name: &str, age: i32) -> &mut Self {
        let person = Person {
            name: String::from(name),
            age: age,
        };

        self.0.push(person);

        // return self
        self
    }
     
    // Convert the struct into a data.frame
    fn into_df(&self) -> Robj {
        let df = self.0.clone().into_dataframe();

        match df {
            Ok(df) => df.as_robj().clone(),
            Err(_) => data_frame!(),
        }
    }

    // add another `People` struct to self
    fn add_people(&mut self, others: &People) -> &mut Self {
        self.0.extend(others.0.clone().into_iter());
        self
    }

    // create a function to print the self which can be called
    // from an R print method
    fn print_self(&self) -> String {
        format!("{:?}", self.0)
    }
}

// Macro to generate exports.
// This ensures exported functions are registered with R.
// See corresponding C code in `entrypoint.c`.
extendr_module! {
    mod testself;
    impl People;
}