miniextendr_api/expression.rs
1//! Safe wrappers for R expression evaluation.
2//!
3//! This module provides ergonomic types for building and evaluating R function
4//! calls from Rust, handling GC protection and error propagation automatically.
5//!
6//! # Types
7//!
8//! | Type | Purpose |
9//! |------|---------|
10//! | [`RSymbol`] | Interned R symbol (SYMSXP) |
11//! | [`RCall`] | Builder for R function calls (LANGSXP) |
12//! | [`REnv`] | Well-known R environments |
13//! | [`REvalError`] | An R error caught by [`RCall::eval`] / [`r_eval_str`] / [`try_eval_with_handlers`] |
14//!
15//! # Example
16//!
17//! ```ignore
18//! use miniextendr_api::expression::{RCall, REnv};
19//!
20//! unsafe {
21//! // Call paste0("hello", " world") in the base environment
22//! let result = RCall::new("paste0")
23//! .arg(Rf_mkString(c"hello".as_ptr()))
24//! .arg(Rf_mkString(c" world".as_ptr()))
25//! .eval(REnv::base().as_sexp())?;
26//! }
27//! ```
28
29use crate::condition::ConditionClass;
30use crate::from_r::TryFromSexp;
31use crate::gc_protect::{OwnedProtect, ProtectScope};
32use crate::into_r::IntoR;
33use crate::protect_pool::ProtectPool;
34use crate::sexp_ext::PairListExt;
35use crate::sys::{
36 self, ParseStatus, R_BaseEnv, R_EmptyEnv, R_GlobalEnv, R_ParseVector, Rf_install,
37};
38use crate::{SEXP, SexpExt};
39use std::ffi::{CStr, CString};
40use std::os::raw::c_void;
41
42// region: RSymbol
43
44/// A safe wrapper around R symbols (SYMSXP).
45///
46/// R symbols are interned strings used as variable and function names.
47/// They are never garbage collected, so `RSymbol` does not need GC protection.
48///
49/// # Example
50///
51/// ```ignore
52/// let sym = RSymbol::new("paste0");
53/// // sym.as_sexp() is a SYMSXP that can be used in call construction
54/// ```
55pub struct RSymbol {
56 sexp: SEXP,
57}
58
59impl RSymbol {
60 /// Create or retrieve an interned R symbol.
61 ///
62 /// # Safety
63 ///
64 /// Must be called from the R main thread.
65 ///
66 /// # Panics
67 ///
68 /// Panics if `name` contains a null byte.
69 #[inline]
70 pub unsafe fn new(name: &str) -> Self {
71 let c_name = CString::new(name).expect("symbol name must not contain null bytes");
72 RSymbol {
73 sexp: unsafe { Rf_install(c_name.as_ptr()) },
74 }
75 }
76
77 /// Create a symbol from a C string literal.
78 ///
79 /// This avoids the allocation needed by [`new`](Self::new) when you have
80 /// a `&CStr` available (e.g., from `c"name"` literals).
81 ///
82 /// # Safety
83 ///
84 /// Must be called from the R main thread.
85 #[inline]
86 pub unsafe fn from_cstr(name: &CStr) -> Self {
87 RSymbol {
88 sexp: unsafe { Rf_install(name.as_ptr()) },
89 }
90 }
91
92 /// Get the underlying SEXP.
93 #[inline]
94 pub fn as_sexp(&self) -> SEXP {
95 self.sexp
96 }
97}
98// endregion
99
100// region: REnv
101
102/// Handle to a well-known R environment.
103///
104/// Provides access to R's standard environments without raw FFI calls.
105pub struct REnv {
106 sexp: SEXP,
107}
108
109impl REnv {
110 /// The global environment (`R_GlobalEnv`).
111 ///
112 /// # Safety
113 ///
114 /// Must be called from the R main thread.
115 #[inline]
116 pub unsafe fn global() -> Self {
117 REnv {
118 sexp: unsafe { R_GlobalEnv },
119 }
120 }
121
122 /// The base environment (`R_BaseEnv`).
123 ///
124 /// # Safety
125 ///
126 /// Must be called from the R main thread.
127 #[inline]
128 pub unsafe fn base() -> Self {
129 REnv {
130 sexp: unsafe { R_BaseEnv },
131 }
132 }
133
134 /// The empty environment (`R_EmptyEnv`).
135 ///
136 /// # Safety
137 ///
138 /// Must be called from the R main thread.
139 #[inline]
140 pub unsafe fn empty() -> Self {
141 REnv {
142 sexp: unsafe { R_EmptyEnv },
143 }
144 }
145
146 /// The base namespace (`SEXP::base_namespace()`).
147 ///
148 /// Unlike [`base()`](Self::base) which is the base *environment* (exported
149 /// functions visible to users), this is the base *namespace* (includes
150 /// internal helpers). Rarely needed — prefer [`base()`](Self::base) unless
151 /// you specifically need unexported base internals.
152 ///
153 /// # Safety
154 ///
155 /// Must be called from the R main thread.
156 #[inline]
157 pub fn base_namespace() -> Self {
158 REnv {
159 sexp: SEXP::base_namespace(),
160 }
161 }
162
163 /// A package's namespace environment.
164 ///
165 /// Finds the namespace for a loaded package. Use this to evaluate functions
166 /// that live in a specific package (e.g., `slot()` from `methods`).
167 ///
168 /// This is a safe wrapper around `getNamespace(name)`, evaluated through
169 /// [`RCall::eval`], so a missing namespace returns `Err` instead of
170 /// longjmping through Rust frames.
171 ///
172 /// # Safety
173 ///
174 /// Must be called from the R main thread.
175 ///
176 /// # Errors
177 ///
178 /// R's error when the namespace cannot be loaded (a
179 /// `packageNotFoundError` for a package that is not installed).
180 pub unsafe fn package_namespace(name: &str) -> Result<Self, REvalError> {
181 unsafe {
182 let name_sexp = OwnedProtect::new(SEXP::scalar_string_from_str(name));
183 RCall::new("getNamespace")
184 .arg(name_sexp.get())
185 .eval(R_BaseEnv)
186 .map(|sexp| REnv { sexp })
187 }
188 }
189
190 /// The current execution environment.
191 ///
192 /// Returns the environment of the innermost active closure on R's call
193 /// stack, or the global environment if no closure is active.
194 ///
195 /// Useful when you need to evaluate an expression in the caller's context
196 /// rather than a fixed well-known environment.
197 ///
198 /// # Safety
199 ///
200 /// Must be called from the R main thread.
201 #[inline]
202 pub unsafe fn caller() -> Self {
203 REnv {
204 sexp: unsafe { sys::R_GetCurrentEnv() },
205 }
206 }
207
208 /// Wrap an arbitrary environment SEXP.
209 ///
210 /// # Safety
211 ///
212 /// `sexp` must be a valid ENVSXP.
213 #[inline]
214 pub unsafe fn from_sexp(sexp: SEXP) -> Self {
215 REnv { sexp }
216 }
217
218 /// Get the underlying SEXP.
219 #[inline]
220 pub fn as_sexp(&self) -> SEXP {
221 self.sexp
222 }
223
224 /// The value bound to `name` in this environment's own frame, as R's
225 /// `get0(name, envir = env, inherits = FALSE)` reads it, or `None` when
226 /// the frame has no such binding. The enclosing environments are not
227 /// searched; [`get_inherits`](Self::get_inherits) searches them.
228 ///
229 /// A binding to `NULL` is `Some` of `NULL`. Reading a binding does what
230 /// `get0()` does:
231 ///
232 /// - A promise is forced, once, and its value is kept in the promise. A
233 /// function in a lazy-loaded namespace, a `delayedAssign()` and an
234 /// argument of an R function are promises. So this is not a check for
235 /// whether a name is bound without running anything.
236 /// - An active binding (`makeActiveBinding()`) calls its function.
237 /// - A binding to the missing argument raises R's error.
238 ///
239 /// R 4.5 and later read the binding with `R_getVarEx`; R 4.4 evaluates
240 /// `base::get0()`. Both give the same results. An R error raised while
241 /// reading, such as a promise or an active binding that fails, unwinds the
242 /// Rust frames up to the miniextendr boundary, which hands it back to R,
243 /// as under [`eval_with_handlers`].
244 ///
245 /// # Safety
246 ///
247 /// R's main thread, inside a miniextendr boundary: a `#[miniextendr]`
248 /// function body, a [`with_r_unwind_protect`](crate::unwind_protect::with_r_unwind_protect)
249 /// closure, an ALTREP callback with the `r_unwind` or `rust_unwind` guard,
250 /// a connection callback, a [`with_r_thread`](crate::worker::with_r_thread)
251 /// closure.
252 ///
253 /// # Returns
254 ///
255 /// The value, **unprotected**. A plain binding, or a forced promise,
256 /// keeps it reachable while the name stays bound to it. An active
257 /// binding's value is new and held by nothing. Protect the value
258 /// ([`OwnedProtect`], [`Preserved`](crate::Preserved)) before the next
259 /// allocation unless the binding is known to be a plain value, and before
260 /// anything that may rebind the name: R code you evaluate, or
261 /// [`define`](Self::define).
262 ///
263 /// # Panics
264 ///
265 /// Panics if `name` contains a null byte.
266 pub unsafe fn get(&self, name: &str) -> Option<SEXP> {
267 unsafe { self.lookup(name, false) }
268 }
269
270 /// The value bound to `name` in this environment or the nearest enclosing
271 /// environment that binds it, as R's `get0(name, envir = env,
272 /// inherits = TRUE)` reads it, or `None` when none does.
273 ///
274 /// Bindings are read as [`get`](Self::get) reads them: a promise is
275 /// forced, an active binding is called. The search stops at the first
276 /// binding of `name`, whatever its value.
277 ///
278 /// # Safety
279 ///
280 /// As [`get`](Self::get).
281 ///
282 /// # Returns
283 ///
284 /// The value, **unprotected**, as [`get`](Self::get) returns it.
285 ///
286 /// # Panics
287 ///
288 /// Panics if `name` contains a null byte.
289 pub unsafe fn get_inherits(&self, name: &str) -> Option<SEXP> {
290 unsafe { self.lookup(name, true) }
291 }
292
293 /// Bind `name` to `value` in this environment's own frame, as
294 /// `assign(name, value, envir = env)` does: a binding of `name` in the
295 /// frame is replaced, and the enclosing environments are not touched.
296 ///
297 /// R raises its error, which unwinds as under [`get`](Self::get), when
298 /// the binding cannot be made: the empty environment, a locked
299 /// environment that lacks the binding (a package namespace, once the
300 /// package is loaded), or a locked binding. Assigning to an active binding
301 /// calls its function with `value`.
302 ///
303 /// # Safety
304 ///
305 /// As [`get`](Self::get). `value` is a valid SEXP; it needs no root of
306 /// its own, and the binding keeps it reachable afterwards.
307 ///
308 /// # Panics
309 ///
310 /// Panics if `name` contains a null byte.
311 pub unsafe fn define(&self, name: &str, value: SEXP) {
312 assert!(
313 !name.contains('\0'),
314 "a binding name must not contain null bytes"
315 );
316 unsafe { self.define_symbol(SEXP::symbol(name), value) }
317 }
318
319 /// [`define`](Self::define) for a name already interned as a symbol.
320 ///
321 /// # Safety
322 ///
323 /// As [`define`](Self::define); `symbol` is a SYMSXP.
324 pub(crate) unsafe fn define_symbol(&self, symbol: SEXP, value: SEXP) {
325 struct Define {
326 symbol: SEXP,
327 value: SEXP,
328 env: SEXP,
329 }
330
331 unsafe extern "C-unwind" fn define(data: *mut c_void) -> SEXP {
332 let data = unsafe { &*data.cast::<Define>() };
333 unsafe { sys::Rf_defineVar(data.symbol, data.value, data.env) };
334 SEXP::nil()
335 }
336
337 unsafe {
338 // Rooted ahead of the evaluation's own protect frame, so an R exit
339 // leaves the protect stack as the scope expects.
340 let scope = ProtectScope::new();
341 let env = scope.protect_raw(self.sexp);
342 let value = scope.protect_raw(value);
343 let mut data = Define { symbol, value, env };
344 crate::unwind_protect::call_unwinding(define, (&raw mut data).cast());
345 }
346 }
347
348 /// [`get`](Self::get) and [`get_inherits`](Self::get_inherits).
349 ///
350 /// # Safety
351 ///
352 /// As [`get`](Self::get).
353 unsafe fn lookup(&self, name: &str, inherits: bool) -> Option<SEXP> {
354 assert!(
355 !name.contains('\0'),
356 "a binding name must not contain null bytes"
357 );
358
359 // Each branch roots the environment ahead of the evaluation's own
360 // protect frame, so an R exit leaves the protect stack as the guards
361 // expect.
362 #[cfg(r_4_5)]
363 unsafe {
364 struct Lookup {
365 symbol: SEXP,
366 env: SEXP,
367 inherits: crate::Rboolean,
368 }
369
370 unsafe extern "C-unwind" fn lookup(data: *mut c_void) -> SEXP {
371 let data = unsafe { &*data.cast::<Lookup>() };
372 unsafe {
373 sys::R_getVarEx(data.symbol, data.env, data.inherits, sys::R_UnboundValue)
374 }
375 }
376
377 let env = OwnedProtect::new(self.sexp);
378 let mut data = Lookup {
379 symbol: SEXP::symbol(name),
380 env: env.get(),
381 inherits: crate::Rboolean::from(inherits),
382 };
383 let value = crate::unwind_protect::call_unwinding(lookup, (&raw mut data).cast());
384 (value != sys::R_UnboundValue).then_some(value)
385 }
386
387 #[cfg(not(r_4_5))]
388 unsafe {
389 let env = OwnedProtect::new(self.sexp);
390 // A new object, so no binding holds it: `get0()` returns it only
391 // for an unbound name, which tells an unbound name from one bound
392 // to `NULL`.
393 let unbound = OwnedProtect::new(SEXP::alloc_list(0));
394 // Evaluated in the base environment, so `get0` is base's own.
395 let value = RCall::new("get0")
396 .arg_value(name)
397 .named_arg("envir", env.get())
398 .named_value("mode", "any")
399 .named_value("inherits", inherits)
400 .named_arg("ifnotfound", unbound.get())
401 .eval_with_handlers(R_BaseEnv);
402 (value != unbound.get()).then_some(value)
403 }
404 }
405}
406// endregion
407
408// region: RCall
409
410/// Builder for constructing and evaluating R function calls.
411///
412/// `RCall` constructs a LANGSXP (R language object) from a function name or
413/// SEXP and a sequence of arguments (optionally named). It handles GC
414/// protection during construction and evaluation.
415///
416/// # Example
417///
418/// ```ignore
419/// use miniextendr_api::expression::RCall;
420/// use miniextendr_api::sys;
421///
422/// unsafe {
423/// // seq_len(10)
424/// let result = RCall::new("seq_len")
425/// .arg(SEXP::scalar_integer(10))
426/// .eval_base()?;
427///
428/// // paste(x, collapse = ", ")
429/// let result = RCall::new("paste")
430/// .arg(some_sexp)
431/// .named_arg("collapse", sys::Rf_mkString(c", ".as_ptr()))
432/// .eval_base()?;
433/// }
434/// ```
435pub struct RCall {
436 /// Function symbol or SEXP.
437 fun: SEXP,
438 /// Arguments as (optional_name, value) pairs.
439 args: Vec<(Option<CString>, SEXP)>,
440 /// Roots the callable and every argument for the builder's lifetime,
441 /// except symbols, which need no root ([`needs_root`]).
442 ///
443 /// Besides keeping inline allocations alive, `ProtectPool` makes `RCall`
444 /// `!Send + !Sync`: construction, mutation, and drop stay on R's thread.
445 roots: ProtectPool,
446}
447
448impl RCall {
449 /// Initialize an empty builder calling `fun`, rooted unless it is a symbol.
450 ///
451 /// `fun` may be a freshly allocated, unprotected closure. The temporary
452 /// stack root keeps it alive while the pool allocates its backing VECSXP.
453 #[inline]
454 unsafe fn from_callable(fun: SEXP) -> Self {
455 unsafe {
456 if !needs_root(fun) {
457 return RCall {
458 fun,
459 args: Vec::new(),
460 roots: ProtectPool::new(4),
461 };
462 }
463 let fun_guard = OwnedProtect::new(fun);
464 let mut roots = ProtectPool::new(4);
465 roots.insert(fun_guard.get());
466 RCall {
467 fun,
468 args: Vec::new(),
469 roots,
470 }
471 }
472 }
473
474 /// Start building a call to a named R function.
475 ///
476 /// The function is looked up via `Rf_install`, which returns an interned symbol.
477 ///
478 /// # Safety
479 ///
480 /// Must be called from the R main thread.
481 ///
482 /// # Panics
483 ///
484 /// Panics if `fun_name` contains a null byte.
485 #[inline]
486 pub unsafe fn new(fun_name: &str) -> Self {
487 let c_name = CString::new(fun_name).expect("function name must not contain null bytes");
488 unsafe { Self::from_callable(Rf_install(c_name.as_ptr())) }
489 }
490
491 /// Start building a call to a function given as a C string literal.
492 ///
493 /// More efficient than [`new`](Self::new) when a `&CStr` is available.
494 ///
495 /// # Safety
496 ///
497 /// Must be called from the R main thread.
498 #[inline]
499 pub unsafe fn from_cstr(fun_name: &CStr) -> Self {
500 unsafe { Self::from_callable(Rf_install(fun_name.as_ptr())) }
501 }
502
503 /// Start building a call with a function SEXP (closure, builtin, etc.).
504 ///
505 /// # Safety
506 ///
507 /// `fun` must be a valid SEXP representing a callable R object.
508 #[inline]
509 pub unsafe fn from_sexp(fun: SEXP) -> Self {
510 unsafe { Self::from_callable(fun) }
511 }
512
513 /// Root an argument for the builder's lifetime, unless it is a symbol.
514 ///
515 /// `value` may be fresh: the pool keeps it reachable while it grows.
516 #[inline]
517 fn root(&mut self, value: SEXP) {
518 if needs_root(value) {
519 self.roots.root(value);
520 }
521 }
522
523 /// Add a positional argument.
524 #[inline]
525 pub fn arg(mut self, value: SEXP) -> Self {
526 self.root(value);
527 self.args.push((None, value));
528 self
529 }
530
531 /// Add a named argument.
532 ///
533 /// # Panics
534 ///
535 /// Panics if `name` contains a null byte.
536 #[inline]
537 pub fn named_arg(mut self, name: &str, value: SEXP) -> Self {
538 let c_name = CString::new(name).expect("argument name must not contain null bytes");
539 self.root(value);
540 self.args.push((Some(c_name), value));
541 self
542 }
543
544 /// Convert a Rust value and add it as a positional argument.
545 ///
546 /// The converted value is rooted before anything else allocates, so a
547 /// value made only for this call needs no root of its own. Write
548 /// `RCall::new("qt").arg_value(p).arg_value(df)`, not
549 /// `p.into_sexp()` and `df.into_sexp()` first: the second conversion, and
550 /// [`new`](Self::new), allocate while the first value is not rooted.
551 ///
552 /// # Panics
553 ///
554 /// Panics if the conversion fails, as [`IntoR::into_sexp`] does.
555 #[inline]
556 pub fn arg_value(self, value: impl IntoR) -> Self {
557 self.arg(value.into_sexp())
558 }
559
560 /// Convert a Rust value and add it as a named argument. See
561 /// [`arg_value`](Self::arg_value).
562 ///
563 /// # Panics
564 ///
565 /// Panics if `name` contains a null byte, or if the conversion fails.
566 #[inline]
567 pub fn named_value(self, name: &str, value: impl IntoR) -> Self {
568 self.named_arg(name, value.into_sexp())
569 }
570
571 /// Add R's `...` at this position: the dots of the frame the call is
572 /// evaluated in, each passed on as the promise R matched, unevaluated.
573 ///
574 /// Only [`LazyDots::forward`](crate::LazyDots::forward) /
575 /// [`try_forward`](crate::LazyDots::try_forward) evaluate a call in a
576 /// frame that has dots (the generated wrapper's), and they add `...` last
577 /// themselves, so this is for putting it elsewhere:
578 /// `RCall::new("f").dots().named_value("na.rm", true)` is
579 /// `f(..., na.rm = TRUE)`. Evaluated in an environment without dots, R
580 /// raises "'...' used in an incorrect context".
581 #[inline]
582 pub fn dots(self) -> Self {
583 // SAFETY: symbols are interned for the session and need no root.
584 self.arg(unsafe { dots_symbol() })
585 }
586
587 /// Whether the call passes `...` ([`dots`](Self::dots)).
588 pub(crate) fn has_dots(&self) -> bool {
589 // SAFETY: as in `dots`.
590 let dots = unsafe { dots_symbol() };
591 self.args
592 .iter()
593 .any(|(name, value)| name.is_none() && *value == dots)
594 }
595
596 /// Add a positional argument passed as is: `quote(<value>)`.
597 ///
598 /// The call evaluates its arguments, so a symbol, a call or a quosure
599 /// added with [`arg`](Self::arg) is evaluated before the function sees
600 /// it. Use this for a language object the function must receive as a
601 /// value: a call for an `error_call` / `call` argument, an expression
602 /// for `eval()`. Any other value passes through `quote()` unchanged.
603 #[inline]
604 pub fn quoted_arg(self, value: SEXP) -> Self {
605 let quoted = unsafe { quote(value) };
606 self.arg(quoted)
607 }
608
609 /// Add a named argument passed as is: `name = quote(<value>)`. See
610 /// [`quoted_arg`](Self::quoted_arg).
611 ///
612 /// # Panics
613 ///
614 /// Panics if `name` contains a null byte.
615 #[inline]
616 pub fn named_quoted_arg(self, name: &str, value: SEXP) -> Self {
617 let quoted = unsafe { quote(value) };
618 self.named_arg(name, quoted)
619 }
620
621 /// Build the LANGSXP without evaluating it.
622 ///
623 /// The returned SEXP is **unprotected**. The caller must protect it if
624 /// further allocations will occur before use.
625 ///
626 /// # Safety
627 ///
628 /// Must be called from the R main thread. The builder keeps the callable
629 /// and every argument rooted until it is dropped.
630 pub unsafe fn build(&self) -> SEXP {
631 unsafe {
632 // Build the argument pairlist from back to front using Rf_cons.
633 // ProtectScope tracks all intermediate cons cells and the final
634 // LANGSXP head, then unprotects them all on drop. The returned
635 // call is unprotected — caller protects it if needed.
636 let scope = ProtectScope::new();
637
638 let mut tail = SEXP::nil();
639 for (name, value) in self.args.iter().rev() {
640 tail = scope.protect_raw(value.cons(tail));
641 if let Some(c_name) = name {
642 tail.set_tag(Rf_install(c_name.as_ptr()));
643 }
644 }
645
646 // Prepend the function as LANGSXP head.
647 // ProtectScope drops here; the call is unprotected on return
648 // (callers re-protect via OwnedProtect before invoking eval).
649 scope.protect_raw(self.fun.lcons(tail))
650 }
651 }
652
653 /// Evaluate the call in the given environment, catching an R error.
654 ///
655 /// The call runs in a new top-level context (`R_ToplevelExec`) under an
656 /// exiting handler for `error` conditions (`R_tryCatchError`). So the
657 /// caller's condition handlers and restarts don't see it, and an R error
658 /// comes back as `Err` holding R's condition (its message, call, classes
659 /// and the object itself) instead of jumping through the Rust frames.
660 /// Use [`eval_with_handlers`](Self::eval_with_handlers) for a call whose
661 /// conditions the user should see as raised, and
662 /// [`try_eval_with_handlers`](Self::try_eval_with_handlers) for one whose
663 /// warnings and messages the user should see but whose error the Rust
664 /// code handles.
665 ///
666 /// ```ignore
667 /// match RCall::new("print").arg(df).named_arg("na.print", one).eval_base() {
668 /// Ok(_) => {}
669 /// // `e` is R's condition: "invalid 'na.print' specification",
670 /// // without the "Error in print.default(...) :" prefix.
671 /// Err(e) => rust_error!(class = e.reraise_class("pkg_print_error"), "{e}"),
672 /// }
673 /// ```
674 ///
675 /// # Safety
676 ///
677 /// - Must be called from the R main thread.
678 /// - `env` must be a valid ENVSXP.
679 /// - The builder must not outlive the active R session.
680 ///
681 /// # Returns
682 ///
683 /// - `Ok(SEXP)` with the result (unprotected — caller should protect if needed)
684 /// - `Err(REvalError)` with R's error condition on failure
685 pub unsafe fn eval(&self, env: SEXP) -> Result<SEXP, REvalError> {
686 unsafe {
687 let call = OwnedProtect::new(self.build());
688 try_eval(call.get(), env)
689 }
690 }
691
692 /// Evaluate in `R_BaseEnv`.
693 ///
694 /// # Safety
695 ///
696 /// Same as [`eval`](Self::eval).
697 #[inline]
698 pub unsafe fn eval_base(&self) -> Result<SEXP, REvalError> {
699 unsafe { self.eval(R_BaseEnv) }
700 }
701
702 /// Evaluate the call in `env`, as [`eval`](Self::eval) does, and read the
703 /// result as `T`.
704 ///
705 /// The result stays rooted while it is converted, so the caller never
706 /// holds it unrooted:
707 ///
708 /// ```ignore
709 /// let q: Vec<Option<f64>> = RCall::new("qt")
710 /// .arg_value(p)
711 /// .arg_value(df)
712 /// .eval_as(stats.as_sexp())?;
713 /// ```
714 ///
715 /// A result that `T` can't read is an `Err` too: a `simpleError`
716 /// whose message is the conversion's, with no call. A `T` that only
717 /// views the value (`SEXP`, `List`, `DataFrame`) comes back unrooted, as
718 /// from [`eval`](Self::eval); read into an owned type (`Vec<T>`,
719 /// `String`, a struct) or protect it.
720 ///
721 /// # Safety
722 ///
723 /// As [`eval`](Self::eval).
724 pub unsafe fn eval_as<T>(&self, env: SEXP) -> Result<T, REvalError>
725 where
726 T: TryFromSexp,
727 T::Error: std::fmt::Display,
728 {
729 unsafe {
730 let value = OwnedProtect::new(self.eval(env)?);
731 T::try_from_sexp(value.get()).map_err(|e| REvalError::simple_error(&e.to_string()))
732 }
733 }
734
735 /// [`eval_as`](Self::eval_as) in `R_BaseEnv`.
736 ///
737 /// # Safety
738 ///
739 /// As [`eval`](Self::eval).
740 #[inline]
741 pub unsafe fn eval_base_as<T>(&self) -> Result<T, REvalError>
742 where
743 T: TryFromSexp,
744 T::Error: std::fmt::Display,
745 {
746 unsafe { self.eval_as(R_BaseEnv) }
747 }
748
749 /// Evaluate the call in `env` in the caller's R context, keeping R's
750 /// condition handlers: see [`eval_with_handlers`].
751 ///
752 /// Use it to call R code that signals conditions the user should see, with
753 /// their classes, through their own `withCallingHandlers()` /
754 /// `tryCatch()`. A tidyselect selection, say:
755 ///
756 /// ```ignore
757 /// // `cols` is a `Quosure` parameter, `data` a data frame.
758 /// let selected = unsafe {
759 /// RCall::namespaced("tidyselect", "eval_select")?
760 /// .arg(cols.sexp())
761 /// .arg(data)
762 /// .eval_with_handlers(R_BaseEnv)
763 /// };
764 /// ```
765 ///
766 /// A column that does not exist raises tidyselect's own error (class
767 /// `vctrs_error_subscript_oob`, with its call), which unwinds through the
768 /// Rust frames and reaches the user's `tryCatch()` as it was raised. To
769 /// get the error back as `Err(REvalError)` instead, while the user's
770 /// handlers still see warnings and messages, use
771 /// [`try_eval_with_handlers`](Self::try_eval_with_handlers).
772 ///
773 /// # Safety
774 ///
775 /// As [`eval_with_handlers`]: R's main thread, inside a miniextendr
776 /// boundary, `env` an environment. The result is unprotected.
777 pub unsafe fn eval_with_handlers(&self, env: SEXP) -> SEXP {
778 unsafe {
779 let call = OwnedProtect::new(self.build());
780 eval_with_handlers(call.get(), env)
781 }
782 }
783
784 /// Evaluate the call in `env` in the caller's R context, keeping R's
785 /// condition handlers, with an R error returned as `Err`: see
786 /// [`try_eval_with_handlers`].
787 ///
788 /// Use it for a call that forwards the user's arguments to an R function
789 /// and raises the function's errors as the package's own: the user's
790 /// `withCallingHandlers()`, `suppressWarnings()` and
791 /// `tryCatch(warning = )` see the function's warnings and messages, and
792 /// an R error comes back as [`REvalError`]. A `[` method of a data-frame
793 /// subclass, say:
794 ///
795 /// ```ignore
796 /// let out = unsafe {
797 /// RCall::new("[")
798 /// .arg(frame)
799 /// .arg(i)
800 /// .named_arg("drop", drop)
801 /// .try_eval_with_handlers(R_BaseEnv)
802 /// }
803 /// .unwrap_or_else(|e| rust_error!(class = e.reraise_class("pkg_subset_error"), "{e}"));
804 /// ```
805 ///
806 /// `x[1, drop = FALSE]` warns that `drop` is ignored; the user's
807 /// `suppressWarnings()` silences it. A column that does not exist
808 /// ("undefined columns selected") comes back as `Err` and is raised again
809 /// under `pkg_subset_error`.
810 ///
811 /// # Safety
812 ///
813 /// As [`try_eval_with_handlers`]: R's main thread, inside a miniextendr
814 /// boundary, `env` an environment. The value is unprotected.
815 pub unsafe fn try_eval_with_handlers(&self, env: SEXP) -> Result<SEXP, REvalError> {
816 unsafe {
817 let call = OwnedProtect::new(self.build());
818 try_eval_with_handlers(call.get(), env)
819 }
820 }
821
822 /// Start building a namespaced call: `pkg::fun(args…)`.
823 ///
824 /// Looks up `pkg::fun_name` in the base environment and uses the resolved
825 /// function closure as the call target. This respects R's namespace lookup
826 /// rules (exported + non-exported via `::` / `:::`).
827 ///
828 /// This is the runtime counterpart of the lowered `pkg::fn(args…)` form
829 /// in `r!(pkg::fn(args…))`.
830 ///
831 /// # Safety
832 ///
833 /// Must be called from the R main thread.
834 ///
835 /// # Panics
836 ///
837 /// Panics if `pkg` or `fun_name` contain a null byte.
838 ///
839 /// # Errors
840 ///
841 /// R's error if the namespace lookup fails (package not installed, or no
842 /// such function).
843 pub unsafe fn namespaced(pkg: &str, fun_name: &str) -> Result<Self, REvalError> {
844 unsafe {
845 // Build (:: pkg fun_name) as a LANGSXP and evaluate it to get the closure.
846 let ns_op = Rf_install(c"::".as_ptr());
847 let pkg_sym = {
848 let c = CString::new(pkg).expect("pkg name must not contain null bytes");
849 Rf_install(c.as_ptr())
850 };
851 let fun_sym = {
852 let c = CString::new(fun_name).expect("fun name must not contain null bytes");
853 Rf_install(c.as_ptr())
854 };
855
856 // Build `(:: pkg fun_name)` pairlist from back to front.
857 let scope = crate::gc_protect::ProtectScope::new();
858 let nil = crate::sys::R_NilValue;
859 let fun_cons = scope.protect_raw(fun_sym.cons(nil));
860 let pkg_cons = scope.protect_raw(pkg_sym.cons(fun_cons));
861 let ns_call = scope.protect_raw(ns_op.lcons(pkg_cons));
862
863 // Evaluate to resolve the function closure.
864 let fun_sexp = try_eval(ns_call, R_BaseEnv)?;
865
866 // Root the resolved closure for the builder lifetime. This is
867 // load-bearing even for closures that are not namespace bindings
868 // (the same constructor backs `RCall::from_sexp`).
869 Ok(RCall::from_sexp(fun_sexp))
870 }
871 }
872}
873
874/// The symbol `...`.
875///
876/// # Safety
877///
878/// R's main thread. Symbols are never collected.
879unsafe fn dots_symbol() -> SEXP {
880 unsafe { Rf_install(c"...".as_ptr()) }
881}
882
883/// Build and evaluate `target$name` — the R `$` extraction operator.
884///
885/// This is a convenience wrapper that avoids hand-rolling
886/// `Rf_install("$") + Rf_lang3(...) + R_tryEval(...)` ladders.
887/// Equivalent to:
888///
889/// ```ignore
890/// RCall::new("$")
891/// .arg(target)
892/// .arg(SEXP::scalar_string_from_str(name))
893/// .eval_base()
894/// ```
895///
896/// with the name argument protected while the call is built.
897///
898/// # Safety
899///
900/// - Must be called from the R main thread.
901/// - `target` must be a valid SEXP (typically a list, environment, or S4
902/// object that supports `$` extraction).
903///
904/// # Returns
905///
906/// - `Ok(SEXP)` with the extracted value (unprotected — caller should protect if needed).
907/// - `Err(REvalError)` with R's error if `$` extraction fails.
908pub unsafe fn dollar_extract(target: SEXP, name: &str) -> Result<SEXP, REvalError> {
909 unsafe {
910 let name_sexp = OwnedProtect::new(SEXP::scalar_string_from_str(name));
911 RCall::new("$").arg(target).arg(name_sexp.get()).eval_base()
912 }
913}
914// endregion
915
916/// Whether `value` needs a GC root while Rust holds it across an allocation.
917///
918/// A symbol never does: R never frees one. `install()` links every new symbol
919/// into `R_SymbolTable` (`src/main/names.c`, `install`, and `installNoTrChar`
920/// likewise), nothing ever unlinks it, and the collector marks every bucket of
921/// the table on every collection (`src/main/memory.c`, `RunGenCollect`: the
922/// `R_SymbolTable` loop). The marker symbols outside the table
923/// (`R_MissingArg`, `R_UnboundValue`, `R_RestartToken` and the rest, made by
924/// `mkSymMarker` in `InitNames`) are forwarded as roots of their own in the
925/// same function.
926#[inline]
927fn needs_root(value: SEXP) -> bool {
928 value.type_of() != crate::SEXPTYPE::SYMSXP
929}
930
931/// `quote(<value>)`, unprotected. `value` is rooted across the allocation
932/// unless it is a symbol ([`needs_root`]).
933///
934/// # Safety
935///
936/// R's main thread.
937unsafe fn quote(value: SEXP) -> SEXP {
938 unsafe {
939 let quote = Rf_install(c"quote".as_ptr());
940 if !needs_root(value) {
941 return crate::sys::Rf_lang2(quote, value);
942 }
943 let value = OwnedProtect::new(value);
944 crate::sys::Rf_lang2(quote, value.get())
945 }
946}
947
948// region: eval_with_handlers, try_eval_with_handlers (evaluation in the caller's R context)
949
950/// Evaluate `expr` in `env` in the caller's R context, the way R code calling
951/// `eval(expr, env)` does.
952///
953/// | | [`RCall::eval`], [`r_eval_str`] | `eval_with_handlers` | [`try_eval_with_handlers`] |
954/// |---|---|---|---|
955/// | R entry point | `R_tryCatchError` inside `R_ToplevelExec` | `Rf_eval` in its own `R_UnwindProtect` | `R_tryCatchError` in its own `R_UnwindProtect` |
956/// | caller's `withCallingHandlers()`, `suppressWarnings()` | not seen (`R_ToplevelExec` empties the handler and restart stacks) | see every warning, message and condition | see every warning, message and condition except an error |
957/// | R error | `Err(`[`REvalError`]`)`: R's condition, with its message (no `Error in` prefix, no `Calls:` line), call and classes; the Rust code decides what to raise | unwinds as the R condition, class and call kept | `Err(`[`REvalError`]`)`, as from [`RCall::eval`] |
958/// | caller's `tryCatch(warning = )`, restarts, interrupts | not seen (an interrupt ends the evaluation with an `Err`) | exit through the Rust frames | exit through the Rust frames |
959///
960/// An R error, or any other exit from the evaluation (an exiting handler of
961/// the caller's `tryCatch()`, `invokeRestart()`, an interrupt), stops at this
962/// function's own `R_UnwindProtect` frame, so it never jumps over a Rust
963/// frame. It then leaves as a Rust unwind: the frames between here and the
964/// `#[miniextendr]` boundary drop their values (a guard's `Drop` runs), and
965/// the boundary hands the exit back to R, which carries on to the handler or
966/// restart it was going to, with the original condition object. A warning or
967/// message the caller muffles returns here and the evaluation continues.
968///
969/// So this is the evaluator for code a user wrote: an argument passed
970/// unevaluated ([`crate::Quoted`], [`crate::Quosure`]), a callback, a call into
971/// a package whose conditions are part of its interface. Keep [`RCall::eval`]
972/// for internal calls whose failure the Rust code handles itself, for
973/// instance by raising its own condition with the caught message
974/// ([`REvalError::reraise_class`]). [`try_eval_with_handlers`] combines the
975/// two: the caller's handlers see warnings and messages, and an R error comes
976/// back as `Err` for the Rust code to raise.
977///
978/// The unwind must reach a miniextendr boundary. Don't catch it with
979/// `std::panic::catch_unwind` in between, or the R exit is abandoned (R
980/// carries on as after `R_tryEval`, without running the caller's handler);
981/// resume a caught payload with `std::panic::resume_unwind` on the same
982/// thread before the call returns. An exit resumed in a later call has lost
983/// its target: the boundary raises an error instead. Don't call this from a
984/// `Drop` implementation: an exit there would start an unwind during an
985/// unwind, which aborts.
986///
987/// # Safety
988///
989/// - R's main thread, inside a miniextendr boundary: a `#[miniextendr]`
990/// function body, a [`with_r_unwind_protect`](crate::unwind_protect::with_r_unwind_protect)
991/// closure, an ALTREP callback with the `r_unwind` or `rust_unwind` guard
992/// (not `unsafe`, which catches nothing), a connection callback, a
993/// [`with_r_thread`](crate::worker::with_r_thread) closure.
994/// - `expr` and `env` stay rooted for the call; `env` is an environment.
995///
996/// # Returns
997///
998/// The value, **unprotected**: protect it before the next allocation.
999pub unsafe fn eval_with_handlers(expr: SEXP, env: SEXP) -> SEXP {
1000 unsafe { crate::unwind_protect::eval_unwinding(expr, env) }
1001}
1002
1003/// Evaluate `expr` in `env` in the caller's R context, as
1004/// [`eval_with_handlers`] does, but return an R error as `Err` instead of
1005/// letting it unwind.
1006///
1007/// The caller's `withCallingHandlers()`, `suppressWarnings()` and
1008/// `suppressMessages()` see the evaluation's warnings, messages and other
1009/// conditions; one they muffle returns here and the evaluation goes on. A
1010/// condition of class `error` is caught at the evaluation, by an exiting
1011/// handler (`R_tryCatchError`), and comes back as `Err(`[`REvalError`]`)`
1012/// built as [`RCall::eval`] builds it: R's condition, with its message (no
1013/// `Error in` prefix, no `Calls:` line), call and classes. The Rust code
1014/// decides what to raise ([`REvalError::reraise_class`]).
1015///
1016/// Any other exit (an exiting handler of the caller's `tryCatch()`, such as
1017/// `tryCatch(warning = )`, `invokeRestart()`, an interrupt) leaves as under
1018/// [`eval_with_handlers`]: it stops at this function's own `R_UnwindProtect`
1019/// frame and goes on as a Rust unwind, the frames up to the `#[miniextendr]`
1020/// boundary drop their values, and the boundary hands the exit back to R.
1021///
1022/// The error handler is the innermost one, so a handler of the caller's for
1023/// errors (`withCallingHandlers(error = )`, `tryCatch(error = )`) does not see
1024/// an error the evaluation raises. An error raised by a handler of the
1025/// caller's, as in `withCallingHandlers(warning = function(w) stop("no"))`,
1026/// is not the evaluation's: R runs that handler outside the evaluation's
1027/// handlers, so the error unwinds to the caller as raised.
1028///
1029/// The evaluation runs inside R's `tryCatch()`, as under [`RCall::eval`]: an
1030/// error raised at the top of `expr` (`stop()` called directly, not from a
1031/// function) has no [`call`](REvalError::call), and code at the top of `expr`
1032/// that inspects the call stack (`sys.call()`) sees the `tryCatch()` frames.
1033///
1034/// The rules of [`eval_with_handlers`] for the unwind hold here too: don't
1035/// catch it with `std::panic::catch_unwind` on its way to the boundary, and
1036/// don't call this from a `Drop` implementation.
1037///
1038/// # Safety
1039///
1040/// As [`eval_with_handlers`]:
1041///
1042/// - R's main thread, inside a miniextendr boundary: a `#[miniextendr]`
1043/// function body, a [`with_r_unwind_protect`](crate::unwind_protect::with_r_unwind_protect)
1044/// closure, an ALTREP callback with the `r_unwind` or `rust_unwind` guard
1045/// (not `unsafe`, which catches nothing), a connection callback, a
1046/// [`with_r_thread`](crate::worker::with_r_thread) closure.
1047/// - `expr` and `env` stay rooted for the call; `env` is an environment.
1048///
1049/// # Returns
1050///
1051/// - `Ok(SEXP)` with the value, **unprotected**: protect it before the next
1052/// allocation.
1053/// - `Err(REvalError)` with R's error condition.
1054pub unsafe fn try_eval_with_handlers(expr: SEXP, env: SEXP) -> Result<SEXP, REvalError> {
1055 unsafe { into_result(try_eval_unwinding(expr, env)) }
1056}
1057
1058// endregion
1059
1060// region: r_eval_str (runtime string parse + eval)
1061
1062/// Parse a string of R source and evaluate it in `env`.
1063///
1064/// This is the runtime workhorse behind the [`r_str!`](crate::r_str) and
1065/// [`r!`](crate::r) macros. It performs the full
1066/// `R_ParseVector` → check status → `Rf_eval` ladder with correct GC
1067/// protection on every intermediate SEXP, so callers never have to hand-roll
1068/// `OwnedProtect` around the parse tree.
1069///
1070/// Only the **last** top-level expression's value is returned (matching R's
1071/// `eval(parse(text = ...))` semantics): each parsed expression is evaluated in
1072/// order so that side effects (assignments, `library()`, …) take effect, and
1073/// the value of the final one is returned. An empty / whitespace-only string
1074/// yields `R_NilValue`.
1075///
1076/// # Safety
1077///
1078/// - Must be called from (or routed to) the R main thread. The parse and eval
1079/// FFI calls go through the checked `#[r_ffi_checked]` variants, which
1080/// serialize onto the R thread via `with_r_thread`, so calling from a
1081/// worker thread is sound — but the returned SEXP must not outlive the R
1082/// session.
1083/// - `env` must be a valid ENVSXP.
1084///
1085/// # Returns
1086///
1087/// - `Ok(SEXP)` with the value of the last expression (**unprotected** — the
1088/// caller should protect it if further allocations will occur before use).
1089/// - `Err(REvalError)` if evaluation raises an R error: R's condition, caught
1090/// as in [`RCall::eval`], so it never longjmps through Rust frames. A parse
1091/// failure (syntax error / incomplete input) has no R condition; it comes
1092/// back as a `simpleError` whose message names the failure and the source.
1093///
1094/// # Example
1095///
1096/// ```ignore
1097/// use miniextendr_api::expression::r_eval_str;
1098/// use miniextendr_api::sys::R_GlobalEnv;
1099///
1100/// unsafe {
1101/// let three = r_eval_str("1L + 2L", R_GlobalEnv)?;
1102/// // three is an INTSXP holding 3
1103/// }
1104/// ```
1105pub unsafe fn r_eval_str(code: &str, env: SEXP) -> Result<SEXP, REvalError> {
1106 unsafe {
1107 // 1. Wrap the source in a length-1 STRSXP. scalar_string_from_str
1108 // allocates a CHARSXP + STRSXP; protect it across the parse, which
1109 // allocates again.
1110 let code_sexp = OwnedProtect::new(SEXP::scalar_string_from_str(code));
1111
1112 // 2. Parse. R_ParseVector returns an EXPRSXP (a vector of expressions).
1113 // Protect it across the subsequent VECTOR_ELT / Rf_eval allocations.
1114 let mut status = ParseStatus::PARSE_NULL;
1115 let parsed = R_ParseVector(code_sexp.get(), -1, &mut status, sys::R_NilValue);
1116
1117 let parse_failure = match status {
1118 ParseStatus::PARSE_OK => None,
1119 ParseStatus::PARSE_INCOMPLETE => Some(format!(
1120 "incomplete R expression (unbalanced delimiter?): {code}"
1121 )),
1122 ParseStatus::PARSE_ERROR => Some(format!("R syntax error while parsing: {code}")),
1123 ParseStatus::PARSE_EOF => {
1124 Some(format!("unexpected end of input while parsing: {code}"))
1125 }
1126 ParseStatus::PARSE_NULL => {
1127 Some(format!("R_ParseVector returned PARSE_NULL for: {code}"))
1128 }
1129 };
1130 if let Some(message) = parse_failure {
1131 return Err(REvalError::simple_error(&message));
1132 }
1133
1134 let parsed = OwnedProtect::new(parsed);
1135
1136 // 3. Evaluate each parsed expression in order; return the value of the
1137 // last one. An empty EXPRSXP (blank source) yields R_NilValue.
1138 let n = parsed.get().xlength();
1139 let mut result = sys::R_NilValue;
1140 for i in 0..n {
1141 // VECTOR_ELT borrows from `parsed` (still protected). The element
1142 // is part of the protected EXPRSXP, so it stays reachable.
1143 let expr = parsed.get().vector_elt(i);
1144 result = try_eval(expr, env)?;
1145 }
1146
1147 Ok(result)
1148 }
1149}
1150
1151/// Parse and evaluate a string of R source in `R_GlobalEnv`.
1152///
1153/// Convenience wrapper over [`r_eval_str`] for the common case. See that
1154/// function for safety and return semantics.
1155///
1156/// # Safety
1157///
1158/// Same as [`r_eval_str`].
1159#[inline]
1160pub unsafe fn r_eval_str_global(code: &str) -> Result<SEXP, REvalError> {
1161 unsafe { r_eval_str(code, R_GlobalEnv) }
1162}
1163// endregion
1164
1165// region: REvalError (an R error caught by RCall::eval / r_eval_str)
1166
1167/// The trailing classes [`REvalError::specific_classes`] leaves out: R's base
1168/// error layers, and the `rust_error` layer a miniextendr function adds.
1169/// `error!` and a `Result` return add them again.
1170const BASE_ERROR_CLASSES: [&str; 4] = ["rust_error", "simpleError", "error", "condition"];
1171
1172/// The message of the `simpleError` that stands for an evaluation that jumped
1173/// to the top level without an error condition.
1174const EXIT_MESSAGE: &str =
1175 "R evaluation was interrupted (it jumped to the top level without an error condition)";
1176
1177/// An R error caught by [`RCall::eval`] / [`RCall::eval_base`], [`r_eval_str`],
1178/// the helpers built on them ([`REnv::package_namespace`],
1179/// [`RCall::namespaced`], [`dollar_extract`]), and [`try_eval_with_handlers`] /
1180/// [`RCall::try_eval_with_handlers`].
1181///
1182/// It holds R's condition object, rooted while this value lives, and what R
1183/// reports about it:
1184///
1185/// - [`message`](Self::message): `conditionMessage(cond)`, the text R prints
1186/// after `Error in <call> :`, without that prefix and without the `Calls:`
1187/// traceback line of a non-interactive session;
1188/// - [`call`](Self::call): `conditionCall(cond)`, `None` when it is `NULL`;
1189/// - [`classes`](Self::classes): the class vector, most specific first;
1190/// - [`condition`](Self::condition): the condition object itself.
1191///
1192/// `Display` writes the message alone. Every value holds a condition: a parse
1193/// failure in [`r_eval_str`] and an evaluation under [`RCall::eval`] that
1194/// jumps to the top level without an error (an interrupt) come back as a
1195/// `simpleError` built for them, with no call.
1196///
1197/// # Raising your own condition with it
1198///
1199/// The condition macros take the message through `Display`, and
1200/// [`reraise_class`](Self::reraise_class) puts the package's own classes
1201/// ahead of the caught ones:
1202///
1203/// ```ignore
1204/// use miniextendr_api::rust_error;
1205///
1206/// match RCall::new("print").arg(x).named_arg("na.print", na).eval_base() {
1207/// Ok(_) => {}
1208/// // The package's own class with R's message:
1209/// // class = "pkg_print_error"
1210/// // or with the caught classes kept after it, so a handler for those
1211/// // still matches:
1212/// Err(e) => rust_error!(class = e.reraise_class("pkg_print_error"), "{e}"),
1213/// }
1214/// ```
1215///
1216/// [`reraise`](Self::reraise) raises the caught condition itself instead, as
1217/// R raised it.
1218///
1219/// A `#[miniextendr]` function returning `Result<T, REvalError>` raises the
1220/// caught message with the caught [specific classes](Self::specific_classes)
1221/// (`REvalError` implements [`RConditionData`](crate::condition::RConditionData)).
1222/// For a `Result<T, condition::RError>` return, `RError::from(e)` takes the
1223/// message (it is a `std::error::Error`) and `.class(...)` adds the classes.
1224///
1225/// # Threads
1226///
1227/// `!Send + !Sync`: dropping the value releases its root on R's precious list,
1228/// which is R main-thread state, and [`condition`](Self::condition) /
1229/// [`call`](Self::call) hand out SEXPs. To carry the failure to another thread
1230/// or into a `Send` error type (`anyhow::Error`, `Box<dyn Error + Send>`),
1231/// take [`message`](Self::message) or convert into
1232/// [`condition::RError`](crate::condition::RError).
1233pub struct REvalError {
1234 /// `conditionMessage(cond)`.
1235 message: String,
1236 /// `class(cond)`.
1237 classes: Vec<String>,
1238 /// `list(cond, call)`, on R's precious list while this value lives, where
1239 /// `call` is `conditionCall(cond)` or `NULL` (see [`REvalError::call`]).
1240 /// Its handle makes the value `!Send + !Sync`, see the type docs.
1241 roots: crate::Preserved,
1242}
1243
1244impl REvalError {
1245 /// The condition's message (`conditionMessage(cond)`), without R's
1246 /// `Error in <call> :` prefix and `Calls:` line.
1247 #[inline]
1248 pub fn message(&self) -> &str {
1249 &self.message
1250 }
1251
1252 /// The condition's call (`conditionCall(cond)`), `None` when it is `NULL`.
1253 ///
1254 /// Also `None` for an error raised at the top of the evaluated expression
1255 /// (`stop()` called directly rather than from a function): R gives such
1256 /// an error the call of the `tryCatch()` frame the evaluation runs in,
1257 /// `doTryCatch(return(expr), name, parentenv, handler)`, which is no call
1258 /// of the evaluated code. The [condition object](Self::condition) keeps
1259 /// what R recorded.
1260 ///
1261 /// The SEXP is rooted while this value lives; protect it to keep it longer.
1262 #[inline]
1263 pub fn call(&self) -> Option<SEXP> {
1264 let call = self.roots.vector_elt(1);
1265 (!call.is_nil()).then_some(call)
1266 }
1267
1268 /// The condition's class vector, most specific first: for `stop("boom")`,
1269 /// `["simpleError", "error", "condition"]`.
1270 #[inline]
1271 pub fn classes(&self) -> &[String] {
1272 &self.classes
1273 }
1274
1275 /// Whether the condition's class vector contains `class`.
1276 #[inline]
1277 pub fn inherits(&self, class: &str) -> bool {
1278 self.classes.iter().any(|c| c == class)
1279 }
1280
1281 /// The classes ahead of the base layers: the class vector without its
1282 /// trailing `rust_error`, `simpleError`, `error` and `condition`, which the
1283 /// condition macros add again. Empty for `stop("boom")`; `["my_class"]`
1284 /// for `stop(errorCondition("boom", class = "my_class"))` or for a
1285 /// miniextendr function's `error!(class = "my_class", "boom")`.
1286 pub fn specific_classes(&self) -> &[String] {
1287 let end = self
1288 .classes
1289 .iter()
1290 .rposition(|c| !BASE_ERROR_CLASSES.contains(&c.as_str()))
1291 .map_or(0, |last| last + 1);
1292 &self.classes[..end]
1293 }
1294
1295 /// The class vector for raising this error again as the package's own
1296 /// condition: `own` first (one class or several, most specific first),
1297 /// then the caught [specific classes](Self::specific_classes) not already
1298 /// in `own`.
1299 ///
1300 /// ```ignore
1301 /// // stop(errorCondition("boom", class = "vctrs_error")) caught as `e`:
1302 /// rust_error!(class = e.reraise_class(["pkg_print_error", "pkg_error"]), "{e}");
1303 /// // class: pkg_print_error, pkg_error, vctrs_error, rust_error,
1304 /// // simpleError, error, condition
1305 /// ```
1306 pub fn reraise_class(&self, own: impl ConditionClass) -> Vec<String> {
1307 let mut classes = own.into_condition_class();
1308 for class in self.specific_classes() {
1309 if !classes.contains(class) {
1310 classes.push(class.clone());
1311 }
1312 }
1313 classes
1314 }
1315
1316 /// The condition object.
1317 ///
1318 /// The SEXP is rooted while this value lives; protect it to keep it longer.
1319 #[inline]
1320 pub fn condition(&self) -> SEXP {
1321 self.roots.vector_elt(0)
1322 }
1323
1324 /// Raise the caught condition again, as R raised it: its classes, message
1325 /// and fields are unchanged, and its call is [`call`](Self::call). So an
1326 /// error raised at the top of the evaluated expression reports no call,
1327 /// not R's `doTryCatch(...)` frame.
1328 ///
1329 /// Use it for the errors a body doesn't explain itself, next to a
1330 /// package's own condition for the ones it does
1331 /// ([`Quoted::try_eval_in`](crate::Quoted::try_eval_in) has an example).
1332 /// Unlike `rust_error!(class = e.reraise_class(..), "{e}")`, the condition
1333 /// gets no `rust_error` class and keeps R's call, not the wrapper's.
1334 ///
1335 /// The condition is signalled by base `stop(cond)`, evaluated as
1336 /// [`eval_with_handlers`] evaluates: the caller's handlers see it, and the
1337 /// exit stops at that evaluation's `R_UnwindProtect` frame and leaves as a
1338 /// Rust unwind. The frames up to the `#[miniextendr]` boundary drop their
1339 /// values, and the boundary hands the exit back to R, which goes on to the
1340 /// caller's handler or to the top level. The same rules hold as for
1341 /// [`eval_with_handlers`]: don't catch the unwind with
1342 /// `std::panic::catch_unwind`, and don't call this from a `Drop`
1343 /// implementation.
1344 ///
1345 /// # Safety
1346 ///
1347 /// As [`eval_with_handlers`]: R's main thread, inside a miniextendr
1348 /// boundary (a `#[miniextendr]` function body, a
1349 /// [`with_r_unwind_protect`](crate::unwind_protect::with_r_unwind_protect)
1350 /// closure, ...).
1351 pub unsafe fn reraise(self) -> ! {
1352 unsafe {
1353 let scope = ProtectScope::new();
1354 let cond = scope.protect_raw(without_try_catch_frame_call(self.condition()));
1355 // `stop(cond)` with the condition bound in a child of base, so a
1356 // traceback shows `stop(cond)` rather than the deparsed object.
1357 let env = scope.protect_raw(sys::R_NewEnv(R_BaseEnv, crate::Rboolean::FALSE, 1));
1358 let cond_sym = RSymbol::from_cstr(c"cond").as_sexp();
1359 REnv::from_sexp(env).define_symbol(cond_sym, cond);
1360 let call = scope.protect_raw(sys::Rf_lang2(
1361 RSymbol::from_cstr(c"stop").as_sexp(),
1362 cond_sym,
1363 ));
1364 eval_with_handlers(call, env);
1365 }
1366 unreachable!("stop() returned without signalling an error")
1367 }
1368
1369 /// Take a caught condition: read its classes, message and call, and root
1370 /// the condition with its call.
1371 ///
1372 /// # Safety
1373 ///
1374 /// R's main thread; `cond` is rooted by the caller for the call.
1375 unsafe fn from_condition(cond: SEXP) -> Self {
1376 unsafe {
1377 let classes = string_vector(cond.get_class());
1378 let message = condition_message(cond);
1379 let call = OwnedProtect::new(condition_call(cond));
1380 Self::adopt(cond, call.get(), message, classes)
1381 }
1382 }
1383
1384 /// A `simpleError` with `message` and no call, for a failure that raised
1385 /// no R condition (a parse failure, a jump to the top level, a result
1386 /// [`RCall::eval_as`] can't read).
1387 ///
1388 /// # Safety
1389 ///
1390 /// R's main thread.
1391 unsafe fn simple_error(message: &str) -> Self {
1392 const CLASSES: [&str; 3] = ["simpleError", "error", "condition"];
1393 unsafe {
1394 let scope = ProtectScope::new();
1395 // list(message = <message>, call = NULL): `alloc_list` fills
1396 // `NULL`, and each fresh element is stored before the next
1397 // allocation.
1398 let cond = scope.protect_raw(SEXP::alloc_list(2));
1399 cond.set_vector_elt(0, SEXP::scalar_string_from_str(message));
1400 let names = scope.protect_raw(SEXP::alloc_strsxp(2));
1401 names.set_string_elt(0, SEXP::charsxp("message"));
1402 names.set_string_elt(1, SEXP::charsxp("call"));
1403 cond.set_names(names);
1404 let class = scope.protect_raw(SEXP::alloc_strsxp(3));
1405 for (i, name) in (0..).zip(CLASSES) {
1406 class.set_string_elt(i, SEXP::charsxp(name));
1407 }
1408 cond.set_class(class);
1409 Self::adopt(
1410 cond,
1411 SEXP::nil(),
1412 message.to_owned(),
1413 CLASSES.map(String::from).to_vec(),
1414 )
1415 }
1416 }
1417
1418 /// Root `cond` and `call` together for the value's lifetime.
1419 ///
1420 /// # Safety
1421 ///
1422 /// R's main thread; `cond` and `call` are rooted by the caller for the
1423 /// call.
1424 unsafe fn adopt(cond: SEXP, call: SEXP, message: String, classes: Vec<String>) -> Self {
1425 unsafe {
1426 let roots = crate::Preserved::new(SEXP::alloc_list(2));
1427 roots.set_vector_elt(0, cond);
1428 roots.set_vector_elt(1, call);
1429 REvalError {
1430 message,
1431 classes,
1432 roots,
1433 }
1434 }
1435 }
1436}
1437
1438impl std::fmt::Display for REvalError {
1439 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1440 f.write_str(&self.message)
1441 }
1442}
1443
1444impl std::fmt::Debug for REvalError {
1445 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1446 f.debug_struct("REvalError")
1447 .field("message", &self.message)
1448 .field("classes", &self.classes)
1449 .finish_non_exhaustive()
1450 }
1451}
1452
1453impl std::error::Error for REvalError {}
1454
1455/// Returned as a `#[miniextendr]` function's `Err`, the caught error is raised
1456/// again with its message and its [specific classes](REvalError::specific_classes),
1457/// ahead of the `rust_error` layers; the call is the function's own.
1458impl crate::condition::RConditionData for REvalError {
1459 fn message(&self) -> String {
1460 self.message.clone()
1461 }
1462
1463 fn class(&self) -> Vec<String> {
1464 self.specific_classes().to_vec()
1465 }
1466}
1467
1468/// The elements of a character vector (`NA` as `"NA"`); empty for anything
1469/// else. Does not allocate.
1470///
1471/// # Safety
1472///
1473/// R's main thread.
1474unsafe fn string_vector(x: SEXP) -> Vec<String> {
1475 if x.type_of() != crate::SEXPTYPE::STRSXP {
1476 return Vec::new();
1477 }
1478 (0..x.xlength())
1479 .map(|i| {
1480 // SAFETY: `x` is a STRSXP, so its elements are CHARSXPs.
1481 unsafe { crate::from_r::charsxp_to_string_lossy(x.string_elt(i)) }
1482 .unwrap_or_else(|| "NA".to_owned())
1483 })
1484 .collect()
1485}
1486
1487/// `conditionMessage(cond)`, through S3 dispatch, so a class with its own
1488/// method (rlang's errors, say) words its message. If the method fails or
1489/// returns no string: the condition's `message` field, then a placeholder.
1490///
1491/// # Safety
1492///
1493/// R's main thread; `cond` rooted.
1494unsafe fn condition_message(cond: SEXP) -> String {
1495 unsafe {
1496 let call = OwnedProtect::new(RCall::new("conditionMessage").quoted_arg(cond).build());
1497 if let Caught::Value(message) = try_eval_raw(call.get(), R_BaseEnv) {
1498 let lines = string_vector(message);
1499 if !lines.is_empty() {
1500 return lines.join("\n");
1501 }
1502 }
1503 if cond.type_of() == crate::SEXPTYPE::VECSXP {
1504 let names = string_vector(cond.get_names());
1505 if let Some(i) = names.iter().position(|name| name == "message") {
1506 let i = isize::try_from(i).expect("list index exceeds isize::MAX");
1507 let lines = string_vector(cond.vector_elt(i));
1508 if !lines.is_empty() {
1509 return lines.join("\n");
1510 }
1511 }
1512 }
1513 "R error with no message".to_owned()
1514 }
1515}
1516
1517/// `conditionCall(cond)`, or `NULL` if the method fails or the call is the
1518/// `tryCatch()` frame's ([`is_try_catch_frame_call`]). Unprotected.
1519///
1520/// # Safety
1521///
1522/// R's main thread; `cond` rooted.
1523unsafe fn condition_call(cond: SEXP) -> SEXP {
1524 unsafe {
1525 let call = OwnedProtect::new(RCall::new("conditionCall").quoted_arg(cond).build());
1526 match try_eval_raw(call.get(), R_BaseEnv) {
1527 Caught::Value(call) if !is_try_catch_frame_call(call) => call,
1528 Caught::Value(_) | Caught::Error(_) | Caught::Exit => SEXP::nil(),
1529 }
1530 }
1531}
1532
1533/// Whether `call` is `doTryCatch(return(expr), name, parentenv, handler)`,
1534/// the frame of R's `tryCatch()`, which `R_tryCatchError` evaluates in. An
1535/// error raised at the top of the evaluated expression (`stop()` called
1536/// directly, not from a function) takes that frame's call as its own; it is
1537/// no call of the user's code, so [`REvalError::call`] reports `None` there.
1538/// Base R's `try()` recognises the frame by the same `doTryCatch` head.
1539fn is_try_catch_frame_call(call: SEXP) -> bool {
1540 call.type_of() == crate::SEXPTYPE::LANGSXP
1541 // SAFETY: `doTryCatch` is a literal without NUL; interning is main-thread work.
1542 && call.car() == unsafe { RSymbol::from_cstr(c"doTryCatch") }.as_sexp()
1543}
1544
1545/// `cond`, or a shallow copy of it whose `call` element is `NULL` when that
1546/// element is the [`tryCatch()` frame's call](is_try_catch_frame_call): the
1547/// condition [`REvalError::reraise`] signals, with the call
1548/// [`REvalError::call`] reports.
1549///
1550/// # Safety
1551///
1552/// R's main thread; `cond` rooted by the caller. The result is unprotected.
1553unsafe fn without_try_catch_frame_call(cond: SEXP) -> SEXP {
1554 unsafe {
1555 if cond.type_of() != crate::SEXPTYPE::VECSXP {
1556 return cond;
1557 }
1558 let names = string_vector(cond.get_names());
1559 let Some(i) = names.iter().position(|name| name == "call") else {
1560 return cond;
1561 };
1562 let i = isize::try_from(i).expect("list index exceeds isize::MAX");
1563 if !is_try_catch_frame_call(cond.vector_elt(i)) {
1564 return cond;
1565 }
1566 let copy = sys::Rf_shallow_duplicate(cond);
1567 copy.set_vector_elt(i, SEXP::nil());
1568 copy
1569 }
1570}
1571
1572// endregion
1573
1574// region: try_eval (evaluation with R errors caught)
1575
1576/// How an evaluation with R errors caught ended. The SEXPs are unprotected.
1577enum Caught {
1578 /// The expression's value.
1579 Value(SEXP),
1580 /// The `error` condition the evaluation raised.
1581 Error(SEXP),
1582 /// A jump to the top level without an error condition: an interrupt, an
1583 /// `abort` restart. Only [`try_eval_raw`] stops those.
1584 Exit,
1585}
1586
1587/// A C callback run with R errors caught, given the caller's data. An R error
1588/// jumps out of it, so it holds nothing to drop.
1589type TryBody = unsafe extern "C-unwind" fn(*mut c_void) -> SEXP;
1590
1591/// What [`catch_error`] shares with its callbacks.
1592struct TryEvalData {
1593 /// `R_tryCatchError`'s body: [`eval_body`] for an R expression.
1594 body: TryBody,
1595 body_data: *mut c_void,
1596 /// A protected list of one, which receives the value or the caught
1597 /// condition. The callbacks store into it without allocating, so what
1598 /// they hand back is rooted before R runs again.
1599 slot: SEXP,
1600 /// Whether the error handler ran.
1601 caught: bool,
1602}
1603
1604impl TryEvalData {
1605 /// The call of `body(body_data)`; `slot` is a protected list of one.
1606 fn new(body: TryBody, body_data: *mut c_void, slot: SEXP) -> Self {
1607 TryEvalData {
1608 body,
1609 body_data,
1610 slot,
1611 caught: false,
1612 }
1613 }
1614
1615 /// How [`catch_error`] ended, once it has returned. The SEXP is rooted by
1616 /// the slot.
1617 fn outcome(&self) -> Caught {
1618 let value = self.slot.vector_elt(0);
1619 if self.caught {
1620 Caught::Error(value)
1621 } else {
1622 Caught::Value(value)
1623 }
1624 }
1625}
1626
1627/// An R expression and the environment to evaluate it in: [`eval_body`]'s
1628/// data.
1629struct EvalArgs {
1630 expr: SEXP,
1631 env: SEXP,
1632}
1633
1634/// Evaluate an [`EvalArgs`]. An R error jumps from here to the `tryCatch()`
1635/// frame, over no Rust frame holding anything to drop.
1636unsafe extern "C-unwind" fn eval_body(data: *mut c_void) -> SEXP {
1637 let data = data.cast::<EvalArgs>();
1638 unsafe { sys::Rf_eval((*data).expr, (*data).env) }
1639}
1640
1641/// Run a [`TryEvalData`]'s body with `error` conditions caught
1642/// (`R_tryCatchError`), and store its value, or the caught condition, in its
1643/// slot. Returns `R_tryCatchError`'s value: the body's, or `NULL` after an
1644/// error ([`TryEvalData::outcome`] tells them apart).
1645///
1646/// `R_tryCatchError` runs R's `tryCatch()`, so the caller's calling handlers
1647/// see the evaluation's other conditions, and any jump that is not an error
1648/// (an exiting handler or restart of the caller's) passes through. A jump out
1649/// of here crosses no Rust frame holding anything to drop.
1650unsafe extern "C-unwind" fn catch_error(data: *mut c_void) -> SEXP {
1651 /// `R_tryCatchError`'s handler, run once R has unwound to the
1652 /// `tryCatch()` frame: keep the condition.
1653 unsafe extern "C-unwind" fn handler(cond: SEXP, data: *mut c_void) -> SEXP {
1654 let data = data.cast::<TryEvalData>();
1655 unsafe {
1656 (*data).slot.set_vector_elt(0, cond);
1657 (*data).caught = true;
1658 }
1659 SEXP::nil()
1660 }
1661
1662 let data = data.cast::<TryEvalData>();
1663 unsafe {
1664 let value = sys::R_tryCatchError(
1665 Some((*data).body),
1666 (*data).body_data,
1667 Some(handler),
1668 data.cast(),
1669 );
1670 if !(*data).caught {
1671 (*data).slot.set_vector_elt(0, value);
1672 }
1673 value
1674 }
1675}
1676
1677/// Call `body(body_data)`, hidden from the caller's handlers and restarts
1678/// (a new top-level context, `R_ToplevelExec`), with `error` conditions
1679/// caught ([`catch_error`]).
1680///
1681/// `R_tryCatchError` alone is not enough here: the caller's calling handlers
1682/// would see the evaluation's warnings, and an exiting handler or restart of
1683/// the caller would jump through the Rust frames. `R_ToplevelExec` gives the
1684/// isolation `R_tryEval` gives, and stops any jump that is not an error.
1685///
1686/// # Safety
1687///
1688/// R's main thread (the checked FFI routes a worker's call there);
1689/// `body(body_data)` is sound to call, and what it reads is rooted.
1690unsafe fn try_call_raw(body: TryBody, body_data: *mut c_void) -> Caught {
1691 /// `R_ToplevelExec`'s callback. A jump out of it crosses no Rust frame
1692 /// holding anything to drop.
1693 unsafe extern "C-unwind" fn toplevel(data: *mut c_void) {
1694 unsafe { catch_error(data) };
1695 }
1696
1697 unsafe {
1698 let slot = OwnedProtect::new(SEXP::alloc_list(1));
1699 let mut data = TryEvalData::new(body, body_data, slot.get());
1700 let completed = sys::R_ToplevelExec(Some(toplevel), (&raw mut data).cast());
1701 if completed == crate::sexp_types::Rboolean::FALSE {
1702 return Caught::Exit;
1703 }
1704 data.outcome()
1705 }
1706}
1707
1708/// Evaluate `expr` in `env` as [`try_call_raw`] calls a body.
1709///
1710/// # Safety
1711///
1712/// R's main thread (the checked FFI routes a worker's call there); `expr`
1713/// and `env` rooted.
1714unsafe fn try_eval_raw(expr: SEXP, env: SEXP) -> Caught {
1715 let mut args = EvalArgs { expr, env };
1716 unsafe { try_call_raw(eval_body, (&raw mut args).cast()) }
1717}
1718
1719/// Call `body(body_data)`, a C callback that may raise an R error, as
1720/// [`RCall::eval`] evaluates a call: hidden from the caller's handlers and
1721/// restarts, with an R error returned as `Err`. The value is unprotected.
1722///
1723/// For a C entry point that raises R errors, such as `R_WriteConnection`
1724/// (`connection/access.rs`); an R call needs no body of its own.
1725///
1726/// # Safety
1727///
1728/// As [`try_call_raw`]. An R error jumps out of `body`, so it must hold
1729/// nothing to drop.
1730#[cfg(all(feature = "connections", r_4_6))]
1731pub(crate) unsafe fn try_call(body: TryBody, body_data: *mut c_void) -> Result<SEXP, REvalError> {
1732 unsafe { into_result(try_call_raw(body, body_data)) }
1733}
1734
1735/// Evaluate `expr` in `env` in the caller's R context, with `error`
1736/// conditions caught ([`catch_error`]): the caller's handlers and restarts
1737/// stay in place, and any other R exit leaves as a Rust unwind
1738/// ([`call_unwinding`](crate::unwind_protect::call_unwinding)). Never
1739/// [`Caught::Exit`].
1740///
1741/// The slot is protected before the evaluation and holds the caught condition
1742/// until the caller roots it. An exit jumps to `R_UnwindProtect`'s frame,
1743/// which resets the protect stack to its level when the frame was entered, so
1744/// the slot's protection is still the top one when the unwind drops it.
1745///
1746/// # Safety
1747///
1748/// As [`try_eval_with_handlers`].
1749unsafe fn try_eval_unwinding(expr: SEXP, env: SEXP) -> Caught {
1750 unsafe {
1751 let slot = OwnedProtect::new(SEXP::alloc_list(1));
1752 let mut args = EvalArgs { expr, env };
1753 let mut data = TryEvalData::new(eval_body, (&raw mut args).cast(), slot.get());
1754 crate::unwind_protect::call_unwinding(catch_error, (&raw mut data).cast());
1755 data.outcome()
1756 }
1757}
1758
1759/// An evaluation's outcome with a caught error as an [`REvalError`]. The
1760/// value is unprotected.
1761///
1762/// # Safety
1763///
1764/// R's main thread, right after the evaluation: nothing has allocated since.
1765unsafe fn into_result(caught: Caught) -> Result<SEXP, REvalError> {
1766 unsafe {
1767 match caught {
1768 Caught::Value(value) => Ok(value),
1769 Caught::Error(cond) => {
1770 let cond = OwnedProtect::new(cond);
1771 Err(REvalError::from_condition(cond.get()))
1772 }
1773 Caught::Exit => Err(REvalError::simple_error(EXIT_MESSAGE)),
1774 }
1775 }
1776}
1777
1778/// [`try_eval_raw`] with a caught error as an [`REvalError`]. The value is
1779/// unprotected.
1780///
1781/// # Safety
1782///
1783/// As [`try_eval_raw`].
1784unsafe fn try_eval(expr: SEXP, env: SEXP) -> Result<SEXP, REvalError> {
1785 unsafe { into_result(try_eval_raw(expr, env)) }
1786}
1787
1788// endregion
1789
1790// region: Tests
1791
1792#[cfg(test)]
1793mod tests {
1794 use super::*;
1795
1796 // These tests verify compilation and basic invariants.
1797 // Full integration tests require the R runtime.
1798
1799 #[test]
1800 fn renv_types_are_sized() {
1801 // Just verify types compile and are sized
1802 fn assert_sized<T: Sized>() {}
1803 assert_sized::<RSymbol>();
1804 assert_sized::<RCall>();
1805 assert_sized::<REnv>();
1806 }
1807
1808 #[test]
1809 fn renv_constructors_compile() {
1810 // Verify all REnv constructor signatures compile.
1811 // Actual testing requires the R runtime.
1812 fn assert_env_fn<F: FnOnce() -> REnv>(_f: F) {}
1813 fn assert_env_result_fn<F: FnOnce() -> Result<REnv, REvalError>>(_f: F) {}
1814
1815 assert_env_fn(|| unsafe { REnv::global() });
1816 assert_env_fn(|| unsafe { REnv::base() });
1817 assert_env_fn(|| unsafe { REnv::empty() });
1818 assert_env_fn(REnv::base_namespace);
1819 assert_env_fn(|| unsafe { REnv::caller() });
1820 assert_env_result_fn(|| unsafe { REnv::package_namespace("base") });
1821 }
1822}
1823// endregion