pub struct RCall {
fun: SEXP,
args: Vec<(Option<CString>, SEXP)>,
roots: ProtectPool,
}Expand description
Builder for constructing and evaluating R function calls.
RCall constructs a LANGSXP (R language object) from a function name or
SEXP and a sequence of arguments (optionally named). It handles GC
protection during construction and evaluation.
§Example
use miniextendr_api::expression::RCall;
use miniextendr_api::sys;
unsafe {
// seq_len(10)
let result = RCall::new("seq_len")
.arg(SEXP::scalar_integer(10))
.eval_base()?;
// paste(x, collapse = ", ")
let result = RCall::new("paste")
.arg(some_sexp)
.named_arg("collapse", sys::Rf_mkString(c", ".as_ptr()))
.eval_base()?;
}Fields§
§fun: SEXPFunction symbol or SEXP.
args: Vec<(Option<CString>, SEXP)>Arguments as (optional_name, value) pairs.
roots: ProtectPoolRoots the callable and every argument for the builder’s lifetime,
except symbols, which need no root (needs_root).
Besides keeping inline allocations alive, ProtectPool makes RCall
!Send + !Sync: construction, mutation, and drop stay on R’s thread.
Implementations§
Source§impl RCall
impl RCall
Sourceunsafe fn from_callable(fun: SEXP) -> Self
unsafe fn from_callable(fun: SEXP) -> Self
Initialize an empty builder calling fun, rooted unless it is a symbol.
fun may be a freshly allocated, unprotected closure. The temporary
stack root keeps it alive while the pool allocates its backing VECSXP.
Sourcepub unsafe fn from_sexp(fun: SEXP) -> Self
pub unsafe fn from_sexp(fun: SEXP) -> Self
Start building a call with a function SEXP (closure, builtin, etc.).
§Safety
fun must be a valid SEXP representing a callable R object.
Sourcefn root(&mut self, value: SEXP)
fn root(&mut self, value: SEXP)
Root an argument for the builder’s lifetime, unless it is a symbol.
value may be fresh: the pool keeps it reachable while it grows.
Sourcepub fn arg_value(self, value: impl IntoR) -> Self
pub fn arg_value(self, value: impl IntoR) -> Self
Convert a Rust value and add it as a positional argument.
The converted value is rooted before anything else allocates, so a
value made only for this call needs no root of its own. Write
RCall::new("qt").arg_value(p).arg_value(df), not
p.into_sexp() and df.into_sexp() first: the second conversion, and
new, allocate while the first value is not rooted.
§Panics
Panics if the conversion fails, as IntoR::into_sexp does.
Sourcepub fn named_value(self, name: &str, value: impl IntoR) -> Self
pub fn named_value(self, name: &str, value: impl IntoR) -> Self
Sourcepub fn dots(self) -> Self
pub fn dots(self) -> Self
Add R’s ... at this position: the dots of the frame the call is
evaluated in, each passed on as the promise R matched, unevaluated.
Only LazyDots::forward /
try_forward evaluate a call in a
frame that has dots (the generated wrapper’s), and they add ... last
themselves, so this is for putting it elsewhere:
RCall::new("f").dots().named_value("na.rm", true) is
f(..., na.rm = TRUE). Evaluated in an environment without dots, R
raises “‘…’ used in an incorrect context”.
Sourcepub fn quoted_arg(self, value: SEXP) -> Self
pub fn quoted_arg(self, value: SEXP) -> Self
Add a positional argument passed as is: quote(<value>).
The call evaluates its arguments, so a symbol, a call or a quosure
added with arg is evaluated before the function sees
it. Use this for a language object the function must receive as a
value: a call for an error_call / call argument, an expression
for eval(). Any other value passes through quote() unchanged.
Sourcepub fn named_quoted_arg(self, name: &str, value: SEXP) -> Self
pub fn named_quoted_arg(self, name: &str, value: SEXP) -> Self
Add a named argument passed as is: name = quote(<value>). See
quoted_arg.
§Panics
Panics if name contains a null byte.
Sourcepub unsafe fn build(&self) -> SEXP
pub unsafe fn build(&self) -> SEXP
Build the LANGSXP without evaluating it.
The returned SEXP is unprotected. The caller must protect it if further allocations will occur before use.
§Safety
Must be called from the R main thread. The builder keeps the callable and every argument rooted until it is dropped.
Sourcepub unsafe fn eval(&self, env: SEXP) -> Result<SEXP, REvalError>
pub unsafe fn eval(&self, env: SEXP) -> Result<SEXP, REvalError>
Evaluate the call in the given environment, catching an R error.
The call runs in a new top-level context (R_ToplevelExec) under an
exiting handler for error conditions (R_tryCatchError). So the
caller’s condition handlers and restarts don’t see it, and an R error
comes back as Err holding R’s condition (its message, call, classes
and the object itself) instead of jumping through the Rust frames.
Use eval_with_handlers for a call whose
conditions the user should see as raised, and
try_eval_with_handlers for one whose
warnings and messages the user should see but whose error the Rust
code handles.
match RCall::new("print").arg(df).named_arg("na.print", one).eval_base() {
Ok(_) => {}
// `e` is R's condition: "invalid 'na.print' specification",
// without the "Error in print.default(...) :" prefix.
Err(e) => rust_error!(class = e.reraise_class("pkg_print_error"), "{e}"),
}§Safety
- Must be called from the R main thread.
envmust be a valid ENVSXP.- The builder must not outlive the active R session.
§Returns
Ok(SEXP)with the result (unprotected — caller should protect if needed)Err(REvalError)with R’s error condition on failure
Sourcepub unsafe fn eval_base(&self) -> Result<SEXP, REvalError>
pub unsafe fn eval_base(&self) -> Result<SEXP, REvalError>
Sourcepub unsafe fn eval_as<T>(&self, env: SEXP) -> Result<T, REvalError>
pub unsafe fn eval_as<T>(&self, env: SEXP) -> Result<T, REvalError>
Evaluate the call in env, as eval does, and read the
result as T.
The result stays rooted while it is converted, so the caller never holds it unrooted:
let q: Vec<Option<f64>> = RCall::new("qt")
.arg_value(p)
.arg_value(df)
.eval_as(stats.as_sexp())?;A result that T can’t read is an Err too: a simpleError
whose message is the conversion’s, with no call. A T that only
views the value (SEXP, List, DataFrame) comes back unrooted, as
from eval; read into an owned type (Vec<T>,
String, a struct) or protect it.
§Safety
As eval.
Sourcepub unsafe fn eval_base_as<T>(&self) -> Result<T, REvalError>
pub unsafe fn eval_base_as<T>(&self) -> Result<T, REvalError>
Sourcepub unsafe fn eval_with_handlers(&self, env: SEXP) -> SEXP
pub unsafe fn eval_with_handlers(&self, env: SEXP) -> SEXP
Evaluate the call in env in the caller’s R context, keeping R’s
condition handlers: see eval_with_handlers.
Use it to call R code that signals conditions the user should see, with
their classes, through their own withCallingHandlers() /
tryCatch(). A tidyselect selection, say:
// `cols` is a `Quosure` parameter, `data` a data frame.
let selected = unsafe {
RCall::namespaced("tidyselect", "eval_select")?
.arg(cols.sexp())
.arg(data)
.eval_with_handlers(R_BaseEnv)
};A column that does not exist raises tidyselect’s own error (class
vctrs_error_subscript_oob, with its call), which unwinds through the
Rust frames and reaches the user’s tryCatch() as it was raised. To
get the error back as Err(REvalError) instead, while the user’s
handlers still see warnings and messages, use
try_eval_with_handlers.
§Safety
As eval_with_handlers: R’s main thread, inside a miniextendr
boundary, env an environment. The result is unprotected.
Sourcepub unsafe fn try_eval_with_handlers(
&self,
env: SEXP,
) -> Result<SEXP, REvalError>
pub unsafe fn try_eval_with_handlers( &self, env: SEXP, ) -> Result<SEXP, REvalError>
Evaluate the call in env in the caller’s R context, keeping R’s
condition handlers, with an R error returned as Err: see
try_eval_with_handlers.
Use it for a call that forwards the user’s arguments to an R function
and raises the function’s errors as the package’s own: the user’s
withCallingHandlers(), suppressWarnings() and
tryCatch(warning = ) see the function’s warnings and messages, and
an R error comes back as REvalError. A [ method of a data-frame
subclass, say:
let out = unsafe {
RCall::new("[")
.arg(frame)
.arg(i)
.named_arg("drop", drop)
.try_eval_with_handlers(R_BaseEnv)
}
.unwrap_or_else(|e| rust_error!(class = e.reraise_class("pkg_subset_error"), "{e}"));x[1, drop = FALSE] warns that drop is ignored; the user’s
suppressWarnings() silences it. A column that does not exist
(“undefined columns selected”) comes back as Err and is raised again
under pkg_subset_error.
§Safety
As try_eval_with_handlers: R’s main thread, inside a miniextendr
boundary, env an environment. The value is unprotected.
Sourcepub unsafe fn namespaced(pkg: &str, fun_name: &str) -> Result<Self, REvalError>
pub unsafe fn namespaced(pkg: &str, fun_name: &str) -> Result<Self, REvalError>
Start building a namespaced call: pkg::fun(args…).
Looks up pkg::fun_name in the base environment and uses the resolved
function closure as the call target. This respects R’s namespace lookup
rules (exported + non-exported via :: / :::).
This is the runtime counterpart of the lowered pkg::fn(args…) form
in r!(pkg::fn(args…)).
§Safety
Must be called from the R main thread.
§Panics
Panics if pkg or fun_name contain a null byte.
§Errors
R’s error if the namespace lookup fails (package not installed, or no such function).
Auto Trait Implementations§
impl !Send for RCall
impl !Sync for RCall
impl Freeze for RCall
impl RefUnwindSafe for RCall
impl Unpin for RCall
impl UnsafeUnpin for RCall
impl UnwindSafe for RCall
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> SizeHint for Twhere
T: ?Sized,
impl<T> SizeHint for Twhere
T: ?Sized,
Source§default fn lower_bound(&self) -> usize
default fn lower_bound(&self) -> usize
core_io_internals)[u8; 12] could return any value between 0 and
12 inclusively as a correct implementation. Read moreSource§impl<T> SizedTypeProperties for T
impl<T> SizedTypeProperties for T
Source§#[doc(hidden)]const SIZE: usize = _
#[doc(hidden)]const SIZE: usize = _
sized_type_properties)Source§#[doc(hidden)]const ALIGN: usize = _
#[doc(hidden)]const ALIGN: usize = _
sized_type_properties)Source§#[doc(hidden)]const ALIGNMENT: Alignment = _
#[doc(hidden)]const ALIGNMENT: Alignment = _
ptr_alignment_type)Source§#[doc(hidden)]const IS_ZST: bool = _
#[doc(hidden)]const IS_ZST: bool = _
sized_type_properties)Source§#[doc(hidden)]const LAYOUT: Layout = _
#[doc(hidden)]const LAYOUT: Layout = _
sized_type_properties)Source§#[doc(hidden)]const MAX_SLICE_LEN: usize = _
#[doc(hidden)]const MAX_SLICE_LEN: usize = _
sized_type_properties)[Self]. Read moreLayout§
Note: Most layout information is completely unstable and may even differ between compilations. The only exception is types with certain repr(...) attributes. Please see the Rust Reference's “Type Layout” chapter for details on type layout guarantees.
Size: 112 bytes