extendr - A safe and user friendly R extension interface using Rust

Extendr is a Rust extension mechanism for R

The following code illustrates a simple structure trait which is written in Rust. The data is defined in the struct declaration and the methods in the impl.

Extendr consists of the following projects:

  • extendr set of crates, including:
    • extendr-api - the core Extendr crate providing all of the functionality;
    • extendr-macros - Extendr crate responsbile for Rust wrapper generation;
    • extendr-engine - crate that enables launching R sessions from Rust code;
  • rextendr - an R package that helps scaffolding extendr-enabled packages or compiling Rust code dynamically;
  • libR-sys - provides auto-generated R bindings for Rust.
use extendr_api::prelude::*;

struct Person {
    pub name: String,

impl Person {
    fn new() -> Self {
        Self { name: "".to_string() }

    fn set_name(&mut self, name: &str) {
        self.name = name.to_string();

    fn name(&self) -> &str {

fn aux_func() {

// Macro to generate exports
extendr_module! {
    mod classes;
    impl Person;
    fn aux_func;

The #[extendr] attribute causes the compiler to generate wrapper and registration functions for R which are called when the package is loaded.

On R’s side, users can access to the above Rust functions as follows:

# call function

# create Person object
p <- Person$new()
p$name()   # "foo" is returned

The extendr_module! macro lists the module name and exported functions and interfaces.

This library aims to provide an interface that will be familiar to first-time users of Rust or indeed any compiled language.

Anyone who knows the R library should be able to write R extensions.

Wrappers for R types

Extendr provides a number of wrappers for R types. These fall into three categories, scalar types such as a single integer, vector types which are an array of a scalar type and linked list types used to represent R code and call arguments.

Scalar types

R type Extendr wrapper Deref type: &*object
Any extendr_api::robj::Robj N/A
character extendr_api::wrapper::Rstr N/A
integer extendr_api::wrapper::Rint N/A
double extendr_api::wrapper::Rfloat N/A
complex extendr_api::wrapper::Rcplx N/A
extptr extendr_api::wrapper::ExternalPtr<T> &T / &mut T

Vector types

R type Extendr wrapper Deref type: &*object
integer extendr_api::wrapper::Integers &[Rint]
double extendr_api::wrapper::Doubles &[Rfloat]
logical extendr_api::wrapper::Logicals &[Rbool]
complex extendr_api::wrapper::Complexes &[Rcplx]
string extendr_api::wrapper::Strings &[Rstr]
list extendr_api::wrapper::List &[Robj]
data.frame extendr_api::wrapper::Dataframe<T> &[Robj]
expression extendr_api::wrapper::Expression &[Lang]

Linked list types

R type Extendr wrapper Deref type: &*object
pairlist extendr_api::wrapper::Pairlist N/A
lang extendr_api::wrapper::Lang N/A


Returning lists and strings

Lists and strings in rust are vectors of R objects. These are represented by the wrappers List and Strings.

List contains a slice of Robj wrappers which can contain any R object.

Strings contains a slice of Rstr wrappers which can contain a single string.

These examples show how to return a list or string to R from Rust.

use extendr_api::wrapper::{List, Strings};
use extendr_api::list;

fn get_strings() -> Strings {
        .map(|i| format!("number {}", i))

fn get_named_list() -> List {
    list!(x=1, y="xyz", z=())

fn get_unnamed_list() -> List {

Returning scalars

Whilst we can use i32 and f64 in Extendr to return values. A better way is to use the Rint and Rfloat wrappers which provide access to the NA value used by R to represent missing data.

use extendr_api::scalar::{Rint, Rfloat};

// for .na()
use extendr_api::CanBeNA;

fn get_int() -> Rint {

fn get_na_int() -> Rint {

fn get_float() -> Rfloat {

fn get_na_float() -> Rfloat {

Plotting a PNG file from Rust

We can use Extendr to take advantage of the stats and plotting functions in R.

For example, we could make a web server that returns plots of incoming data.

use extendr_api::{test, Result, eval_string, eval_string_with_params};
use extendr_api::{Doubles, R};

fn main() {
        let x = Doubles::from_values((0..100).map(|i| i as f64 / 20.0));

        // let y = Doubles::from_values(x.iter().map(|x| x.inner().sin()));
        let y = Doubles::from_values((0..100).map(|i| (i as f64 / 20.0).sin()));

        // Set a PNG device

        // Plot x and y
        R!("plot({{&x}}, {{&y}})")?;

        // Linear model.
        R!("abline(lm({{y}} ~ {{x}}))")?;

        // Flush the device to the image.

  • Extendr logo


Dev status

  • Github Actions Build Status
  • Crates.io
  • Documentation
  • License: MIT


  • Andy Thomason
    Author, maintainer
  • Mossa M. Reimert
  • Claus O. Wilke
  • Hiroaki Yutani
  • Ilia Kosenkov
  • Daniel Falbel
  • Genomics Plc
    Copyright holder