Skip to main content

Module quoted

Module quoted 

Source
Expand description

Unevaluated-argument markers (Quoted / Quosure) for #[miniextendr] parameters. Unevaluated arguments: the Quoted and Quosure parameter markers.

A generated R wrapper forces every argument it hands to .Call(), so a Rust body normally sees values only. A parameter typed Quoted or Quosure is passed unevaluated instead: the body receives the argument’s expression and the environment to evaluate it in, and decides what to do with them. That is what subset()-style methods and APIs taking bare column names (f(data, TIME) as well as f(data, "TIME")) need.

markerthe wrapper passesneeds{{ x }} / !!x
Quotedlist(substitute(x), parent.frame())base Rno
Quosurerlang::enquo(x)rlang in Importsyes
ⓘ
use miniextendr_api::{miniextendr, Quoted, SEXP};

/// Rows of `data` where `cond` holds; `cond` sees the columns of `data`,
/// then the caller's variables.
#[miniextendr]
pub fn keep_rows(data: SEXP, cond: Quoted) -> Vec<i32> {
    let keep = cond.eval_in(data);
    // ... read the logical vector
}
threshold <- 3
keep_rows(df, value > threshold)

The wrapper never forces the argument: a Quoted / Quosure parameter takes no R-side checks and none of the per-parameter options (coerce, match_arg, choices, default, no_na, inherits, …), which are compile errors on it. A function taking one runs on R’s main thread. It works on free functions, including standalone S3 methods (#[miniextendr(s3(generic = "subset", class = "..."))]): in a method reached through UseMethod(), parent.frame() is the generic’s caller, as in base R’s subset.data.frame().

A missing argument is a conversion error naming the parameter (argument "cond" is missing, with no default), like forcing it in R. Take Missing<Quoted> / Missing<Quosure> to make the argument optional.

Evaluation goes through crate::expression::eval_with_handlers: the caller’s withCallingHandlers() / suppressWarnings() see what the expression signals, and an error, or the exit of a tryCatch() handler set up around the call, unwinds through the Rust frames (running their destructors) and carries on in R as the original condition.

Both markers borrow from the .Call() arguments, which R keeps rooted for the call; the lifetime keeps them from outliving it. They are !Send.

A Quosure can also be read from a quosure found in an R object (Quosure::from_sexp), such as one a wrapper wrote into a call with c(time = {{ t }}), or built from an expression and an environment (Quosure::new, Quosure::args). It then borrows the root the caller holds: the SEXP it was read from, or a ProtectScope.

Structs§

Quosure
An argument captured as an rlang quosure, rlang::enquo(x): its expression and environment, with rlang’s argument forwarding and injection resolved.
Quoted
An argument passed unevaluated: its expression and the environment it was written in, as base R’s substitute(x) and parent.frame() give them.

Functions§

data_mask 🔒 ⚠
A new environment enclosed by enclos that binds each named element of the list data, as eval() builds one for a list envir. Bound in reverse so the first of two same-named elements wins, as in eval().
expr_name 🔒
The name an argument expression stands for: a symbol’s name, or the value of a length-1 character literal. None for anything else, and for NA.
innermost_quosure 🔒
The quosure x stands for: x itself, or, when its expression is a quosure too (rlang::new_quosure(<quosure>)), the innermost one. None when x is not a quosure.
is_quosure 🔒
Whether x is an rlang quosure: a one-sided formula, ~expr, of class quosure.
r_index 🔒
An R vector index.
rlang_new_quosure 🔒 ⚠
The function rlang::new_quosure, unprotected.
wrap_in_quosure 🔒 ⚠
new_quosure(quote(<expr>), env), unprotected.