minirextendr is a pure-R companion package that scaffolds, builds, and maintains R packages using the miniextendr Rust-R framework. Think of it as usethis for miniextendr projects.

Location: minirextendr/ in the monorepo.

πŸ”—Installation

# From the monorepo:
just minirextendr-install

# Or directly:
R CMD INSTALL minirextendr

πŸ”—Creating Projects

πŸ”—Standalone R Package

library(minirextendr)
create_miniextendr_package("mypackage")

Creates a complete R package with Rust backend:

mypackage/
β”œβ”€β”€ DESCRIPTION          # Config/build/bootstrap: TRUE
β”œβ”€β”€ NAMESPACE
β”œβ”€β”€ R/
β”œβ”€β”€ configure.ac         # Autoconf source
β”œβ”€β”€ configure            # Generated by autoconf
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ rust/
β”‚   β”‚   β”œβ”€β”€ Cargo.toml   # Rust dependencies
β”‚   β”‚   β”œβ”€β”€ lib.rs       # Your Rust code
β”‚   β”‚   β”œβ”€β”€ build.rs     # Build-time lint
β”‚   β”œβ”€β”€ stub.c            # Minimal C stub for R linker
β”‚   β”œβ”€β”€ Makevars.in
β”‚   └── win.def.in
β”œβ”€β”€ vendor/              # Vendored miniextendr crates
└── tools/               # config.guess, config.sub

πŸ”—Monorepo (Workspace)

create_miniextendr_monorepo("myproject",
  package = "mypkg",
  crate_name = "mypkg-rs"
)

Creates a Cargo workspace with a separate Rust crate alongside the R package:

myproject/
β”œβ”€β”€ Cargo.toml           # Workspace root
β”œβ”€β”€ mypkg-rs/            # Main Rust crate
β”‚   β”œβ”€β”€ Cargo.toml
β”‚   └── src/lib.rs
β”œβ”€β”€ mypkg/               # Generated R package
β”‚   β”œβ”€β”€ src/rust/        # R-facing Rust bindings
β”‚   └── vendor/
β”œβ”€β”€ tools/               # Version management scripts
β”‚   └── bump-version.R
└── justfile

To vendor from a specific GitHub tag instead of the default ("main"):

create_miniextendr_monorepo("myproject",
  miniextendr_version = "v0.1.0"
)

πŸ”—Build Workflow

devtools::document() handles the entire pipeline automatically:

devtools::document("mypackage")   # Compiles Rust + generates R wrappers + runs roxygen2
devtools::install("mypackage")    # Install the final package

How it works: devtools::document() calls pkgload::load_all(), which detects Config/build/bootstrap: TRUE in DESCRIPTION and runs bootstrap.R. That triggers ./configure β†’ make β†’ cargo build β†’ document binary β†’ R wrappers β†’ roxygen2, all in a single invocation. No manual ./configure or two-pass install needed.

πŸ”—Manual: step-by-step functions

For fine-grained control or when not using devtools:

miniextendr_autoconf(path = "mypackage")   # autoconf β†’ generate configure
miniextendr_configure(path = "mypackage")  # ./configure β†’ generate Makevars
miniextendr_build(path = "mypackage")      # R CMD INSTALL
miniextendr_document(path = "mypackage")   # devtools::document (regenerate wrappers)

πŸ”—One-Shot Sync

miniextendr_sync() detects staleness and rebuilds only what’s needed:

miniextendr_sync(path = ".", mode = "if_stale", stage = "install")

Modes: "if_stale" (default), "always", "never". Stages: "install" (default), "wrappers", "build".

πŸ”—Inline Rust Compilation

Compile Rust code on the fly without an existing package (like Rcpp’s sourceCpp()):

