Skip to content

Commit

Permalink
simplify front page (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
kbvernon authored Jul 3, 2024
1 parent 9acd81b commit b558376
Showing 1 changed file with 38 additions and 162 deletions.
200 changes: 38 additions & 162 deletions index.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
title: ""
---

:::::: {style="margin:0; width: 100%;"}
::: {style="margin:0; width: 100%;"}
::: {style="margin:0; width: 81%; float: left;"}
## extendr - A safe and user friendly R extension interface using Rust
:::

::: {style="margin: 0.25rem 0 0 0; width: 19%; float: right;"}
![](images/extendr-logo-256.png){width="100%" fig-alt="rextendr logo"}
:::
::::::
:::

[![Github Actions Build
Status](https://github.com/extendr/extendr/workflows/Tests/badge.svg)](https://github.com/extendr/extendr/actions)
Expand All @@ -18,29 +19,15 @@ Status](https://github.com/extendr/extendr/workflows/Tests/badge.svg)](https://g
[![License:
MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

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`](https://extendr.github.io/extendr) set of crates, including:
- [`extendr-api`](https://extendr.github.io/extendr/extendr_api) - the
core Extendr crate providing all of the functionality;
- [`extendr-macros`](https://extendr.github.io/extendr/extendr_macros) -
Extendr crate responsbile for Rust wrapper generation;
- [`extendr-engine`](https://extendr.github.io/extendr/extendr_engine) -
crate that enables launching R sessions from Rust code;
- [`rextendr`](https://extendr.github.io/rextendr) - an R package that helps
scaffolding extendr-enabled packages or compiling Rust code dynamically;
- [`libR-sys`](https://extendr.github.io/libR-sys/libR_sys) - provides
auto-generated R bindings for Rust.
The extendr suite of software packages provides a Rust extension mechanism for
R, thus bringing the computing power of Rust to the statistical programming
environment of R. The following code provides a simple illustration of how
extendr achieves this.

``` rust
use extendr_api::prelude::*;

#[derive(Debug)]
struct Person {
pub name: String,
}
Expand All @@ -61,169 +48,58 @@ impl Person {
}

#[extendr]
fn aux_func() {
}

fn my_function() { }

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

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:
registration functions for R which are called when the package is loaded, thus
allowing one to access Rust functions and structures in an R session:

``` r
# call function
aux_func()
my_function()

# create Person object
p <- Person$new()
p$set_name("foo")
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 |

## Examples

### 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.

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

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

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

fn get_unnamed_list() -> List {
List::from_values(0..10)
}
```

### 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.

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

// for .na()
use extendr_api::CanBeNA;
This, of course, is just the tip of the iceberg, for there are many ways to use
extendr in R:

fn get_int() -> Rint {
Rint::from(1)
}
- In an interactive R session one may use [`rextendr::rust_function` and
friends](https://extendr.github.io/rextendr/reference/rust_source.html) to
quickly prototype Rust code.

fn get_na_int() -> Rint {
Rint::na()
}
- In an R package context, one may use
[`rextendr::use_extendr()`](https://extendr.github.io/rextendr/reference/use_extendr.html)
to setup a Rust powered R-package. See also the [vignette on
R-packages](https://extendr.github.io/rextendr/articles/package.html).

fn get_float() -> Rfloat {
Rfloat::from(1.0)
}
- It is also possible to inline Rust code in `Quarto` documents, see
[vignette on extendr
`knitr-engine`](https://extendr.github.io/rextendr/articles/rmarkdown.html).

fn get_na_float() -> Rfloat {
Rfloat::na()
}
```

### Plotting a PNG file from Rust
## Software Overview

We can use Extendr to take advantage of the stats and plotting functions in R.
The software packages that make up extendr include:

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

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

fn main() {
test!{
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
R!(r#"png("/tmp/sin_plot.png")"#)?;

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

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

// Flush the device to the image.
R!("dev.off()")?;
}
}
```
- Rust crates:
- [`extendr-api`](https://extendr.github.io/extendr/extendr_api) - the
core Extendr crate providing all of the functionality;
- [`extendr-macros`](https://extendr.github.io/extendr/extendr_macros) -
Extendr crate responsbile for Rust wrapper generation;
- [`extendr-engine`](https://extendr.github.io/extendr/extendr_engine) -
crate that enables launching R sessions from Rust code;
- An R package [`rextendr`](https://extendr.github.io/rextendr) that helps
scaffolding extendr-enabled packages or compiling Rust code dynamically; and
- [`libR-sys`](https://extendr.github.io/libR-sys/libR_sys) - provides
auto-generated R bindings for Rust.

0 comments on commit b558376

Please sign in to comment.