Function extendr_macros::extendr_impl::extendr_impl

source ·
pub 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 avaialble to R as an environment. By adding the [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;
}

Known limitation: if you return &Self or &mut Self or a reference to the same type, the resultant R object will always be the original self. For example the below method will not return other.

 // This is not possible today
#[extendr]
impl People {
  fn return_other(&self, other: &'static T) -> &Self {
    other
  }
}