miniextendr_api/sys.rs
1//! Raw FFI bindings to R headers.
2//!
3//! This module mirrors R's C API closely and is intentionally thin. **You
4//! almost never call these directly from user code** — prefer the
5//! higher-level wrappers: `SEXP` (in [`crate::sexp`]), [`SexpExt`] (in
6//! [`crate::sexp_ext`]), the type vocabulary in [`crate::sexp_types`], plus
7//! [`IntoR`], [`TryFromSexp`], [`with_r_thread`], [`with_r_unwind_protect`],
8//! and the `#[miniextendr]` proc-macro. The items here exist so those
9//! wrappers can be written; treat them as the framework's escape hatch.
10//!
11//! [`SexpExt`]: crate::sexp_ext::SexpExt
12//! [`IntoR`]: crate::IntoR
13//! [`TryFromSexp`]: crate::TryFromSexp
14//! [`with_r_thread`]: crate::worker::with_r_thread
15//! [`with_r_unwind_protect`]: crate::unwind_protect::with_r_unwind_protect
16//!
17//! # Checked vs `*_unchecked` variants
18//!
19//! Most non-variadic R API entry points come in two forms thanks to the
20//! [`#[r_ffi_checked]`](miniextendr_macros::r_ffi_checked) proc-macro applied
21//! to the `unsafe extern "C-unwind"` blocks below:
22//!
23//! - **Checked** (default — e.g. `Rf_allocVector`, `Rf_protect`, `INTEGER`):
24//! debug-asserts you're on R's main thread, routing through
25//! [`crate::worker::with_r_thread`] when called from a worker thread. **Use
26//! these by default.**
27//! - **`*_unchecked`** (e.g. `Rf_allocVector_unchecked`): bypass the assertion
28//! and the worker round-trip. Calling one off the R main thread is
29//! undefined behaviour. They exist for three known-safe contexts:
30//! 1. Inside ALTREP callbacks — R is already calling us on the main thread.
31//! 2. Inside a [`crate::unwind_protect::with_r_unwind_protect`] body —
32//! the guard has already established main-thread context.
33//! 3. Inside a [`crate::worker::with_r_thread`] body — the check would be
34//! redundant.
35//!
36//! The build-time lint **MXL301** enforces this: any `*_unchecked` call
37//! outside those contexts is a compile-time error.
38//!
39//! # Don't raise R errors directly
40//!
41//! `Rf_error`, `Rf_errorcall`, and their `_unchecked` siblings longjmp,
42//! which **skips Rust destructors** and leaks resources. The lint **MXL300**
43//! forbids them in user code. Use `panic!()` instead; the framework converts
44//! the panic into a structured R condition with `rust_*` class layering via
45//! the tagged-SEXP transport (see [`crate::error_value`]).
46//!
47//! # Cross references
48//!
49//! - [`crate::ffi_guard`] — guard taxonomy and worker-thread invariants.
50//! - [`crate::thread`] / [`crate::worker`] — worker / main-thread split.
51//! - [`crate::altrep_traits`] / [`crate::altrep_bridge`] — guard modes
52//! inside ALTREP callbacks.
53//! - [`crate::error_value`] / [`mod@crate::condition`] — panic → R condition
54//! transport.
55
56/// Raw ALTREP C API method type aliases.
57pub mod altrep;
58
59// `extern "C-unwind"` signatures below reference the type vocabulary by
60// bare name. Bring it into scope as a private `use` (NOT `pub use`) — the
61// vocab's canonical home is the crate root (`crate::SEXP`, etc.) and
62// `crate::sexp_types` for the niche helpers. Adding these to the public
63// API of `sys::` would re-create the bridge.
64use crate::sexp::SEXP;
65use crate::sexp_types::{R_CFinalizer_t, R_xlen_t, Rboolean, Rbyte, Rcomplex, SEXPTYPE, cetype_t};
66
67// region: Connections types (gated behind `connections` feature)
68// WARNING: R's connection API is explicitly marked as UNSTABLE.
69
70/// Opaque R connection implementation (from R_ext/Connections.h).
71///
72/// This is an opaque type representing R's internal connection structure.
73/// The actual structure is explicitly unstable and may change between R versions.
74#[cfg(feature = "connections")]
75#[repr(C)]
76#[allow(non_camel_case_types)]
77pub struct Rconnection_impl(::std::os::raw::c_void);
78
79/// Pointer to an R connection handle.
80///
81/// This is the typed equivalent of R's `Rconnection` type, which is a pointer
82/// to the opaque `Rconn` struct. Using this instead of `*mut c_void` provides
83/// type safety for connection APIs.
84#[cfg(feature = "connections")]
85#[allow(non_camel_case_types)]
86pub type Rconnection = *mut Rconnection_impl;
87
88/// R connections API version from R's `R_ext/Connections.h` at compile time.
89///
90/// This is a compile-time constant baked into the Rust FFI bindings when they
91/// were generated against a particular R version's headers. It does **not**
92/// dynamically probe the running R session.
93///
94/// From R_ext/Connections.h: "you *must* check the version and proceed only
95/// if it matches what you expect. We explicitly reserve the right to change
96/// the connection implementation without a compatibility layer."
97///
98/// Before using any connection APIs, check that this equals the expected version (1).
99#[cfg(feature = "connections")]
100#[allow(non_upper_case_globals)]
101pub const R_CONNECTIONS_VERSION: ::std::os::raw::c_int = 1;
102
103// endregion
104
105use miniextendr_macros::r_ffi_checked;
106
107// Unchecked variadic functions (internal use only, no thread check)
108#[allow(clashing_extern_declarations)]
109#[allow(varargs_without_pattern)]
110unsafe extern "C-unwind" {
111 /// Unchecked variadic `Rf_error`; call checked wrapper when possible.
112 #[link_name = "Rf_error"]
113 pub fn Rf_error_unchecked(arg1: *const ::std::os::raw::c_char, ...) -> !;
114 /// Unchecked variadic `Rf_errorcall`; call checked wrapper when possible.
115 #[link_name = "Rf_errorcall"]
116 pub fn Rf_errorcall_unchecked(arg1: SEXP, arg2: *const ::std::os::raw::c_char, ...) -> !;
117 /// Unchecked variadic `Rf_warning`; call checked wrapper when possible.
118 #[link_name = "Rf_warning"]
119 pub fn Rf_warning_unchecked(arg1: *const ::std::os::raw::c_char, ...);
120 /// Unchecked variadic `Rprintf`; call checked wrapper when possible.
121 #[link_name = "Rprintf"]
122 pub fn Rprintf_unchecked(arg1: *const ::std::os::raw::c_char, ...);
123 /// Unchecked variadic `REprintf`; call checked wrapper when possible.
124 #[link_name = "REprintf"]
125 pub fn REprintf_unchecked(arg1: *const ::std::os::raw::c_char, ...);
126}
127
128// Error message access (non-API, declared in Rinternals.h but flagged by R CMD check)
129#[cfg(feature = "nonapi")]
130unsafe extern "C-unwind" {
131 /// Get the current R error message buffer.
132 ///
133 /// Returns a pointer to R's internal error message buffer.
134 /// Used by Rserve and other embedding applications.
135 ///
136 /// # Safety
137 ///
138 /// - The returned pointer is only valid until the next R error
139 /// - Must not be modified
140 /// - Should be copied if needed beyond the immediate scope
141 ///
142 /// # Feature Gate
143 ///
144 /// This is a non-API function and requires the `nonapi` feature.
145 #[allow(non_snake_case, dead_code)] // used by worker.rs under worker-thread feature
146 pub(crate) fn R_curErrorBuf() -> *const ::std::os::raw::c_char;
147}
148
149// Console hooks (non-API; declared in Rinterface.h)
150#[cfg(feature = "nonapi")]
151unsafe extern "C-unwind" {
152 #[expect(dead_code, reason = "declared for future use")]
153 pub(crate) static ptr_R_WriteConsoleEx: Option<
154 unsafe extern "C-unwind" fn(
155 *const ::std::os::raw::c_char,
156 ::std::os::raw::c_int,
157 ::std::os::raw::c_int,
158 ),
159 >;
160}
161
162/// Checked wrapper for `Rf_error` - panics if called from non-main thread.
163/// Common usage: `Rf_error(c"%s".as_ptr(), message.as_ptr())`
164///
165/// # Safety
166///
167/// - Must be called from the R main thread
168/// - `fmt` and `arg1` must be valid null-terminated C strings
169#[inline(always)]
170#[allow(non_snake_case)]
171pub unsafe fn Rf_error(
172 fmt: *const ::std::os::raw::c_char,
173 arg1: *const ::std::os::raw::c_char,
174) -> ! {
175 if !crate::worker::is_r_main_thread() {
176 panic!("Rf_error called from non-main thread");
177 }
178 unsafe { Rf_error_unchecked(fmt, arg1) }
179}
180
181/// Checked wrapper for `Rf_errorcall` - panics if called from non-main thread.
182///
183/// # Safety
184///
185/// - Must be called from the R main thread
186/// - `call` must be a valid SEXP or R_NilValue
187/// - `fmt` and `arg1` must be valid null-terminated C strings
188#[inline(always)]
189#[allow(non_snake_case)]
190pub unsafe fn Rf_errorcall(
191 call: SEXP,
192 fmt: *const ::std::os::raw::c_char,
193 arg1: *const ::std::os::raw::c_char,
194) -> ! {
195 if !crate::worker::is_r_main_thread() {
196 panic!("Rf_errorcall called from non-main thread");
197 }
198 unsafe { Rf_errorcall_unchecked(call, fmt, arg1) }
199}
200
201/// Checked wrapper for `Rf_warning` - panics if called from non-main thread.
202///
203/// # Safety
204///
205/// - Must be called from the R main thread
206/// - `fmt` and `arg1` must be valid null-terminated C strings
207#[inline(always)]
208#[allow(non_snake_case)]
209pub unsafe fn Rf_warning(fmt: *const ::std::os::raw::c_char, arg1: *const ::std::os::raw::c_char) {
210 if !crate::worker::is_r_main_thread() {
211 panic!("Rf_warning called from non-main thread");
212 }
213 unsafe { Rf_warning_unchecked(fmt, arg1) }
214}
215
216/// Checked wrapper for `Rprintf` - panics if called from non-main thread.
217///
218/// # Safety
219///
220/// - Must be called from the R main thread
221/// - `fmt` and `arg1` must be valid null-terminated C strings
222#[inline(always)]
223#[allow(non_snake_case)]
224pub unsafe fn Rprintf(fmt: *const ::std::os::raw::c_char, arg1: *const ::std::os::raw::c_char) {
225 if !crate::worker::is_r_main_thread() {
226 panic!("Rprintf called from non-main thread");
227 }
228 unsafe { Rprintf_unchecked(fmt, arg1) }
229}
230
231/// Print to R's stderr (via R_ShowMessage or error console).
232///
233/// # Safety
234///
235/// - Must be called from the R main thread
236/// - `fmt` and `arg1` must be valid null-terminated C strings
237#[inline(always)]
238#[allow(non_snake_case)]
239pub unsafe fn REprintf(fmt: *const ::std::os::raw::c_char, arg1: *const ::std::os::raw::c_char) {
240 if !crate::worker::is_r_main_thread() {
241 panic!("REprintf called from non-main thread");
242 }
243 unsafe { REprintf_unchecked(fmt, arg1) }
244}
245
246// Imported R symbols and functions with runtime thread checks enabled.
247#[allow(missing_docs)]
248#[r_ffi_checked]
249#[allow(clashing_extern_declarations)]
250unsafe extern "C-unwind" {
251 /// The canonical R `NULL` value.
252 pub static R_NilValue: SEXP;
253
254 #[doc(alias = "NA_STRING")]
255 /// Missing string singleton — encapsulated by SEXP::na_string()
256 pub static R_NaString: SEXP;
257 /// Empty string CHARSXP — encapsulated by SEXP::blank_string()
258 pub static R_BlankString: SEXP;
259 /// Symbol for `names` attribute.
260 // Attribute symbols — encapsulated by SexpExt methods and SEXP::*_symbol()
261 pub static R_NamesSymbol: SEXP;
262 pub static R_DimSymbol: SEXP;
263 pub static R_DimNamesSymbol: SEXP;
264 pub static R_ClassSymbol: SEXP;
265 pub static R_RowNamesSymbol: SEXP;
266 pub static R_LevelsSymbol: SEXP;
267 pub static R_TspSymbol: SEXP;
268
269 /// Global environment (`.GlobalEnv`).
270 pub static R_GlobalEnv: SEXP;
271 /// Base package namespace environment.
272 pub static R_BaseEnv: SEXP;
273 /// Empty root environment.
274 pub static R_EmptyEnv: SEXP;
275 /// Base package namespace — encapsulated by SEXP::base_namespace()
276 pub static R_BaseNamespace: SEXP;
277
278 /// The "missing argument" sentinel value.
279 ///
280 /// When an R function is called without providing a value for a formal
281 /// argument, R passes `R_MissingArg` as a placeholder. This is different
282 /// from `R_NilValue` (NULL) - a missing argument means "not provided",
283 /// while NULL is an explicit value.
284 ///
285 /// In R: `f <- function(x) missing(x); f()` returns `TRUE`.
286 /// Encapsulated by SEXP::missing_arg()
287 pub static R_MissingArg: SEXP;
288
289 /// Sentinel returned by `Rf_findVarInFrame`/`Rf_findVarInFrame3` when the
290 /// symbol has no binding in the searched frame(s).
291 pub static R_UnboundValue: SEXP;
292
293 // Issue #112 cat. 10: kept pub(crate) — single-caller utilities; wrapping adds no value
294 // Rinterface.h
295 pub(crate) fn R_FlushConsole();
296
297 // Special logical values (from internal Defn.h, not public API)
298 // These are gated behind `nonapi` feature as they may change across R versions.
299 #[cfg(feature = "nonapi")]
300 /// Non-API TRUE singleton.
301 pub static R_TrueValue: SEXP;
302 #[cfg(feature = "nonapi")]
303 /// Non-API FALSE singleton.
304 pub static R_FalseValue: SEXP;
305 #[cfg(feature = "nonapi")]
306 /// Non-API NA logical singleton.
307 pub static R_LogicalNAValue: SEXP;
308
309 // Rinternals.h
310 #[doc(alias = "mkChar")]
311 pub fn Rf_mkChar(s: *const ::std::os::raw::c_char) -> SEXP;
312 #[doc(alias = "mkCharLen")]
313 pub fn Rf_mkCharLen(s: *const ::std::os::raw::c_char, len: i32) -> SEXP;
314 #[doc(alias = "mkCharLenCE")]
315 pub fn Rf_mkCharLenCE(
316 x: *const ::std::os::raw::c_char,
317 len: ::std::os::raw::c_int,
318 ce: cetype_t,
319 ) -> SEXP;
320 #[doc(alias = "xlength")]
321 #[doc(alias = "XLENGTH")]
322 pub fn Rf_xlength(x: SEXP) -> R_xlen_t;
323 #[doc(alias = "translateCharUTF8")]
324 pub fn Rf_translateCharUTF8(x: SEXP) -> *const ::std::os::raw::c_char;
325 #[doc(alias = "getCharCE")]
326 pub fn Rf_getCharCE(x: SEXP) -> cetype_t;
327 #[doc(alias = "charIsASCII")]
328 pub fn Rf_charIsASCII(x: SEXP) -> Rboolean;
329 #[doc(alias = "charIsUTF8")]
330 pub fn Rf_charIsUTF8(x: SEXP) -> Rboolean;
331 #[doc(alias = "charIsLatin1")]
332 pub fn Rf_charIsLatin1(x: SEXP) -> Rboolean;
333
334 // Issue #112 cat. 3: kept pub(crate) — only called from unwind_protect.rs; users go through with_r_unwind_protect
335 pub(crate) fn R_MakeUnwindCont() -> SEXP;
336 pub(crate) fn R_ContinueUnwind(cont: SEXP) -> !;
337 pub(crate) fn R_UnwindProtect(
338 fun: ::std::option::Option<
339 unsafe extern "C-unwind" fn(*mut ::std::os::raw::c_void) -> SEXP,
340 >,
341 fun_data: *mut ::std::os::raw::c_void,
342 cleanfun: ::std::option::Option<
343 unsafe extern "C-unwind" fn(*mut ::std::os::raw::c_void, Rboolean),
344 >,
345 cleanfun_data: *mut ::std::os::raw::c_void,
346 cont: SEXP,
347 ) -> SEXP;
348
349 /// Version of `R_UnwindProtect` that accepts `extern "C-unwind"` function pointers
350 #[link_name = "R_UnwindProtect"]
351 pub(crate) fn R_UnwindProtect_C_unwind(
352 fun: ::std::option::Option<
353 unsafe extern "C-unwind" fn(*mut ::std::os::raw::c_void) -> SEXP,
354 >,
355 fun_data: *mut ::std::os::raw::c_void,
356 cleanfun: ::std::option::Option<
357 unsafe extern "C-unwind" fn(*mut ::std::os::raw::c_void, Rboolean),
358 >,
359 cleanfun_data: *mut ::std::os::raw::c_void,
360 cont: SEXP,
361 ) -> SEXP;
362
363 // Rinternals.h
364 // Issue #112 cat. 2: kept pub(crate) — ExternalPtr<T> encapsulates these for users; raw access needed within externalptr.rs
365 #[doc = " External pointer interface"]
366 pub(crate) fn R_MakeExternalPtr(p: *mut ::std::os::raw::c_void, tag: SEXP, prot: SEXP) -> SEXP;
367 pub fn R_ExternalPtrAddr(s: SEXP) -> *mut ::std::os::raw::c_void;
368 pub(crate) fn R_ExternalPtrTag(s: SEXP) -> SEXP;
369 pub(crate) fn R_ExternalPtrProtected(s: SEXP) -> SEXP;
370 pub(crate) fn R_ClearExternalPtr(s: SEXP);
371 pub(crate) fn R_SetExternalPtrAddr(s: SEXP, p: *mut ::std::os::raw::c_void);
372 pub(crate) fn R_SetExternalPtrTag(s: SEXP, tag: SEXP);
373 pub(crate) fn R_SetExternalPtrProtected(s: SEXP, p: SEXP);
374 #[doc = " Added in R 3.4.0"]
375 pub fn R_MakeExternalPtrFn(p: DL_FUNC, tag: SEXP, prot: SEXP) -> SEXP;
376 pub fn R_ExternalPtrAddrFn(s: SEXP) -> DL_FUNC;
377 pub fn R_RegisterFinalizer(s: SEXP, fun: SEXP);
378 pub(crate) fn R_RegisterCFinalizer(s: SEXP, fun: R_CFinalizer_t);
379 pub fn R_RegisterFinalizerEx(s: SEXP, fun: SEXP, onexit: Rboolean);
380 pub(crate) fn R_RegisterCFinalizerEx(s: SEXP, fun: R_CFinalizer_t, onexit: Rboolean);
381
382 // R_ext/Rdynload.h - C-callable interface
383 // Issue #112 cat. 10: kept pub(crate) — cross-package ABI helpers used from mx_abi.rs; wrapping adds no value
384 /// Register a C-callable function for cross-package access.
385 pub(crate) fn R_RegisterCCallable(
386 package: *const ::std::os::raw::c_char,
387 name: *const ::std::os::raw::c_char,
388 fptr: DL_FUNC,
389 );
390 /// Get a C-callable function from another package.
391 pub(crate) fn R_GetCCallable(
392 package: *const ::std::os::raw::c_char,
393 name: *const ::std::os::raw::c_char,
394 ) -> DL_FUNC;
395
396 // region: GC protection
397 //
398 // R has two GC protection mechanisms with very different cost profiles:
399 //
400 // ## Protect stack (`Rf_protect` / `Rf_unprotect`)
401 //
402 // A pre-allocated array (`R_PPStack`) with an integer index (`R_PPStackTop`).
403 // Protect pushes: `R_PPStack[R_PPStackTop++] = s`.
404 // Unprotect pops: `R_PPStackTop -= n`.
405 // **No heap allocation. No GC pressure. Essentially a single memory write.**
406 // Use this for temporary protection within a function.
407 // Requires LIFO discipline — nested scopes are fine, interleaved are not.
408 //
409 // ## Precious list (`R_PreserveObject` / `R_ReleaseObject`)
410 //
411 // A global linked list of CONSXP cells (`R_PreciousList`).
412 // Preserve: `CONS(object, R_PreciousList)` — **allocates a cons cell every call**.
413 // Release: linear scan of the entire list to find and unlink the object — **O(n)**.
414 // (Optional `R_HASH_PRECIOUS` env var enables a 1069-bucket hash table, improving
415 // Release to O(bucket_size), but Preserve still allocates.)
416 // Use this only for long-lived objects that outlive any single protect scope.
417 //
418 // ## Cost summary
419 //
420 // | Operation | Cost | Allocates? |
421 // |----------------------|--------------------|------------|
422 // | `Rf_protect` | array write | no |
423 // | `Rf_unprotect(n)` | integer subtract | no |
424 // | `Rf_unprotect_ptr` | scan + shift | no |
425 // | `R_PreserveObject` | cons cell alloc | **yes** |
426 // | `R_ReleaseObject` | linked list scan | no (O(n)) |
427 // | `R_ProtectWithIndex` | array write + save | no |
428 // | `R_Reprotect` | array index write | no |
429
430 /// Add a SEXP to the protect stack, preventing GC collection.
431 ///
432 /// **Cost: O(1)** — single array write (`R_PPStack[top++] = s`). No allocation.
433 ///
434 /// Must be balanced by a corresponding `Rf_unprotect`. The protect stack is
435 /// LIFO — nested scopes are safe, but interleaved usage from different scopes
436 /// will cause incorrect unprotection.
437 #[doc(alias = "PROTECT")]
438 #[doc(alias = "protect")]
439 pub fn Rf_protect(s: SEXP) -> SEXP;
440
441 /// Pop the top `l` entries from the protect stack.
442 ///
443 /// **Cost: O(1)** — single integer subtract (`R_PPStackTop -= l`). No allocation.
444 ///
445 /// The popped SEXPs become eligible for GC. Must match the number of
446 /// `Rf_protect` calls in the current scope (LIFO order).
447 #[doc(alias = "UNPROTECT")]
448 #[doc(alias = "unprotect")]
449 pub fn Rf_unprotect(l: ::std::os::raw::c_int);
450
451 /// Remove a specific SEXP from anywhere in the protect stack.
452 ///
453 /// **Cost: O(k)** — scans backwards from top (k = distance from top), then
454 /// shifts remaining entries down. No allocation. R source comment:
455 /// *"should be among the top few items"*.
456 ///
457 /// Unlike `Rf_unprotect`, this is order-independent — it finds and removes
458 /// the specific pointer regardless of stack position. Useful when LIFO
459 /// discipline cannot be maintained, but more expensive than `Rf_unprotect`.
460 #[doc(alias = "UNPROTECT_PTR")]
461 pub fn Rf_unprotect_ptr(s: SEXP);
462
463 /// Add a SEXP to the global precious list, preventing GC indefinitely.
464 ///
465 /// **Cost: O(1) but allocates a CONSXP cell** — creates GC pressure on every
466 /// call. The precious list is a global linked list (`R_PreciousList`).
467 ///
468 /// Use only for long-lived objects (e.g., ExternalPtr stored across R calls).
469 /// For temporary protection within a function, prefer `Rf_protect`.
470 pub fn R_PreserveObject(object: SEXP);
471
472 /// Remove a SEXP from the global precious list, allowing GC.
473 ///
474 /// **Cost: O(n)** — linear scan of the entire precious list to find and unlink
475 /// the cons cell. With `R_HASH_PRECIOUS` env var, O(bucket_size) average
476 /// via a 1069-bucket hash table, but this is off by default.
477 pub fn R_ReleaseObject(object: SEXP);
478
479 // endregion
480 // Vector allocation functions
481 #[doc(alias = "allocVector")]
482 pub fn Rf_allocVector(sexptype: SEXPTYPE, length: R_xlen_t) -> SEXP;
483 #[doc(alias = "allocMatrix")]
484 pub fn Rf_allocMatrix(
485 sexptype: SEXPTYPE,
486 nrow: ::std::os::raw::c_int,
487 ncol: ::std::os::raw::c_int,
488 ) -> SEXP;
489 #[doc(alias = "allocArray")]
490 pub fn Rf_allocArray(sexptype: SEXPTYPE, dims: SEXP) -> SEXP;
491 #[doc(alias = "alloc3DArray")]
492 pub fn Rf_alloc3DArray(
493 sexptype: SEXPTYPE,
494 nrow: ::std::os::raw::c_int,
495 ncol: ::std::os::raw::c_int,
496 nface: ::std::os::raw::c_int,
497 ) -> SEXP;
498
499 // Pairlist allocation
500 // Issue #112 cat. 10: kept pub(crate) — 2 callers in expression.rs/dots.rs; wrapping adds no value
501 #[doc(alias = "allocList")]
502 pub(crate) fn Rf_allocList(n: ::std::os::raw::c_int) -> SEXP;
503 #[doc(alias = "allocLang")]
504 pub fn Rf_allocLang(n: ::std::os::raw::c_int) -> SEXP;
505 #[doc(alias = "allocS4Object")]
506 pub fn Rf_allocS4Object() -> SEXP;
507
508 // Pairlist construction — encapsulated by PairListExt trait
509 pub fn Rf_cons(car: SEXP, cdr: SEXP) -> SEXP;
510 pub fn Rf_lcons(car: SEXP, cdr: SEXP) -> SEXP;
511
512 // Attribute manipulation — encapsulated by SexpExt methods
513 #[doc(alias = "setAttrib")]
514 pub fn Rf_setAttrib(vec: SEXP, name: SEXP, val: SEXP) -> SEXP;
515
516 // Rinternals.h — scalar constructors; encapsulated by SEXP::scalar_*() / scalar_*_unchecked()
517 #[doc(alias = "ScalarComplex")]
518 pub fn Rf_ScalarComplex(x: Rcomplex) -> SEXP;
519 #[doc(alias = "ScalarInteger")]
520 pub fn Rf_ScalarInteger(x: ::std::os::raw::c_int) -> SEXP;
521 #[doc(alias = "ScalarLogical")]
522 pub fn Rf_ScalarLogical(x: ::std::os::raw::c_int) -> SEXP;
523 #[doc(alias = "ScalarRaw")]
524 pub fn Rf_ScalarRaw(x: Rbyte) -> SEXP;
525 #[doc(alias = "ScalarReal")]
526 pub fn Rf_ScalarReal(x: f64) -> SEXP;
527 #[doc(alias = "ScalarString")]
528 pub fn Rf_ScalarString(x: SEXP) -> SEXP;
529
530 // Rinternals.h
531 /// Non-API function - use DATAPTR_RO or DATAPTR_OR_NULL instead.
532 /// Only available with `nonapi` feature.
533 #[cfg(feature = "nonapi")]
534 pub(crate) fn DATAPTR(x: SEXP) -> *mut ::std::os::raw::c_void;
535 pub fn DATAPTR_RO(x: SEXP) -> *const ::std::os::raw::c_void;
536 pub fn DATAPTR_OR_NULL(x: SEXP) -> *const ::std::os::raw::c_void;
537
538 // region: Cons Cell (Pairlist) Accessors
539 //
540 // R's pairlists (LISTSXP) are cons cells like in Lisp/Scheme. Each node has:
541 // - CAR: The value/head element
542 // - CDR: The rest/tail of the list (another pairlist or R_NilValue)
543 // - TAG: An optional name (symbol) for named lists/arguments
544 //
545 // Example R pairlist: list(a = 1, b = 2, 3)
546 // - First node: CAR=1, TAG="a", CDR=<next node>
547 // - Second node: CAR=2, TAG="b", CDR=<next node>
548 // - Third node: CAR=3, TAG=NULL, CDR=R_NilValue
549 //
550 // Pairlists are used for:
551 // - Function arguments (formal parameters and actual arguments)
552 // - Language objects (calls)
553 // - Dotted pairs in old-style lists
554 //
555 // The names CAR/CDR come from Lisp:
556 // - CAR = "Contents of Address part of Register"
557 // - CDR = "Contents of Decrement part of Register" (pronounced "could-er")
558 //
559 // Modern R mostly uses generic vectors (VECSXP) instead of pairlists,
560 // but pairlists are still used internally for function calls.
561
562 // Pairlist accessors — basic ops encapsulated by PairListExt trait,
563 // compound accessors (CAAR, CADR, etc.) module-private since no callers exist.
564 pub fn CAR(e: SEXP) -> SEXP;
565 pub fn CDR(e: SEXP) -> SEXP;
566 pub fn CAAR(e: SEXP) -> SEXP;
567 pub fn CDAR(e: SEXP) -> SEXP;
568 pub fn CADR(e: SEXP) -> SEXP;
569 pub fn CDDR(e: SEXP) -> SEXP;
570 pub fn CADDR(e: SEXP) -> SEXP;
571 pub fn CADDDR(e: SEXP) -> SEXP;
572 pub fn CAD4R(e: SEXP) -> SEXP;
573 pub fn TAG(e: SEXP) -> SEXP;
574 pub fn SET_TAG(x: SEXP, y: SEXP);
575 pub fn SETCAR(x: SEXP, y: SEXP) -> SEXP;
576 pub fn SETCDR(x: SEXP, y: SEXP) -> SEXP;
577 pub fn SETCADR(x: SEXP, y: SEXP) -> SEXP;
578 pub fn SETCADDR(x: SEXP, y: SEXP) -> SEXP;
579 pub fn SETCADDDR(x: SEXP, y: SEXP) -> SEXP;
580 pub fn SETCAD4R(e: SEXP, y: SEXP) -> SEXP;
581 pub fn LOGICAL_OR_NULL(x: SEXP) -> *const ::std::os::raw::c_int;
582 pub fn INTEGER_OR_NULL(x: SEXP) -> *const ::std::os::raw::c_int;
583 pub fn REAL_OR_NULL(x: SEXP) -> *const f64;
584 pub fn COMPLEX_OR_NULL(x: SEXP) -> *const Rcomplex;
585 pub fn RAW_OR_NULL(x: SEXP) -> *const Rbyte;
586
587 // Element-wise accessors (ALTREP-aware) — encapsulated by SexpExt methods
588 pub fn INTEGER_ELT(x: SEXP, i: R_xlen_t) -> ::std::os::raw::c_int;
589 pub fn REAL_ELT(x: SEXP, i: R_xlen_t) -> f64;
590 pub fn LOGICAL_ELT(x: SEXP, i: R_xlen_t) -> ::std::os::raw::c_int;
591 pub fn COMPLEX_ELT(x: SEXP, i: R_xlen_t) -> Rcomplex;
592 pub fn RAW_ELT(x: SEXP, i: R_xlen_t) -> Rbyte;
593 pub fn VECTOR_ELT(x: SEXP, i: R_xlen_t) -> SEXP;
594 pub fn STRING_ELT(x: SEXP, i: R_xlen_t) -> SEXP;
595 pub fn SET_STRING_ELT(x: SEXP, i: R_xlen_t, v: SEXP);
596 pub fn SET_LOGICAL_ELT(x: SEXP, i: R_xlen_t, v: ::std::os::raw::c_int);
597 pub fn SET_INTEGER_ELT(x: SEXP, i: R_xlen_t, v: ::std::os::raw::c_int);
598 pub fn SET_REAL_ELT(x: SEXP, i: R_xlen_t, v: f64);
599 pub fn SET_COMPLEX_ELT(x: SEXP, i: R_xlen_t, v: Rcomplex);
600 pub fn SET_RAW_ELT(x: SEXP, i: R_xlen_t, v: Rbyte);
601 pub fn SET_VECTOR_ELT(x: SEXP, i: R_xlen_t, v: SEXP) -> SEXP;
602
603 // endregion
604
605 // region: SEXP metadata accessors
606
607 /// Get the length of a SEXP as `int` (for short vectors < 2^31).
608 ///
609 /// For long vectors, use `Rf_xlength()` instead.
610 /// Returns 0 for R_NilValue.
611 pub fn LENGTH(x: SEXP) -> ::std::os::raw::c_int;
612
613 /// Get the length of a SEXP as `R_xlen_t` (supports long vectors).
614 ///
615 /// ALTREP-aware: will call ALTREP Length method if needed.
616 pub fn XLENGTH(x: SEXP) -> R_xlen_t;
617
618 /// Get the true length (allocated capacity) of a vector.
619 ///
620 /// May be larger than LENGTH for vectors with reserved space.
621 /// ALTREP-aware.
622 pub fn TRUELENGTH(x: SEXP) -> R_xlen_t;
623
624 /// Get the attributes pairlist of a SEXP.
625 ///
626 /// Returns R_NilValue if no attributes.
627 pub fn ATTRIB(x: SEXP) -> SEXP;
628
629 /// Set the attributes pairlist of a SEXP.
630 ///
631 /// # Safety
632 ///
633 /// `v` must be a pairlist or R_NilValue
634 pub fn SET_ATTRIB(x: SEXP, v: SEXP);
635
636 /// Check if SEXP has the "object" bit set (has a class).
637 ///
638 /// Returns non-zero if object has a class attribute.
639 pub fn OBJECT(x: SEXP) -> ::std::os::raw::c_int;
640
641 /// Set the "object" bit.
642 pub fn SET_OBJECT(x: SEXP, v: ::std::os::raw::c_int);
643
644 /// Get the LEVELS field (for factors).
645 pub fn LEVELS(x: SEXP) -> ::std::os::raw::c_int;
646
647 /// Set the LEVELS field (for factors).
648 ///
649 /// Returns the value that was set.
650 pub fn SETLEVELS(x: SEXP, v: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
651
652 // endregion
653
654 // region: ALTREP support — data2 encapsulated by AltrepSexpExt; data1 via standalone helpers
655
656 // Issue #112 cat. 6: pub(crate) — no AltrepSexpExt method yet; available for future callers
657 pub(crate) fn ALTREP_CLASS(x: SEXP) -> SEXP;
658 pub fn R_altrep_data1(x: SEXP) -> SEXP;
659 pub fn R_altrep_data2(x: SEXP) -> SEXP;
660 pub fn R_set_altrep_data1(x: SEXP, v: SEXP);
661 pub fn R_set_altrep_data2(x: SEXP, v: SEXP);
662
663 /// Check if a SEXP is an ALTREP object (returns non-zero if true).
664 ///
665 /// Use `SexpExt::is_altrep()` instead of calling this directly.
666 pub fn ALTREP(x: SEXP) -> ::std::os::raw::c_int;
667
668 // endregion
669
670 // region: Vector data accessors (mutable pointers)
671 // Issue #112 cat. 5: kept pub(crate) — raw pointer access needed in RNativeType impls and scattered callers;
672 // partial migration to SexpExt::as_mut_slice() tracked in follow-up issue
673
674 /// Get mutable pointer to logical vector data.
675 ///
676 /// For ALTREP vectors, this may force materialization.
677 /// Get mutable pointer to logical vector data.
678 ///
679 /// For ALTREP vectors, this may force materialization.
680 /// Prefer `SexpExt::set_logical_elt()` / `SexpExt::logical_elt()`.
681 pub(crate) fn LOGICAL(x: SEXP) -> *mut ::std::os::raw::c_int;
682
683 /// Get mutable pointer to integer vector data.
684 ///
685 /// For ALTREP vectors, this may force materialization.
686 /// Prefer `SexpExt::set_integer_elt()` / `SexpExt::integer_elt()`.
687 pub(crate) fn INTEGER(x: SEXP) -> *mut ::std::os::raw::c_int;
688
689 /// Get mutable pointer to real vector data.
690 ///
691 /// For ALTREP vectors, this may force materialization.
692 /// Prefer `SexpExt::set_real_elt()` / `SexpExt::real_elt()`.
693 pub(crate) fn REAL(x: SEXP) -> *mut f64;
694
695 /// Get mutable pointer to complex vector data.
696 ///
697 /// For ALTREP vectors, this may force materialization.
698 /// Prefer `SexpExt::set_complex_elt()` / `SexpExt::complex_elt()`.
699 pub(crate) fn COMPLEX(x: SEXP) -> *mut Rcomplex;
700
701 /// Get mutable pointer to raw vector data.
702 ///
703 /// For ALTREP vectors, this may force materialization.
704 /// Prefer `SexpExt::set_raw_elt()` / `SexpExt::raw_elt()`.
705 pub(crate) fn RAW(x: SEXP) -> *mut Rbyte;
706
707 // endregion
708
709 // region: User interrupt and utilities
710
711 // utils.h
712 pub fn R_CheckUserInterrupt();
713
714 // endregion
715
716 // region: Type checking — encapsulated by SexpExt::type_of()
717
718 pub fn TYPEOF(x: SEXP) -> SEXPTYPE;
719
720 // endregion
721
722 // Symbol creation and access
723 #[doc(alias = "install")]
724 pub fn Rf_install(name: *const ::std::os::raw::c_char) -> SEXP;
725 /// Get the print name (CHARSXP) of a symbol (SYMSXP)
726 pub fn PRINTNAME(x: SEXP) -> SEXP;
727 /// Get the C string pointer from a CHARSXP — encapsulated by SexpExt::r_char()
728 #[doc(alias = "CHAR")]
729 pub fn R_CHAR(x: SEXP) -> *const ::std::os::raw::c_char;
730
731 // Attribute access
732 // Attribute accessors — encapsulated by SexpExt methods
733 /// Read an attribute from an object by symbol (e.g. `R_NamesSymbol`).
734 ///
735 /// Returns `R_NilValue` if the attribute is not set.
736 #[doc(alias = "getAttrib")]
737 pub fn Rf_getAttrib(vec: SEXP, name: SEXP) -> SEXP;
738 /// Set the `names` attribute; returns the updated object.
739 #[doc(alias = "namesgets")]
740 pub fn Rf_namesgets(vec: SEXP, val: SEXP) -> SEXP;
741 /// Set the `dim` attribute; returns the updated object.
742 #[doc(alias = "dimgets")]
743 pub fn Rf_dimgets(vec: SEXP, val: SEXP) -> SEXP;
744
745 // Duplication
746 #[doc(alias = "duplicate")]
747 pub fn Rf_duplicate(s: SEXP) -> SEXP;
748 #[doc(alias = "shallow_duplicate")]
749 pub fn Rf_shallow_duplicate(s: SEXP) -> SEXP;
750
751 // Object comparison
752 /// Check if two R objects are identical (deep semantic equality).
753 ///
754 /// This is the C implementation of R's `identical()` function.
755 ///
756 /// # Flags
757 ///
758 /// Use the `IDENT_*` constants below. Flags are inverted: set bit = disable that check.
759 ///
760 /// **Default from R**: `IDENT_USE_CLOENV` (16) - ignore closure environments
761 ///
762 /// # Returns
763 ///
764 /// `TRUE` if identical, `FALSE` otherwise.
765 ///
766 /// # Performance
767 ///
768 /// Fast-path: Returns `TRUE` immediately if pointers are equal.
769 pub fn R_compute_identical(x: SEXP, y: SEXP, flags: ::std::os::raw::c_int) -> Rboolean;
770}
771
772/// Flags for `R_compute_identical` (bitmask, inverted logic: set bit = disable check).
773pub const IDENT_NUM_AS_BITS: ::std::os::raw::c_int = 1;
774/// Treat all NAs as identical (ignore NA payload differences).
775pub const IDENT_NA_AS_BITS: ::std::os::raw::c_int = 2;
776/// Compare attributes in order (not as a set).
777pub const IDENT_ATTR_BY_ORDER: ::std::os::raw::c_int = 4;
778/// Include bytecode in comparison.
779pub const IDENT_USE_BYTECODE: ::std::os::raw::c_int = 8;
780/// Include closure environments in comparison.
781pub const IDENT_USE_CLOENV: ::std::os::raw::c_int = 16;
782/// Include source references in comparison.
783pub const IDENT_USE_SRCREF: ::std::os::raw::c_int = 32;
784/// Compare external pointers as references (not by address).
785pub const IDENT_EXTPTR_AS_REF: ::std::os::raw::c_int = 64;
786
787// Additional checked R API declarations used by conversion and reflection code.
788#[allow(missing_docs)]
789#[r_ffi_checked]
790unsafe extern "C-unwind" {
791 // Type coercion — encapsulated by SexpExt methods
792 #[doc(alias = "asLogical")]
793 pub fn Rf_asLogical(x: SEXP) -> ::std::os::raw::c_int;
794 #[doc(alias = "asInteger")]
795 pub fn Rf_asInteger(x: SEXP) -> ::std::os::raw::c_int;
796 #[doc(alias = "asReal")]
797 pub fn Rf_asReal(x: SEXP) -> f64;
798 #[doc(alias = "asChar")]
799 pub fn Rf_asChar(x: SEXP) -> SEXP;
800 #[doc(alias = "coerceVector")]
801 pub fn Rf_coerceVector(v: SEXP, sexptype: SEXPTYPE) -> SEXP;
802
803 // Matrix utilities — no callers outside ffi.rs
804 #[doc(alias = "nrows")]
805 pub fn Rf_nrows(x: SEXP) -> ::std::os::raw::c_int;
806 #[doc(alias = "ncols")]
807 pub fn Rf_ncols(x: SEXP) -> ::std::os::raw::c_int;
808
809 // Inheritance checking — encapsulated by SexpExt::inherits_class()
810 #[doc(alias = "inherits")]
811 pub fn Rf_inherits(x: SEXP, klass: *const ::std::os::raw::c_char) -> Rboolean;
812
813 // Type checking predicates — encapsulated by SexpExt type-check methods
814 #[doc(alias = "isNull")]
815 pub fn Rf_isNull(s: SEXP) -> Rboolean;
816 #[doc(alias = "isSymbol")]
817 pub fn Rf_isSymbol(s: SEXP) -> Rboolean;
818 #[doc(alias = "isLogical")]
819 pub fn Rf_isLogical(s: SEXP) -> Rboolean;
820 #[doc(alias = "isReal")]
821 pub fn Rf_isReal(s: SEXP) -> Rboolean;
822 #[doc(alias = "isComplex")]
823 pub fn Rf_isComplex(s: SEXP) -> Rboolean;
824 #[doc(alias = "isExpression")]
825 pub fn Rf_isExpression(s: SEXP) -> Rboolean;
826 #[doc(alias = "isEnvironment")]
827 pub fn Rf_isEnvironment(s: SEXP) -> Rboolean;
828 #[doc(alias = "isString")]
829 pub fn Rf_isString(s: SEXP) -> Rboolean;
830
831 // Composite type checking (from inline functions)
832 #[doc(alias = "isArray")]
833 pub fn Rf_isArray(s: SEXP) -> Rboolean;
834 #[doc(alias = "isMatrix")]
835 pub fn Rf_isMatrix(s: SEXP) -> Rboolean;
836 #[doc(alias = "isList")]
837 pub fn Rf_isList(s: SEXP) -> Rboolean;
838 #[doc(alias = "isNewList")]
839 pub fn Rf_isNewList(s: SEXP) -> Rboolean;
840 #[doc(alias = "isPairList")]
841 pub fn Rf_isPairList(s: SEXP) -> Rboolean;
842 #[doc(alias = "isFunction")]
843 pub fn Rf_isFunction(s: SEXP) -> Rboolean;
844 #[doc(alias = "isPrimitive")]
845 pub fn Rf_isPrimitive(s: SEXP) -> Rboolean;
846 #[doc(alias = "isLanguage")]
847 pub fn Rf_isLanguage(s: SEXP) -> Rboolean;
848 #[doc(alias = "isDataFrame")]
849 pub fn Rf_isDataFrame(s: SEXP) -> Rboolean;
850 #[doc(alias = "isFactor")]
851 pub fn Rf_isFactor(s: SEXP) -> Rboolean;
852 #[doc(alias = "isInteger")]
853 pub fn Rf_isInteger(s: SEXP) -> Rboolean;
854 #[doc(alias = "isObject")]
855 pub fn Rf_isObject(s: SEXP) -> Rboolean;
856
857 // Pairlist utilities
858 #[doc(alias = "elt")]
859 pub fn Rf_elt(list: SEXP, i: ::std::os::raw::c_int) -> SEXP;
860 #[doc(alias = "lastElt")]
861 pub fn Rf_lastElt(list: SEXP) -> SEXP;
862 #[doc(alias = "nthcdr")]
863 pub fn Rf_nthcdr(list: SEXP, n: ::std::os::raw::c_int) -> SEXP;
864 #[doc(alias = "listAppend")]
865 pub fn Rf_listAppend(s: SEXP, t: SEXP) -> SEXP;
866
867 // More attribute setters (using R's "gets" suffix convention)
868 //
869 // See "Attribute access" section above for explanation of the "gets" suffix.
870 // These are setter functions equivalent to R's `attr(x) <- value` syntax.
871
872 /// Set the class attribute of a vector.
873 ///
874 /// Equivalent to R's `class(vec) <- klass` syntax.
875 /// The "gets" suffix indicates this is a setter function.
876 ///
877 /// # Returns
878 ///
879 /// Returns the modified vector (like all "*gets" functions).
880 #[doc(alias = "classgets")]
881 pub fn Rf_classgets(vec: SEXP, klass: SEXP) -> SEXP;
882
883 /// Set the dimnames attribute of an array/matrix.
884 ///
885 /// Equivalent to R's `dimnames(vec) <- val` syntax.
886 /// The "gets" suffix indicates this is a setter function.
887 ///
888 /// # Returns
889 ///
890 /// Returns the modified vector.
891 #[doc(alias = "dimnamesgets")]
892 pub fn Rf_dimnamesgets(vec: SEXP, val: SEXP) -> SEXP;
893 // Issue #112 cat. 10: kept pub(crate) — 2 callers each in factor.rs/matrix helpers; wrapping adds no value
894 #[doc(alias = "GetRowNames")]
895 pub(crate) fn Rf_GetRowNames(dimnames: SEXP) -> SEXP;
896 #[doc(alias = "GetColNames")]
897 pub(crate) fn Rf_GetColNames(dimnames: SEXP) -> SEXP;
898
899 // Environment operations
900 #[doc(alias = "findVar")]
901 pub fn Rf_findVar(symbol: SEXP, rho: SEXP) -> SEXP;
902 #[doc(alias = "findVarInFrame")]
903 pub fn Rf_findVarInFrame(rho: SEXP, symbol: SEXP) -> SEXP;
904 #[doc(alias = "findVarInFrame3")]
905 pub fn Rf_findVarInFrame3(rho: SEXP, symbol: SEXP, doget: Rboolean) -> SEXP;
906 #[doc(alias = "defineVar")]
907 pub fn Rf_defineVar(symbol: SEXP, value: SEXP, rho: SEXP);
908 #[doc(alias = "setVar")]
909 pub fn Rf_setVar(symbol: SEXP, value: SEXP, rho: SEXP);
910 #[doc(alias = "findFun")]
911 pub fn Rf_findFun(symbol: SEXP, rho: SEXP) -> SEXP;
912
913 /// Find a registered namespace by name. **Longjmps on error** — prefer
914 /// `REnv::package_namespace()` which wraps this safely.
915 #[doc(alias = "FindNamespace")]
916 pub fn R_FindNamespace(info: SEXP) -> SEXP;
917
918 // Issue #112 cat. 9: kept pub(crate) — R_GetCurrentEnv used from s4_helpers.rs; R_tryEvalSilent from expression.rs
919 /// Return the current execution environment (innermost closure on call
920 /// stack, or `R_GlobalEnv` if none).
921 #[doc(alias = "GetCurrentEnv")]
922 pub(crate) fn R_GetCurrentEnv() -> SEXP;
923
924 // Evaluation
925 #[doc(alias = "eval")]
926 pub fn Rf_eval(expr: SEXP, rho: SEXP) -> SEXP;
927 #[doc(alias = "applyClosure")]
928 pub fn Rf_applyClosure(
929 call: SEXP,
930 op: SEXP,
931 args: SEXP,
932 rho: SEXP,
933 suppliedvars: SEXP,
934 check: Rboolean,
935 ) -> SEXP;
936 pub fn R_tryEval(expr: SEXP, env: SEXP, error_occurred: *mut ::std::os::raw::c_int) -> SEXP;
937 pub(crate) fn R_tryEvalSilent(
938 expr: SEXP,
939 env: SEXP,
940 error_occurred: *mut ::std::os::raw::c_int,
941 ) -> SEXP;
942 pub fn R_forceAndCall(e: SEXP, n: ::std::os::raw::c_int, rho: SEXP) -> SEXP;
943
944 /// Parse R source text into an EXPRSXP (a list of parsed expressions).
945 ///
946 /// `text` is a STRSXP holding the source, `n` is the number of expressions
947 /// to parse (`-1` for all), `status` receives the [`ParseStatus`] outcome,
948 /// and `srcfile` is a srcref/`R_NilValue`. Allocates; protect the result.
949 ///
950 /// Prefer the safe [`crate::expression::r_eval_str`] wrapper, which does the
951 /// STRSXP construction, status check, and protection bookkeeping for you.
952 #[doc(alias = "ParseVector")]
953 pub fn R_ParseVector(
954 text: SEXP,
955 n: ::std::os::raw::c_int,
956 status: *mut ParseStatus,
957 srcfile: SEXP,
958 ) -> SEXP;
959}
960
961/// Outcome of [`R_ParseVector`] (from `R_ext/Parse.h`).
962///
963/// `PARSE_NULL` is never returned by `R_ParseVector`; the meaningful success
964/// value is [`ParseStatus::PARSE_OK`]. The remaining variants indicate parse
965/// failures (`PARSE_ERROR`), incomplete input (`PARSE_INCOMPLETE`), or
966/// end-of-input (`PARSE_EOF`).
967#[allow(non_camel_case_types)]
968#[repr(i32)]
969#[derive(Debug, Clone, Copy, PartialEq, Eq)]
970pub enum ParseStatus {
971 /// Never returned by `R_ParseVector`; the default-initialized sentinel.
972 PARSE_NULL,
973 /// Parse succeeded.
974 PARSE_OK,
975 /// Input ended mid-expression (e.g. an unbalanced delimiter).
976 PARSE_INCOMPLETE,
977 /// A syntax error was encountered.
978 PARSE_ERROR,
979 /// End of input reached with no further expressions.
980 PARSE_EOF,
981}
982
983// region: Connections API (R_ext/Connections.h)
984//
985// Gated behind `connections` feature because R's connection API is explicitly UNSTABLE.
986// From R_ext/Connections.h:
987// "IMPORTANT: we do not expect future connection APIs to be
988// backward-compatible so if you use this, you *must* check the
989// version and proceeds only if it matches what you expect.
990//
991// We explicitly reserve the right to change the connection
992// implementation without a compatibility layer."
993//
994// Use with caution and always check R_CONNECTIONS_VERSION.
995// Issue #112 cat. 8: kept pub(crate) — feature-gated behind `connections`; behind Connection type for users
996#[r_ffi_checked]
997#[cfg(feature = "connections")]
998unsafe extern "C-unwind" {
999 /// Create a new custom connection.
1000 ///
1001 /// # WARNING
1002 ///
1003 /// This API is UNSTABLE. Check `R_CONNECTIONS_VERSION` before use.
1004 /// The connection implementation may change without notice.
1005 ///
1006 /// # Safety
1007 ///
1008 /// - `description`, `mode`, and `class_name` must be valid C strings
1009 /// - `ptr` must be a valid pointer to store the connection handle
1010 pub(crate) fn R_new_custom_connection(
1011 description: *const ::std::os::raw::c_char,
1012 mode: *const ::std::os::raw::c_char,
1013 class_name: *const ::std::os::raw::c_char,
1014 ptr: *mut Rconnection,
1015 ) -> SEXP;
1016
1017 /// Read from a connection.
1018 ///
1019 /// # WARNING
1020 ///
1021 /// This API is UNSTABLE and may change.
1022 ///
1023 /// # Safety
1024 ///
1025 /// - `con` must be a valid Rconnection handle
1026 /// - `buf` must be a valid buffer with at least `n` bytes
1027 pub(crate) fn R_ReadConnection(
1028 con: Rconnection,
1029 buf: *mut ::std::os::raw::c_void,
1030 n: usize,
1031 ) -> usize;
1032
1033 /// Write to a connection.
1034 ///
1035 /// # WARNING
1036 ///
1037 /// This API is UNSTABLE and may change.
1038 ///
1039 /// # Safety
1040 ///
1041 /// - `con` must be a valid Rconnection handle
1042 /// - `buf` must contain at least `n` valid bytes
1043 pub(crate) fn R_WriteConnection(
1044 con: Rconnection,
1045 buf: *const ::std::os::raw::c_void,
1046 n: usize,
1047 ) -> usize;
1048
1049 /// Get a connection from a SEXP.
1050 ///
1051 /// # WARNING
1052 ///
1053 /// This API is UNSTABLE and may change.
1054 /// Added in R 3.3.0.
1055 ///
1056 /// # Safety
1057 ///
1058 /// - `sConn` must be a valid connection SEXP
1059 pub(crate) fn R_GetConnection(sConn: SEXP) -> Rconnection;
1060}
1061// endregion: Connections API
1062
1063/// Check if a SEXP is an S4 object.
1064///
1065/// # Safety
1066///
1067/// - `arg1` must be a valid SEXP
1068#[allow(non_snake_case)]
1069pub unsafe fn Rf_isS4(arg1: SEXP) -> Rboolean {
1070 unsafe extern "C-unwind" {
1071 #[link_name = "Rf_isS4"]
1072 pub fn Rf_isS4_original(arg1: SEXP) -> u32;
1073 }
1074
1075 unsafe {
1076 if Rf_isS4_original(arg1) == 0 {
1077 Rboolean::FALSE
1078 } else {
1079 Rboolean::TRUE
1080 }
1081 }
1082}
1083
1084// region: registration!
1085
1086#[repr(C)]
1087#[derive(Debug)]
1088/// Opaque dynamic library descriptor from R.
1089pub struct DllInfo(::std::os::raw::c_void);
1090
1091/// Generic dynamic library function pointer.
1092///
1093/// R defines this as `void *(*)(void)` - a function taking no arguments and
1094/// returning `void*`. This is used for method registration and external pointer
1095/// functions. The actual function signatures vary; callers cast to the appropriate
1096/// concrete function type before calling.
1097///
1098/// We use `fn() -> *mut c_void` to match R's signature. The function pointer is
1099/// stored generically and cast to the appropriate type when called by R.
1100#[allow(non_camel_case_types)]
1101pub type DL_FUNC =
1102 ::std::option::Option<unsafe extern "C-unwind" fn() -> *mut ::std::os::raw::c_void>;
1103
1104/// Type descriptor for native primitive arguments in .C/.Fortran calls.
1105///
1106/// This is used in `R_CMethodDef` and `R_FortranMethodDef` to specify
1107/// argument types for type checking.
1108#[allow(non_camel_case_types)]
1109pub type R_NativePrimitiveArgType = ::std::os::raw::c_uint;
1110
1111/// Method definition for .C interface routines.
1112///
1113/// Used to register C functions callable via `.C()` from R.
1114#[repr(C)]
1115#[derive(Debug, Copy, Clone)]
1116#[allow(non_camel_case_types)]
1117#[allow(non_snake_case)]
1118pub struct R_CMethodDef {
1119 /// Exported symbol name.
1120 pub name: *const ::std::os::raw::c_char,
1121 /// Function pointer implementing the routine.
1122 pub fun: DL_FUNC,
1123 /// Declared arity.
1124 pub numArgs: ::std::os::raw::c_int,
1125 /// Optional array of argument types for type checking. May be null.
1126 pub types: *const R_NativePrimitiveArgType,
1127}
1128
1129/// Method definition for .Fortran interface routines.
1130///
1131/// Structurally identical to `R_CMethodDef`.
1132#[allow(non_camel_case_types)]
1133pub type R_FortranMethodDef = R_CMethodDef;
1134
1135/// Method definition for .Call interface routines.
1136///
1137/// Used to register C functions callable via `.Call()` from R.
1138/// Unlike `.C()` routines, `.Call()` functions receive and return SEXP values directly.
1139#[repr(C)]
1140#[derive(Debug, Copy, Clone)]
1141#[allow(non_camel_case_types)]
1142#[allow(non_snake_case)]
1143pub struct R_CallMethodDef {
1144 /// Exported symbol name.
1145 pub name: *const ::std::os::raw::c_char,
1146 /// Function pointer implementing the routine.
1147 pub fun: DL_FUNC,
1148 /// Declared arity.
1149 pub numArgs: ::std::os::raw::c_int,
1150}
1151
1152// SAFETY: `name` points to a static CStr literal, `fun` is a function pointer.
1153// Both are valid for program lifetime and safe to read from any thread.
1154unsafe impl Sync for R_CallMethodDef {}
1155unsafe impl Send for R_CallMethodDef {}
1156
1157/// Method definition for .External interface routines.
1158///
1159/// Structurally identical to `R_CallMethodDef`.
1160#[allow(non_camel_case_types)]
1161pub type R_ExternalMethodDef = R_CallMethodDef;
1162
1163// Checked routine registration API declarations.
1164// Issue #112 cat. 7: kept pub(crate) — only called from init.rs during package init; not worth a wrapper type
1165#[allow(missing_docs)]
1166#[r_ffi_checked]
1167#[allow(clashing_extern_declarations)]
1168unsafe extern "C-unwind" {
1169 pub(crate) fn R_registerRoutines(
1170 info: *mut DllInfo,
1171 croutines: *const R_CMethodDef,
1172 callRoutines: *const R_CallMethodDef,
1173 fortranRoutines: *const R_FortranMethodDef,
1174 externalRoutines: *const R_ExternalMethodDef,
1175 ) -> ::std::os::raw::c_int;
1176
1177 pub(crate) fn R_useDynamicSymbols(info: *mut DllInfo, value: Rboolean) -> Rboolean;
1178 pub(crate) fn R_forceSymbols(info: *mut DllInfo, value: Rboolean) -> Rboolean;
1179}
1180
1181// endregion
1182
1183// region: Non-API encoding/locale state (Defn.h)
1184
1185/// Non-API encoding / locale helpers from R's `Defn.h`.
1186///
1187/// These are not part of the stable R API and may break across R versions.
1188///
1189/// Only symbols R's shared library actually **exports** may be declared here.
1190/// `Defn.h` marks most locale globals `extern0` (= `attribute_hidden`) —
1191/// referencing one of those (e.g. `known_to_be_utf8`, `latin1locale`,
1192/// `R_nativeEncoding`) compiles fine but aborts `dyn.load` of any binary that
1193/// carries the reference: data relocations resolve eagerly at load, whether or
1194/// not the code path ever runs. That made every `nonapi` build un-loadable
1195/// (caught by the feature-legs CI, audit A5). `utf8locale`, `mbcslocale`, and
1196/// `known_to_be_latin1` are plain `extern` and exported (verified against
1197/// R 4.6's libR).
1198#[cfg(feature = "nonapi")]
1199pub mod nonapi_encoding {
1200 use super::r_ffi_checked;
1201
1202 // Issue #112 cat. 10: kept pub(crate) — nonapi encoding helpers; single-caller utilities in encoding.rs
1203 #[r_ffi_checked]
1204 #[allow(clashing_extern_declarations)]
1205 unsafe extern "C-unwind" {
1206 // Locale flags (exported, non-hidden)
1207 pub(crate) static utf8locale: super::Rboolean;
1208 pub(crate) static mbcslocale: super::Rboolean;
1209 pub(crate) static known_to_be_latin1: super::Rboolean;
1210 }
1211}
1212
1213// endregion
1214
1215// region: Non-API stack checking variables (Rinterface.h)
1216
1217/// Non-API stack checking variables from `Rinterface.h`.
1218///
1219/// R uses these to detect stack overflow. When calling R from a thread other
1220/// than the main R thread, stack checking will fail because these values are
1221/// set for the main thread's stack.
1222///
1223/// # Usage
1224///
1225/// To safely call R from a worker thread, disable stack checking:
1226/// ```ignore
1227/// #[cfg(feature = "nonapi")]
1228/// unsafe {
1229/// use miniextendr_api::sys::nonapi_stack::*;
1230/// let saved = get_r_cstack_limit();
1231/// set_r_cstack_limit(usize::MAX); // disable checking
1232/// // ... call R APIs ...
1233/// set_r_cstack_limit(saved); // restore
1234/// }
1235/// ```
1236///
1237/// Or use the higher-level [`StackCheckGuard`](crate::thread::StackCheckGuard) which handles this automatically.
1238///
1239/// Setting `R_CStackLimit` to `usize::MAX` (i.e., `-1` as `uintptr_t`) disables
1240/// stack checking entirely.
1241#[cfg(feature = "nonapi")]
1242pub mod nonapi_stack {
1243 unsafe extern "C" {
1244 /// Top of the stack (set during `Rf_initialize_R` for main thread).
1245 ///
1246 /// On Unix, determined via `__libc_stack_end`, `KERN_USRSTACK`, or
1247 /// `thr_stksegment`. On Windows, via `VirtualQuery`.
1248 #[allow(non_upper_case_globals)]
1249 pub(crate) static R_CStackStart: usize;
1250
1251 /// Stack size limit. Set to `usize::MAX` to disable stack checking.
1252 ///
1253 /// From R source: `if(R_CStackStart == -1) R_CStackLimit = -1; /* never set */`
1254 #[allow(non_upper_case_globals)]
1255 pub static R_CStackLimit: usize;
1256
1257 /// Stack growth direction: 1 = grows up, -1 = grows down.
1258 ///
1259 /// Most systems (x86, ARM) grow down (-1).
1260 #[allow(non_upper_case_globals)]
1261 pub(crate) static R_CStackDir: ::std::os::raw::c_int;
1262 }
1263
1264 /// Write to `R_CStackLimit`.
1265 ///
1266 /// # Safety
1267 /// Must be called from R's main thread.
1268 #[inline]
1269 pub unsafe fn set_r_cstack_limit(value: usize) {
1270 unsafe {
1271 let ptr = (&raw const R_CStackLimit).cast_mut();
1272 ptr.write(value);
1273 }
1274 }
1275
1276 // Issue #112 cat. 10: kept pub(crate) — nonapi stack helpers; used from thread.rs; wrapping adds no value
1277 /// Read `R_CStackLimit`.
1278 #[inline]
1279 pub(crate) fn get_r_cstack_limit() -> usize {
1280 unsafe { R_CStackLimit }
1281 }
1282
1283 /// Read `R_CStackStart`.
1284 #[inline]
1285 pub(crate) fn get_r_cstack_start() -> usize {
1286 unsafe { R_CStackStart }
1287 }
1288
1289 /// Read `R_CStackDir`.
1290 #[inline]
1291 pub(crate) fn get_r_cstack_dir() -> ::std::os::raw::c_int {
1292 unsafe { R_CStackDir }
1293 }
1294}
1295
1296// endregion
1297
1298// region: Inline Helper Functions (Rust implementations of R's inline functions)
1299
1300/// Create a length-1 string vector from a C string.
1301///
1302/// Rust equivalent of R's inline `Rf_mkString(s)`, which is
1303/// shorthand for `ScalarString(mkChar(s))`.
1304///
1305/// # Safety
1306///
1307/// - `s` must be a valid null-terminated C string
1308/// - Must be called from R's main thread
1309/// - Result must be protected from GC
1310#[doc(alias = "mkString")]
1311#[allow(non_snake_case)]
1312#[inline]
1313pub unsafe fn Rf_mkString(s: *const ::std::os::raw::c_char) -> SEXP {
1314 unsafe {
1315 let charsxp = Rf_mkChar(s);
1316 let protected = Rf_protect(charsxp);
1317 let result = Rf_ScalarString(protected);
1318 Rf_unprotect(1);
1319 result
1320 }
1321}
1322
1323/// Build a pairlist with 1 element.
1324///
1325/// Rust equivalent of R's inline `Rf_list1(s)`.
1326///
1327/// # Safety
1328///
1329/// - `s` must be a valid SEXP
1330/// - Must be called from R's main thread
1331/// - Result must be protected from GC
1332#[doc(alias = "list1")]
1333#[allow(non_snake_case)]
1334#[inline]
1335pub unsafe fn Rf_list1(s: SEXP) -> SEXP {
1336 unsafe { Rf_cons(s, R_NilValue) }
1337}
1338
1339/// Build a pairlist with 2 elements.
1340///
1341/// Rust equivalent of R's inline `Rf_list2(s, t)`.
1342///
1343/// # Safety
1344///
1345/// - Both SEXPs must be valid
1346/// - Must be called from R's main thread
1347/// - Result must be protected from GC
1348#[doc(alias = "list2")]
1349#[allow(non_snake_case)]
1350#[inline]
1351pub unsafe fn Rf_list2(s: SEXP, t: SEXP) -> SEXP {
1352 unsafe { Rf_cons(s, Rf_cons(t, R_NilValue)) }
1353}
1354
1355/// Build a pairlist with 3 elements.
1356///
1357/// Rust equivalent of R's inline `Rf_list3(s, t, u)`.
1358///
1359/// # Safety
1360///
1361/// - All SEXPs must be valid
1362/// - Must be called from R's main thread
1363/// - Result must be protected from GC
1364#[doc(alias = "list3")]
1365#[allow(non_snake_case)]
1366#[inline]
1367pub unsafe fn Rf_list3(s: SEXP, t: SEXP, u: SEXP) -> SEXP {
1368 unsafe { Rf_cons(s, Rf_cons(t, Rf_cons(u, R_NilValue))) }
1369}
1370
1371/// Build a pairlist with 4 elements.
1372///
1373/// Rust equivalent of R's inline `Rf_list4(s, t, u, v)`.
1374///
1375/// # Safety
1376///
1377/// - All SEXPs must be valid
1378/// - Must be called from R's main thread
1379/// - Result must be protected from GC
1380#[doc(alias = "list4")]
1381#[allow(non_snake_case)]
1382#[inline]
1383pub unsafe fn Rf_list4(s: SEXP, t: SEXP, u: SEXP, v: SEXP) -> SEXP {
1384 unsafe { Rf_cons(s, Rf_cons(t, Rf_cons(u, Rf_cons(v, R_NilValue)))) }
1385}
1386
1387/// Build a language object (call) with 1 element (the function).
1388///
1389/// Rust equivalent of R's inline `Rf_lang1(s)`.
1390/// Creates a call like `f()` where `s` is the function.
1391///
1392/// # Safety
1393///
1394/// - `s` must be a valid SEXP (typically a symbol or closure)
1395/// - Must be called from R's main thread
1396/// - Result must be protected from GC
1397#[doc(alias = "lang1")]
1398#[allow(non_snake_case)]
1399#[inline]
1400pub unsafe fn Rf_lang1(s: SEXP) -> SEXP {
1401 unsafe { Rf_lcons(s, R_NilValue) }
1402}
1403
1404/// Build a language object (call) with function and 1 argument.
1405///
1406/// Rust equivalent of R's inline `Rf_lang2(s, t)`.
1407/// Creates a call like `f(arg)` where `s` is the function and `t` is the argument.
1408///
1409/// # Safety
1410///
1411/// - Both SEXPs must be valid
1412/// - Must be called from R's main thread
1413/// - Result must be protected from GC
1414#[doc(alias = "lang2")]
1415#[allow(non_snake_case)]
1416#[inline]
1417pub unsafe fn Rf_lang2(s: SEXP, t: SEXP) -> SEXP {
1418 unsafe { Rf_lcons(s, Rf_list1(t)) }
1419}
1420
1421/// Build a language object (call) with function and 2 arguments.
1422///
1423/// Rust equivalent of R's inline `Rf_lang3(s, t, u)`.
1424/// Creates a call like `f(arg1, arg2)`.
1425///
1426/// # Safety
1427///
1428/// - All SEXPs must be valid
1429/// - Must be called from R's main thread
1430/// - Result must be protected from GC
1431#[doc(alias = "lang3")]
1432#[allow(non_snake_case)]
1433#[inline]
1434pub unsafe fn Rf_lang3(s: SEXP, t: SEXP, u: SEXP) -> SEXP {
1435 unsafe { Rf_lcons(s, Rf_list2(t, u)) }
1436}
1437
1438/// Build a language object (call) with function and 3 arguments.
1439///
1440/// Rust equivalent of R's inline `Rf_lang4(s, t, u, v)`.
1441/// Creates a call like `f(arg1, arg2, arg3)`.
1442///
1443/// # Safety
1444///
1445/// - All SEXPs must be valid
1446/// - Must be called from R's main thread
1447/// - Result must be protected from GC
1448#[doc(alias = "lang4")]
1449#[allow(non_snake_case)]
1450#[inline]
1451pub unsafe fn Rf_lang4(s: SEXP, t: SEXP, u: SEXP, v: SEXP) -> SEXP {
1452 unsafe { Rf_lcons(s, Rf_list3(t, u, v)) }
1453}
1454
1455/// Build a language object (call) with function and 4 arguments.
1456///
1457/// Rust equivalent of R's inline `Rf_lang5(s, t, u, v, w)`.
1458/// Creates a call like `f(arg1, arg2, arg3, arg4)`.
1459///
1460/// # Safety
1461///
1462/// - All SEXPs must be valid
1463/// - Must be called from R's main thread
1464/// - Result must be protected from GC
1465#[doc(alias = "lang5")]
1466#[allow(non_snake_case)]
1467#[inline]
1468pub unsafe fn Rf_lang5(s: SEXP, t: SEXP, u: SEXP, v: SEXP, w: SEXP) -> SEXP {
1469 unsafe { Rf_lcons(s, Rf_list4(t, u, v, w)) }
1470}
1471
1472/// Build a language object (call) with function and 5 arguments.
1473///
1474/// Rust equivalent of R's inline `Rf_lang6(s, t, u, v, w, x)`.
1475/// Creates a call like `f(arg1, arg2, arg3, arg4, arg5)`.
1476///
1477/// # Safety
1478///
1479/// - All SEXPs must be valid
1480/// - Must be called from R's main thread
1481/// - Result must be protected from GC
1482#[doc(alias = "lang6")]
1483#[allow(non_snake_case)]
1484#[inline]
1485pub unsafe fn Rf_lang6(s: SEXP, t: SEXP, u: SEXP, v: SEXP, w: SEXP, x: SEXP) -> SEXP {
1486 unsafe {
1487 let protected = Rf_protect(s);
1488 let list = Rf_cons(t, Rf_list4(u, v, w, x));
1489 let result = Rf_lcons(protected, list);
1490 Rf_unprotect(1);
1491 result
1492 }
1493}
1494
1495// endregion
1496
1497// region: RNG functions (R_ext/Random.h)
1498
1499/// RNG type enum from R_ext/Random.h
1500#[repr(u32)]
1501#[non_exhaustive]
1502#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
1503#[allow(non_camel_case_types)]
1504pub enum RNGtype {
1505 /// Wichmann-Hill generator.
1506 WICHMANN_HILL = 0,
1507 /// Marsaglia-Multicarry generator.
1508 MARSAGLIA_MULTICARRY = 1,
1509 /// Super-Duper generator.
1510 SUPER_DUPER = 2,
1511 /// Mersenne Twister generator.
1512 MERSENNE_TWISTER = 3,
1513 /// Knuth TAOCP generator.
1514 KNUTH_TAOCP = 4,
1515 /// User-supplied uniform generator.
1516 USER_UNIF = 5,
1517 /// Knuth TAOCP 2002 variant.
1518 KNUTH_TAOCP2 = 6,
1519 /// L'Ecuyer-CMRG generator.
1520 LECUYER_CMRG = 7,
1521}
1522
1523/// Normal distribution generator type enum from R_ext/Random.h
1524#[repr(u32)]
1525#[non_exhaustive]
1526#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
1527#[allow(non_camel_case_types)]
1528pub enum N01type {
1529 /// Legacy buggy Kinderman-Ramage method.
1530 BUGGY_KINDERMAN_RAMAGE = 0,
1531 /// Ahrens-Dieter method.
1532 AHRENS_DIETER = 1,
1533 /// Box-Muller transform.
1534 BOX_MULLER = 2,
1535 /// User-supplied normal generator.
1536 USER_NORM = 3,
1537 /// Inversion method.
1538 INVERSION = 4,
1539 /// Fixed Kinderman-Ramage method.
1540 KINDERMAN_RAMAGE = 5,
1541}
1542
1543/// Discrete uniform sample method enum from R_ext/Random.h
1544#[repr(u32)]
1545#[non_exhaustive]
1546#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
1547#[allow(non_camel_case_types)]
1548pub enum Sampletype {
1549 /// Rounding method for integer sampling.
1550 ROUNDING = 0,
1551 /// Rejection sampling method.
1552 REJECTION = 1,
1553}
1554
1555#[r_ffi_checked]
1556unsafe extern "C-unwind" {
1557 /// Save the current RNG state from R's global state.
1558 ///
1559 /// Must be called before using `unif_rand()`, `norm_rand()`, etc.
1560 /// The state is restored with `PutRNGstate()`.
1561 ///
1562 /// # Example
1563 ///
1564 /// ```ignore
1565 /// unsafe {
1566 /// GetRNGstate();
1567 /// let x = unif_rand();
1568 /// let y = norm_rand();
1569 /// PutRNGstate();
1570 /// }
1571 /// ```
1572 pub fn GetRNGstate();
1573
1574 /// Restore the RNG state to R's global state.
1575 ///
1576 /// Must be called after using `unif_rand()`, `norm_rand()`, etc.
1577 /// to ensure R's `.Random.seed` is updated.
1578 pub fn PutRNGstate();
1579
1580 /// Generate a uniform random number in (0, 1).
1581 ///
1582 /// # Important
1583 ///
1584 /// Must call `GetRNGstate()` before and `PutRNGstate()` after.
1585 pub fn unif_rand() -> f64;
1586
1587 /// Generate a standard normal random number (mean 0, sd 1).
1588 ///
1589 /// # Important
1590 ///
1591 /// Must call `GetRNGstate()` before and `PutRNGstate()` after.
1592 pub fn norm_rand() -> f64;
1593
1594 /// Generate an exponential random number with rate 1.
1595 ///
1596 /// # Important
1597 ///
1598 /// Must call `GetRNGstate()` before and `PutRNGstate()` after.
1599 pub fn exp_rand() -> f64;
1600
1601 /// Generate a uniform random index in [0, dn).
1602 ///
1603 /// Used for sampling without bias for large n.
1604 ///
1605 /// # Important
1606 ///
1607 /// Must call `GetRNGstate()` before and `PutRNGstate()` after.
1608 pub fn R_unif_index(dn: f64) -> f64;
1609
1610 /// Get the current discrete uniform sample method.
1611 pub fn R_sample_kind() -> Sampletype;
1612}
1613
1614// endregion
1615
1616// region: Memory allocation (R_ext/Memory.h)
1617
1618#[r_ffi_checked]
1619unsafe extern "C-unwind" {
1620 /// Get the current R memory stack watermark.
1621 ///
1622 /// Use with `vmaxset()` to restore memory stack state.
1623 /// Memory allocated with `R_alloc()` between `vmaxget()` and `vmaxset()`
1624 /// will be freed when `vmaxset()` is called.
1625 ///
1626 /// # Example
1627 ///
1628 /// ```ignore
1629 /// unsafe {
1630 /// let watermark = vmaxget();
1631 /// let buf = R_alloc(100, 1);
1632 /// // ... use buf ...
1633 /// vmaxset(watermark); // frees buf
1634 /// }
1635 /// ```
1636 pub fn vmaxget() -> *mut ::std::os::raw::c_void;
1637
1638 /// Set the R memory stack watermark, freeing memory allocated since the mark.
1639 ///
1640 /// # Safety
1641 ///
1642 /// `ovmax` must be a value returned by `vmaxget()` called earlier in the
1643 /// same R evaluation context.
1644 pub fn vmaxset(ovmax: *const ::std::os::raw::c_void);
1645
1646 /// Run the R garbage collector.
1647 ///
1648 /// Forces a full garbage collection cycle.
1649 pub fn R_gc();
1650
1651 /// Check if the garbage collector is currently running.
1652 ///
1653 /// Returns non-zero if GC is in progress.
1654 pub fn R_gc_running() -> ::std::os::raw::c_int;
1655
1656 /// Allocate memory on R's memory stack.
1657 ///
1658 /// This memory is automatically freed when the calling R function returns,
1659 /// or can be freed earlier with `vmaxset()`.
1660 ///
1661 /// # Parameters
1662 ///
1663 /// - `nelem`: Number of elements to allocate
1664 /// - `eltsize`: Size of each element in bytes
1665 ///
1666 /// # Returns
1667 ///
1668 /// Pointer to allocated memory (as `char*` for compatibility with S).
1669 pub fn R_alloc(nelem: usize, eltsize: ::std::os::raw::c_int) -> *mut ::std::os::raw::c_char;
1670
1671 /// Allocate an array of long doubles on R's memory stack.
1672 ///
1673 /// # Parameters
1674 ///
1675 /// - `nelem`: Number of long double elements to allocate
1676 pub fn R_allocLD(nelem: usize) -> *mut f64; // Note: f64 is close enough for most uses
1677
1678 /// S compatibility: allocate zeroed memory on R's memory stack.
1679 ///
1680 /// # Parameters
1681 ///
1682 /// - `nelem`: Number of elements
1683 /// - `eltsize`: Size of each element
1684 pub fn S_alloc(
1685 nelem: ::std::os::raw::c_long,
1686 eltsize: ::std::os::raw::c_int,
1687 ) -> *mut ::std::os::raw::c_char;
1688
1689 /// S compatibility: reallocate memory on R's memory stack.
1690 ///
1691 /// # Safety
1692 ///
1693 /// `ptr` must have been allocated by `S_alloc`.
1694 pub fn S_realloc(
1695 ptr: *mut ::std::os::raw::c_char,
1696 newsize: ::std::os::raw::c_long,
1697 oldsize: ::std::os::raw::c_long,
1698 eltsize: ::std::os::raw::c_int,
1699 ) -> *mut ::std::os::raw::c_char;
1700
1701 /// GC-aware malloc.
1702 ///
1703 /// Triggers GC if allocation fails, then retries.
1704 /// Memory must be freed with `free()`.
1705 pub fn R_malloc_gc(size: usize) -> *mut ::std::os::raw::c_void;
1706
1707 /// GC-aware calloc.
1708 ///
1709 /// Triggers GC if allocation fails, then retries.
1710 /// Memory must be freed with `free()`.
1711 pub fn R_calloc_gc(nelem: usize, eltsize: usize) -> *mut ::std::os::raw::c_void;
1712
1713 /// GC-aware realloc.
1714 ///
1715 /// Triggers GC if allocation fails, then retries.
1716 /// Memory must be freed with `free()`.
1717 pub fn R_realloc_gc(
1718 ptr: *mut ::std::os::raw::c_void,
1719 size: usize,
1720 ) -> *mut ::std::os::raw::c_void;
1721}
1722
1723// endregion
1724
1725// region: Sorting and utility functions (R_ext/Utils.h)
1726
1727#[r_ffi_checked]
1728unsafe extern "C-unwind" {
1729 /// Sort an integer vector in place (ascending order).
1730 ///
1731 /// # Parameters
1732 ///
1733 /// - `x`: Pointer to integer array
1734 /// - `n`: Number of elements
1735 pub fn R_isort(x: *mut ::std::os::raw::c_int, n: ::std::os::raw::c_int);
1736
1737 /// Sort a double vector in place (ascending order).
1738 ///
1739 /// # Parameters
1740 ///
1741 /// - `x`: Pointer to double array
1742 /// - `n`: Number of elements
1743 pub fn R_rsort(x: *mut f64, n: ::std::os::raw::c_int);
1744
1745 /// Sort a complex vector in place.
1746 ///
1747 /// # Parameters
1748 ///
1749 /// - `x`: Pointer to Rcomplex array
1750 /// - `n`: Number of elements
1751 pub fn R_csort(x: *mut Rcomplex, n: ::std::os::raw::c_int);
1752
1753 /// Sort doubles in descending order, carrying along an index array.
1754 ///
1755 /// # Parameters
1756 ///
1757 /// - `a`: Pointer to double array (sorted in place, descending)
1758 /// - `ib`: Pointer to integer array (permuted alongside `a`)
1759 /// - `n`: Number of elements
1760 #[doc(alias = "Rf_revsort")]
1761 pub fn revsort(a: *mut f64, ib: *mut ::std::os::raw::c_int, n: ::std::os::raw::c_int);
1762
1763 /// Sort doubles with index array.
1764 ///
1765 /// # Parameters
1766 ///
1767 /// - `x`: Pointer to double array (sorted in place)
1768 /// - `indx`: Pointer to integer array (permuted alongside `x`)
1769 /// - `n`: Number of elements
1770 pub fn rsort_with_index(
1771 x: *mut f64,
1772 indx: *mut ::std::os::raw::c_int,
1773 n: ::std::os::raw::c_int,
1774 );
1775
1776 /// Partial sort integers (moves k-th smallest to position k).
1777 ///
1778 /// # Parameters
1779 ///
1780 /// - `x`: Pointer to integer array
1781 /// - `n`: Number of elements
1782 /// - `k`: Target position (0-indexed)
1783 #[doc(alias = "Rf_iPsort")]
1784 pub fn iPsort(
1785 x: *mut ::std::os::raw::c_int,
1786 n: ::std::os::raw::c_int,
1787 k: ::std::os::raw::c_int,
1788 );
1789
1790 /// Partial sort doubles (moves k-th smallest to position k).
1791 ///
1792 /// # Parameters
1793 ///
1794 /// - `x`: Pointer to double array
1795 /// - `n`: Number of elements
1796 /// - `k`: Target position (0-indexed)
1797 #[doc(alias = "Rf_rPsort")]
1798 pub fn rPsort(x: *mut f64, n: ::std::os::raw::c_int, k: ::std::os::raw::c_int);
1799
1800 /// Partial sort complex numbers.
1801 ///
1802 /// # Parameters
1803 ///
1804 /// - `x`: Pointer to Rcomplex array
1805 /// - `n`: Number of elements
1806 /// - `k`: Target position (0-indexed)
1807 #[doc(alias = "Rf_cPsort")]
1808 pub fn cPsort(x: *mut Rcomplex, n: ::std::os::raw::c_int, k: ::std::os::raw::c_int);
1809
1810 /// Quicksort doubles in place.
1811 ///
1812 /// # Parameters
1813 ///
1814 /// - `v`: Pointer to double array
1815 /// - `i`: Start index (1-indexed for R compatibility)
1816 /// - `j`: End index (1-indexed)
1817 pub fn R_qsort(v: *mut f64, i: usize, j: usize);
1818
1819 /// Quicksort doubles with index array.
1820 ///
1821 /// # Parameters
1822 ///
1823 /// - `v`: Pointer to double array
1824 /// - `indx`: Pointer to index array (permuted alongside v)
1825 /// - `i`: Start index (1-indexed)
1826 /// - `j`: End index (1-indexed)
1827 pub fn R_qsort_I(
1828 v: *mut f64,
1829 indx: *mut ::std::os::raw::c_int,
1830 i: ::std::os::raw::c_int,
1831 j: ::std::os::raw::c_int,
1832 );
1833
1834 /// Quicksort integers in place.
1835 ///
1836 /// # Parameters
1837 ///
1838 /// - `iv`: Pointer to integer array
1839 /// - `i`: Start index (1-indexed)
1840 /// - `j`: End index (1-indexed)
1841 pub fn R_qsort_int(iv: *mut ::std::os::raw::c_int, i: usize, j: usize);
1842
1843 /// Quicksort integers with index array.
1844 ///
1845 /// # Parameters
1846 ///
1847 /// - `iv`: Pointer to integer array
1848 /// - `indx`: Pointer to index array
1849 /// - `i`: Start index (1-indexed)
1850 /// - `j`: End index (1-indexed)
1851 pub fn R_qsort_int_I(
1852 iv: *mut ::std::os::raw::c_int,
1853 indx: *mut ::std::os::raw::c_int,
1854 i: ::std::os::raw::c_int,
1855 j: ::std::os::raw::c_int,
1856 );
1857
1858 /// Expand a filename, resolving `~` and environment variables.
1859 ///
1860 /// # Returns
1861 ///
1862 /// Pointer to expanded path (in R's internal buffer, do not free).
1863 pub fn R_ExpandFileName(s: *const ::std::os::raw::c_char) -> *const ::std::os::raw::c_char;
1864
1865 /// Convert string to double, always using '.' as decimal point.
1866 ///
1867 /// Also accepts "NA" as input, returning NA_REAL.
1868 pub fn R_atof(str: *const ::std::os::raw::c_char) -> f64;
1869
1870 /// Convert string to double with end pointer, using '.' as decimal point.
1871 ///
1872 /// Like `strtod()` but locale-independent.
1873 pub fn R_strtod(c: *const ::std::os::raw::c_char, end: *mut *mut ::std::os::raw::c_char)
1874 -> f64;
1875
1876 /// Generate a temporary filename.
1877 ///
1878 /// # Parameters
1879 ///
1880 /// - `prefix`: Filename prefix
1881 /// - `tempdir`: Directory for temp file
1882 ///
1883 /// # Returns
1884 ///
1885 /// Newly allocated string (must be freed with `R_free_tmpnam`).
1886 pub fn R_tmpnam(
1887 prefix: *const ::std::os::raw::c_char,
1888 tempdir: *const ::std::os::raw::c_char,
1889 ) -> *mut ::std::os::raw::c_char;
1890
1891 /// Generate a temporary filename with extension.
1892 ///
1893 /// # Parameters
1894 ///
1895 /// - `prefix`: Filename prefix
1896 /// - `tempdir`: Directory for temp file
1897 /// - `fileext`: File extension (e.g., ".txt")
1898 ///
1899 /// # Returns
1900 ///
1901 /// Newly allocated string (must be freed with `R_free_tmpnam`).
1902 pub fn R_tmpnam2(
1903 prefix: *const ::std::os::raw::c_char,
1904 tempdir: *const ::std::os::raw::c_char,
1905 fileext: *const ::std::os::raw::c_char,
1906 ) -> *mut ::std::os::raw::c_char;
1907
1908 /// Free a temporary filename allocated by `R_tmpnam` or `R_tmpnam2`.
1909 pub fn R_free_tmpnam(name: *mut ::std::os::raw::c_char);
1910
1911 /// Check for R stack overflow.
1912 ///
1913 /// Throws an R error if stack is nearly exhausted.
1914 pub fn R_CheckStack();
1915
1916 /// Check for R stack overflow with extra space requirement.
1917 ///
1918 /// # Parameters
1919 ///
1920 /// - `extra`: Additional bytes needed
1921 pub fn R_CheckStack2(extra: usize);
1922
1923 /// Find the interval containing a value (binary search).
1924 ///
1925 /// Used for interpolation and binning.
1926 ///
1927 /// # Parameters
1928 ///
1929 /// - `xt`: Sorted breakpoints array
1930 /// - `n`: Number of breakpoints
1931 /// - `x`: Value to find
1932 /// - `rightmost_closed`: If TRUE, rightmost interval is closed
1933 /// - `all_inside`: If TRUE, out-of-bounds values map to endpoints
1934 /// - `ilo`: Initial guess for interval (1-indexed)
1935 /// - `mflag`: Output flag (see R documentation)
1936 ///
1937 /// # Returns
1938 ///
1939 /// Interval index (1-indexed).
1940 pub fn findInterval(
1941 xt: *const f64,
1942 n: ::std::os::raw::c_int,
1943 x: f64,
1944 rightmost_closed: Rboolean,
1945 all_inside: Rboolean,
1946 ilo: ::std::os::raw::c_int,
1947 mflag: *mut ::std::os::raw::c_int,
1948 ) -> ::std::os::raw::c_int;
1949
1950 /// Extended interval finding with left-open option.
1951 #[allow(clippy::too_many_arguments)]
1952 pub fn findInterval2(
1953 xt: *const f64,
1954 n: ::std::os::raw::c_int,
1955 x: f64,
1956 rightmost_closed: Rboolean,
1957 all_inside: Rboolean,
1958 left_open: Rboolean,
1959 ilo: ::std::os::raw::c_int,
1960 mflag: *mut ::std::os::raw::c_int,
1961 ) -> ::std::os::raw::c_int;
1962
1963 /// Find column maxima in a matrix.
1964 ///
1965 /// # Parameters
1966 ///
1967 /// - `matrix`: Column-major matrix data
1968 /// - `nr`: Number of rows
1969 /// - `nc`: Number of columns
1970 /// - `maxes`: Output array for column maxima indices (1-indexed)
1971 /// - `ties_meth`: How to handle ties (1=first, 2=random, 3=last)
1972 pub fn R_max_col(
1973 matrix: *const f64,
1974 nr: *const ::std::os::raw::c_int,
1975 nc: *const ::std::os::raw::c_int,
1976 maxes: *mut ::std::os::raw::c_int,
1977 ties_meth: *const ::std::os::raw::c_int,
1978 );
1979
1980 /// Check if a string represents FALSE in R.
1981 ///
1982 /// Recognizes "FALSE", "false", "False", "F", "f", etc.
1983 #[doc(alias = "Rf_StringFalse")]
1984 pub fn StringFalse(s: *const ::std::os::raw::c_char) -> Rboolean;
1985
1986 /// Check if a string represents TRUE in R.
1987 ///
1988 /// Recognizes "TRUE", "true", "True", "T", "t", etc.
1989 #[doc(alias = "Rf_StringTrue")]
1990 pub fn StringTrue(s: *const ::std::os::raw::c_char) -> Rboolean;
1991
1992 /// Check if a string is blank (empty or only whitespace).
1993 #[doc(alias = "Rf_isBlankString")]
1994 pub fn isBlankString(s: *const ::std::os::raw::c_char) -> Rboolean;
1995}
1996
1997// endregion
1998
1999// region: Additional Rinternals.h functions
2000
2001#[r_ffi_checked]
2002unsafe extern "C-unwind" {
2003 // String/character functions
2004
2005 /// Create a CHARSXP with specified encoding.
2006 ///
2007 /// # Parameters
2008 ///
2009 /// - `s`: C string
2010 /// - `encoding`: Character encoding (CE_UTF8, CE_LATIN1, etc.)
2011 // Issue #112 cat. 10: kept pub(crate) — 2 callers in encoding.rs; wrapping adds no value
2012 #[doc(alias = "mkCharCE")]
2013 pub(crate) fn Rf_mkCharCE(s: *const ::std::os::raw::c_char, encoding: cetype_t) -> SEXP;
2014
2015 /// Get the number of characters in a string/character.
2016 ///
2017 /// # Parameters
2018 ///
2019 /// - `x`: A string SEXP
2020 /// - `ntype`: Type of count (0=bytes, 1=chars, 2=width)
2021 /// - `allowNA`: Whether to allow NA values
2022 /// - `keepNA`: Whether to keep NA in result
2023 /// - `msg_name`: Name for error messages
2024 ///
2025 /// # Returns
2026 ///
2027 /// Character count or -1 on error.
2028 pub fn R_nchar(
2029 x: SEXP,
2030 ntype: ::std::os::raw::c_int,
2031 allowNA: Rboolean,
2032 keepNA: Rboolean,
2033 msg_name: *const ::std::os::raw::c_char,
2034 ) -> ::std::os::raw::c_int;
2035
2036 /// Convert SEXPTYPE to C string name.
2037 ///
2038 /// Returns a string like "INTSXP", "REALSXP", etc.
2039 #[doc(alias = "type2char")]
2040 pub fn Rf_type2char(sexptype: SEXPTYPE) -> *const ::std::os::raw::c_char;
2041
2042 /// Print an R value to the console.
2043 ///
2044 /// Uses R's standard print method for the object.
2045 #[doc(alias = "PrintValue")]
2046 pub fn Rf_PrintValue(x: SEXP);
2047
2048 // Environment functions
2049
2050 /// Create a new environment.
2051 ///
2052 /// # Parameters
2053 ///
2054 /// - `enclos`: Enclosing environment
2055 /// - `hash`: Whether to use a hash table
2056 /// - `size`: Initial hash table size (if hash is TRUE)
2057 // Issue #112 cat. 10: kept pub(crate) — 2 callers in environment.rs; wrapping adds no value
2058 pub(crate) fn R_NewEnv(enclos: SEXP, hash: Rboolean, size: ::std::os::raw::c_int) -> SEXP;
2059
2060 /// Check if a variable exists in an environment frame.
2061 ///
2062 /// Does not search enclosing environments.
2063 pub fn R_existsVarInFrame(rho: SEXP, symbol: SEXP) -> Rboolean;
2064
2065 /// Remove a variable from an environment frame.
2066 ///
2067 /// # Returns
2068 ///
2069 /// The removed value, or R_NilValue if not found.
2070 pub fn R_removeVarFromFrame(symbol: SEXP, env: SEXP) -> SEXP;
2071
2072 /// Get the top-level environment.
2073 ///
2074 /// Walks up enclosing environments until reaching a top-level env
2075 /// (global, namespace, or base).
2076 #[doc(alias = "topenv")]
2077 pub fn Rf_topenv(target: SEXP, envir: SEXP) -> SEXP;
2078
2079 // Matching functions
2080
2081 /// Match elements of first vector in second vector.
2082 ///
2083 /// Like R's `match()` function.
2084 ///
2085 /// # Parameters
2086 ///
2087 /// - `x`: Vector of values to match
2088 /// - `table`: Vector to match against
2089 /// - `nomatch`: Value to return for non-matches
2090 ///
2091 /// # Returns
2092 ///
2093 /// Integer vector of match positions (1-indexed, nomatch for non-matches).
2094 #[doc(alias = "match")]
2095 pub fn Rf_match(x: SEXP, table: SEXP, nomatch: ::std::os::raw::c_int) -> SEXP;
2096
2097 // Duplication and copying
2098
2099 /// Copy most attributes from source to target.
2100 ///
2101 /// Copies all attributes except names, dim, and dimnames.
2102 #[doc(alias = "copyMostAttrib")]
2103 pub fn Rf_copyMostAttrib(source: SEXP, target: SEXP);
2104
2105 /// Find first duplicated element.
2106 ///
2107 /// # Parameters
2108 ///
2109 /// - `x`: Vector to search
2110 /// - `fromLast`: If TRUE, search from end
2111 ///
2112 /// # Returns
2113 ///
2114 /// 0 if no duplicates, otherwise 1-indexed position of first duplicate.
2115 #[doc(alias = "any_duplicated")]
2116 pub fn Rf_any_duplicated(x: SEXP, fromLast: Rboolean) -> R_xlen_t;
2117
2118 // S4 functions
2119
2120 /// Convert to an S4 object.
2121 ///
2122 /// # Parameters
2123 ///
2124 /// - `object`: Object to convert
2125 /// - `flag`: Conversion flag
2126 #[doc(alias = "asS4")]
2127 pub fn Rf_asS4(object: SEXP, flag: Rboolean, complete: ::std::os::raw::c_int) -> SEXP;
2128
2129 /// Get the S3 class of an S4 object.
2130 #[doc(alias = "S3Class")]
2131 pub fn Rf_S3Class(object: SEXP) -> SEXP;
2132
2133 // Option access
2134
2135 /// Get an R option value.
2136 ///
2137 /// Equivalent to `getOption("name")` in R.
2138 ///
2139 /// # Parameters
2140 ///
2141 /// - `tag`: Symbol for option name
2142 #[doc(alias = "GetOption1")]
2143 pub fn Rf_GetOption1(tag: SEXP) -> SEXP;
2144
2145 /// Get the `digits` option.
2146 ///
2147 /// Returns the value of `getOption("digits")`.
2148 #[doc(alias = "GetOptionDigits")]
2149 pub fn Rf_GetOptionDigits() -> ::std::os::raw::c_int;
2150
2151 /// Get the `width` option.
2152 ///
2153 /// Returns the value of `getOption("width")`.
2154 #[doc(alias = "GetOptionWidth")]
2155 pub(crate) fn Rf_GetOptionWidth() -> ::std::os::raw::c_int;
2156
2157 // Factor functions
2158
2159 /// Check if a factor is ordered.
2160 #[doc(alias = "isOrdered")]
2161 pub fn Rf_isOrdered(s: SEXP) -> Rboolean;
2162
2163 /// Check if a factor is unordered.
2164 #[doc(alias = "isUnordered")]
2165 pub fn Rf_isUnordered(s: SEXP) -> Rboolean;
2166
2167 /// Check if a vector is unsorted.
2168 ///
2169 /// # Parameters
2170 ///
2171 /// - `x`: Vector to check
2172 /// - `strictly`: If TRUE, check for strictly increasing
2173 #[doc(alias = "isUnsorted")]
2174 pub fn Rf_isUnsorted(x: SEXP, strictly: Rboolean) -> ::std::os::raw::c_int;
2175
2176 // Expression and evaluation
2177
2178 /// Substitute in an expression.
2179 ///
2180 /// Like R's `substitute()` function.
2181 #[doc(alias = "substitute")]
2182 pub fn Rf_substitute(lang: SEXP, rho: SEXP) -> SEXP;
2183
2184 /// Set vector length.
2185 ///
2186 /// For short vectors (length < 2^31).
2187 #[doc(alias = "lengthgets")]
2188 pub fn Rf_lengthgets(x: SEXP, newlen: R_xlen_t) -> SEXP;
2189
2190 /// Set vector length (long vector version).
2191 #[doc(alias = "xlengthgets")]
2192 pub fn Rf_xlengthgets(x: SEXP, newlen: R_xlen_t) -> SEXP;
2193
2194 // Protection (indexed — see cost table in the "GC protection" region above)
2195
2196 /// Protect a SEXP and record its stack index for later `R_Reprotect`.
2197 ///
2198 /// **Cost: O(1)** — same array write as `Rf_protect`, plus stores the index.
2199 /// No allocation. Use when you need to replace a protected value in-place
2200 /// (e.g., inside a loop that allocates) without unprotect/re-protect churn.
2201 #[doc(alias = "PROTECT_WITH_INDEX")]
2202 pub fn R_ProtectWithIndex(s: SEXP, index: *mut ::std::os::raw::c_int);
2203
2204 /// Replace the SEXP at a previously recorded protect stack index.
2205 ///
2206 /// **Cost: O(1)** — direct array write (`R_PPStack[index] = s`). No allocation.
2207 ///
2208 /// # Safety
2209 ///
2210 /// `index` must be from a previous `R_ProtectWithIndex` call and the
2211 /// stack must not have been unprotected past that index.
2212 #[doc(alias = "REPROTECT")]
2213 pub fn R_Reprotect(s: SEXP, index: ::std::os::raw::c_int);
2214
2215 // Weak references
2216
2217 /// Create a weak reference.
2218 ///
2219 /// # Parameters
2220 ///
2221 /// - `key`: The key object (weak reference target)
2222 /// - `val`: The value to associate
2223 /// - `fin`: Finalizer function (or R_NilValue)
2224 /// - `onexit`: Whether to run finalizer on R exit
2225 pub fn R_MakeWeakRef(key: SEXP, val: SEXP, fin: SEXP, onexit: Rboolean) -> SEXP;
2226
2227 /// Create a weak reference with C finalizer.
2228 pub fn R_MakeWeakRefC(key: SEXP, val: SEXP, fin: R_CFinalizer_t, onexit: Rboolean) -> SEXP;
2229
2230 /// Get the key from a weak reference.
2231 pub fn R_WeakRefKey(w: SEXP) -> SEXP;
2232
2233 /// Get the value from a weak reference.
2234 pub fn R_WeakRefValue(w: SEXP) -> SEXP;
2235
2236 /// Run pending finalizers.
2237 pub fn R_RunPendingFinalizers();
2238
2239 // Conversion list/vector
2240
2241 /// Convert a pairlist to a generic vector (list).
2242 #[doc(alias = "PairToVectorList")]
2243 pub fn Rf_PairToVectorList(x: SEXP) -> SEXP;
2244
2245 /// Convert a generic vector (list) to a pairlist.
2246 #[doc(alias = "VectorToPairList")]
2247 pub fn Rf_VectorToPairList(x: SEXP) -> SEXP;
2248
2249 // Install with CHARSXP
2250
2251 /// Install a symbol from a CHARSXP.
2252 ///
2253 /// Like `Rf_install()` but takes a CHARSXP instead of C string.
2254 #[doc(alias = "installChar")]
2255 pub fn Rf_installChar(x: SEXP) -> SEXP;
2256}
2257
2258// endregion