ワンクリックで
miniextendr-conversions
Use when passing values between R and Rust in a miniextendr package — choosing argument/return types for
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Use when passing values between R and Rust in a miniextendr package — choosing argument/return types for
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Use when the user asks how to expose a Rust struct as an R class, which R class system to use (R6 vs S3 vs S4 vs S7 vs Env vs Vctrs), how method dispatch works, how constructors are generated, how trait methods map to R, or when working in miniextendr-macros/src/miniextendr_impl/*.rs or miniextendr-macros/src/r_class_formatter.rs.
Use when the user asks about converting between R and Rust types, how TryFromSexp or IntoR work, what NA handling looks like, how strict mode differs from normal coercion, why Vec<i32> from an empty R vector panics, or how bool, Option<T>, or large integer types behave across the R-Rust boundary.
Use when the user asks about ExternalPtr, how Rust structs are stored as R objects, TypedExternal, Box<Box<dyn Any>> storage, pointer provenance for cached_ptr, the release_any finalizer, sidecar field accessors, the TYPE_NAME_CSTR vs TYPE_ID_CSTR distinction, or how to pass an ExternalPtr across crate or package boundaries.
Use when a new user asks how to start a miniextendr-backed R package from zero, how to scaffold via minirextendr::use_miniextendr(), what their first Rust function should look like, what the dev loop is, or "can I add Rust to an existing R package". Also use when someone is confused about which package is which (miniextendr vs minirextendr).
Use when the user asks how
Use when debugging configure.ac failures, Makevars issues, Cargo.lock mismatches, vendor tarball problems, build mode confusion, or the cdylib-to-staticlib double-link pipeline. Also use when changing a Makevars value, diagnosing a latch-leak, understanding the bash-vs-sh configure requirement, or working with m4 quoting in configure.ac.
| name | miniextendr-conversions |
| description | Use when passing values between R and Rust in a miniextendr package — choosing argument/return types for |
Every argument of a #[miniextendr] function is converted from an R value
(SEXP) to its Rust type; every return value is converted back. You never call
the conversion traits (TryFromSexp in, IntoR out) directly — you just
pick types, and the framework does the rest. Getting the types right is the
whole game.
| R type | Rust argument | Notes |
|---|---|---|
integer() | i32, Vec<i32>, &[i32] | NA_integer_ is an error unless Option |
double() | f64, Vec<f64>, &[f64] | NA_real_ passes through as an NA NaN |
logical() | bool (errors on NA) or RLogical (three-state) | |
character() | &str, String, Vec<String> | NA_character_ errors unless Option |
raw() | u8, Vec<u8> | |
| any + NA/NULL | Option<T> | NA and NULL both become None |
list() | Dots, typed structs via derives, SEXP | see the dataframe/classes skills |
Return types mirror the same table. &[T] / &str arguments borrow the R
data with no copy — prefer them for read-only inputs. No lifetime annotations
needed; explicit <'a> lifetimes are also fine (type/const generics are not).
i32 accepts only integer(), f64 only
double(). Mismatch → clear R error.i8, i16, u16, u32,
f32, i64, u64, isize, usize accept integer, double, raw, or
logical input and convert with range checking. Out-of-range → error, not
truncation.#[miniextendr(strict)]. Large integer types then
accept only integer/double input, and a returned i64 that doesn't fit in
R's integer range raises an error instead of silently widening to double.Large-integer output without strict mode uses smart widening: fits in i32 →
integer(), otherwise → double() (precision loss possible above 2^53).
R's NAs are type-specific sentinels, and Rust types must opt in to them:
NA_integer_ is i32::MIN. A plain i32 argument rejects it with an
NA error; Option<i32> receives None. Never return i32::MIN as a
"real" value — R prints it as NA.NA_real_ is one specific NaN bit pattern. A plain f64 receives it (it
is a valid f64); use Option<f64> to make NA explicit as None.
f64::is_nan() cannot distinguish NA from an ordinary NaN.bool
errors on NA; use RLogical (True / False / Na) or Option<bool>.NA_character_ errors for String/&str; use Option<String>.Vectors with NAs: Vec<Option<T>> preserves element-wise NA. Vec<String>
from a character vector containing NA is an error — use
Vec<Option<String>>.
Output direction: scalar Option<T> → None becomes the matching NA;
Option<Vec<T>> → None becomes NULL (not NA). Downstream R code checking
is.null() vs is.na() cares about this difference.
Need to accept NA? → wrap in Option<T> (or Vec<Option<T>>)
Read-only vector input? → &[f64] / &[i32] / &str (zero-copy)
Mutating or keeping the data? → Vec<T> / String (owned copy)
Logical that can be NA? → RLogical
Caller may pass integer OR double? → i64 / f64 (coerce mode handles both)
Exact-type contract? → i32/f64 + optionally #[miniextendr(strict)]
Heterogeneous / structured data? → see miniextendr-dataframe (rows) or
miniextendr-classes (stateful objects)
Conversion failures and panic!() in your Rust code both surface as ordinary
R errors (classed conditions carrying the message). Idiomatic error handling:
#[miniextendr]
pub fn checked_sqrt(x: f64) -> f64 {
if x < 0.0 {
panic!("x must be non-negative, got {x}");
}
x.sqrt()
}
tryCatch(checked_sqrt(-1), error = conditionMessage)
#> "x must be non-negative, got -1"
Returning Result<T, E> (with E: Display) also works: Err becomes an R
error. Never call R's C error functions directly from Rust (the MXL300 lint
blocks it) — panic! is the supported path and runs Rust destructors first.
1 in R is a double. f(1) fails a strict i32 argument; f(1L)
passes. Coerce-mode types (i64 etc.) accept both.i32::MIN is NA — see above; it is excluded from valid i32 range.bool in generic code: R logicals are i32-based three-state, so bool
is deliberately not part of the native-type blanket impls. Generic code
over native numeric types won't cover it; handle logicals explicitly.i64 happily receives TRUE as 1.
If that's too loose for your API, add #[miniextendr(strict)].&[T] / Vec<T> (you get an empty
slice/vec). If you write unsafe code against raw R data pointers
yourself, beware: R returns a non-null sentinel pointer for length-0
vectors — always go through the framework's slice helpers instead.as.character() / as.integer() at the call site is often simplest).miniextendr-dataframe skill.miniextendr-classes skill.