# Single function β€” auto-wraps with imports and module block
rust_function('
#[miniextendr]
pub fn add_one(x: i32) -> i32 { x + 1 }
')
add_one(41L)
#> [1] 42

# Vectors work too
rust_function('
#[miniextendr]
pub fn double_vec(x: Vec<f64>) -> Vec<f64> {
    x.into_iter().map(|v| v * 2.0).collect()
}
')
double_vec(c(1.0, 2.5, 3.0))
#> [1] 2.0 5.0 6.0

# Full source with multiple functions
rust_source(code = '
use miniextendr_api::miniextendr;

#[miniextendr]
pub fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

#[miniextendr]
pub fn add(a: f64, b: f64) -> f64 { a + b }
// Registration is automatic via #[miniextendr].
')
greet("world")
#> [1] "Hello, world!"
add(1.5, 2.5)
#> [1] 4

πŸ”—Caching

Results are MD5-cached: same code + features = instant reload. Calling the same rust_function() or rust_source() a second time skips compilation entirely.

# First call: compiles (~10-20s)
rust_function('#[miniextendr] pub fn sq(x: f64) -> f64 { x * x }')

# Second call: instant (cache hit)
rust_function('#[miniextendr] pub fn sq(x: f64) -> f64 { x * x }')

# Clear all cached compilations
rust_source_clean()

πŸ”—Cargo Wrappers

Thin wrappers around cargo that target the package’s src/rust/ directory:

FunctionCargo command
cargo_build()cargo build
cargo_check()cargo check
cargo_test()cargo test
cargo_clippy()cargo clippy
cargo_fmt()cargo fmt
cargo_doc()cargo doc
cargo_add("serde")cargo add serde
cargo_rm("serde")cargo rm serde
cargo_deps()cargo tree
cargo_search("regex")cargo search regex
cargo_update()cargo update

All accept path (default ".") and ... for extra arguments.

Note: cargo_fmt("--check") may report formatting diffs in vendored crates. This is expected β€” vendored code isn’t subject to local formatting rules.

πŸ”—Feature Scaffolding

Add optional miniextendr features with proper Cargo.toml and R-side setup:

use_rayon()             # Parallel iteration
use_serde()             # Serde-based R ↔ Rust serialization
use_vctrs()             # vctrs integration
use_r6()                # R6 class system
use_s4()                # S4 class system
use_s7()                # S7 class system
use_feature_detection() # Conditional compilation via feature flags
use_vendor_lib()        # Vendor external Rust library for monorepo use

Each use_*() function:

  1. Adds the Cargo feature to src/rust/Cargo.toml
  2. Sets up any needed R-side dependencies (e.g., R6, S7 packages)
  3. Updates miniextendr.yml configuration

πŸ”—Feature Detection

use_feature_detection() sets up conditional compilation via R-detected feature flags:

# Initial setup β€” creates detect-features.R and wires it into configure.ac
use_feature_detection()

# After adding new features to miniextendr.yml, regenerate the detection script
update_feature_detection()

Features are detected at ./configure time and passed as --cfg flags to rustc.

πŸ”—Vendoring

# Vendor miniextendr crates from local monorepo
vendor_miniextendr(local_path = "/path/to/miniextendr")

# Vendor miniextendr crates from GitHub release
vendor_miniextendr(version = "0.1.0")

# Vendor external crates from crates.io
vendor_crates_io(path = "mypackage")

# Check vendor freshness
vendor_sync(path = "mypackage")

# List available versions
miniextendr_available_versions()

πŸ”—Diagnostics

has_miniextendr("mypackage")        # TRUE/FALSE β€” is this a miniextendr package?
miniextendr_status(path = ".")      # Show file status (present, stale, missing)
miniextendr_validate(path = ".")    # Validate project consistency
miniextendr_doctor(path = ".")      # Comprehensive health check
miniextendr_check_rust()            # Verify Rust toolchain is available

miniextendr_status() reports each build artifact’s state (present, stale, or missing). miniextendr_validate() checks structural consistency (DESCRIPTION fields, module declarations, etc.). miniextendr_doctor() runs the full suite including Rust toolchain checks.

Note: In monorepo mode, miniextendr_doctor() may report false-positive vendor warnings because vendored crates are resolved differently via [patch] in the workspace.

πŸ”—Configuration

miniextendr.yml in the package root for project-level settings:

mx_config(path = ".")              # Read current config (returns named list)
mx_config_defaults()               # Show all defaults with descriptions

mx_config() merges project-level miniextendr.yml with built-in defaults. Settings include feature flags, class system choices, and build options. mx_config_defaults() lists every available setting with its default value.

πŸ”—knitr / Rmarkdown / Quarto Integration

πŸ”—Package Mode (in a package vignette)

# In a setup chunk:
miniextendr_knitr_setup()          # Syncs and registers {miniextendr} engine

Then use {miniextendr} chunks that evaluate as R code (the package is already built).

πŸ”—Inline Mode (self-contained vignettes)

# In a setup chunk:
miniextendr_knitr_setup(path = NULL)

Each {miniextendr} chunk compiles Rust code via rust_source() and loads functions into the knitr environment. No existing package required.

πŸ”—Render Helpers

Custom output formats that auto-sync before rendering:

# In YAML front matter:
output: minirextendr::miniextendr_html_document
output: minirextendr::miniextendr_pdf_document
output: minirextendr::miniextendr_word_document

For Quarto, use as a pre-render script:

# In _quarto.yml:
pre-render: Rscript -e "minirextendr::miniextendr_quarto_pre_render()"

πŸ”—Upgrading Existing Packages

upgrade_miniextendr_package(path = "mypackage")

Updates templates, vendored crates, and configure.ac to match the latest minirextendr version.

πŸ”—Caching

miniextendr_cache_info()     # Show cache location and size
miniextendr_clear_cache()    # Clear all caches

Cache location: rappdirs::user_cache_dir("minirextendr").

πŸ”—Exported Functions Reference

CategoryFunctions
Project creationcreate_miniextendr_package, create_miniextendr_monorepo
Build workflowminiextendr_autoconf, miniextendr_configure, miniextendr_build, miniextendr_document, miniextendr_sync
Inline compilationrust_source, rust_function, rust_source_clean
Cargo wrapperscargo_add, cargo_rm, cargo_build, cargo_check, cargo_test, cargo_clippy, cargo_fmt, cargo_doc, cargo_search, cargo_deps, cargo_update, cargo_init, cargo_new
Feature scaffoldinguse_miniextendr, use_rayon, use_serde, use_vctrs, use_r6, use_s4, use_s7, use_feature_detection, update_feature_detection, use_vendor_lib
Vendoringvendor_miniextendr, vendor_crates_io, vendor_sync, miniextendr_vendor, miniextendr_available_versions
Diagnosticshas_miniextendr, miniextendr_status, miniextendr_validate, miniextendr_doctor, miniextendr_check_rust
Configurationmx_config, mx_config_defaults
knitr/renderminiextendr_knitr_setup, miniextendr_html_document, miniextendr_pdf_document, miniextendr_word_document, miniextendr_quarto_pre_render, use_miniextendr_knitr, use_miniextendr_rmarkdown, use_miniextendr_quarto
Cacheminiextendr_cache_info, miniextendr_clear_cache
Upgradeupgrade_miniextendr_package
Dev helpersminiextendr_check, miniextendr_dev_link, miniextendr_check_rust, use_miniextendr_build_rs