Skip to main content

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