miniextendr_api/lib.rs
1//! miniextendr-api: core runtime for Rust <-> R interop.
2//!
3//! This crate provides the FFI surface, safety wrappers, and macro re-exports
4//! used by most miniextendr users. It is the primary dependency for building
5//! Rust-powered R packages and exposing Rust types to R.
6//!
7//! At a glance:
8//! - FFI bindings + checked wrappers for R's C API (`sys`, `r_ffi_checked`).
9//! - Conversions between Rust and R types (`IntoR`, `TryFromSexp`, `Coerce`).
10//! - ALTREP traits, registration helpers, and iterator-backed ALTREP data types.
11//! - Wrapper generation from Rust signatures (`#[miniextendr]`, automatic registration via linkme).
12//! - Main-thread unwind protection plus optional worker dispatch (`worker`).
13//! - Class system support (S3, S4, S7, R6, env-style impl blocks).
14//! - Cross-package trait ABI for type-erased dispatch (`trait_abi`).
15//!
16//! Most users should depend on this crate directly. For embedding R in
17//! standalone binaries or integration tests, see `miniextendr-engine`.
18//!
19//! ## Quick start
20//!
21//! ```ignore
22//! use miniextendr_api::miniextendr;
23//!
24//! #[miniextendr]
25//! fn add(a: i32, b: i32) -> i32 {
26//! a + b
27//! }
28//! ```
29//!
30//! That's it — `#[miniextendr]` handles everything. Items self-register
31//! at link time; `miniextendr_init!` generates the `R_init_*` function
32//! that calls `package_init()` to register all routines with R.
33//! Wrapper R code is produced from Rust doc comments (roxygen tags are
34//! extracted) by loading the freshly linked package library and calling the
35//! registry writer. `R/miniextendr-wrappers.R` is regenerated during
36//! development installs, kept out of git, and shipped from disk in release
37//! tarballs; roxygen2 derives the tracked `NAMESPACE` and `man/*.Rd` files.
38//!
39//! ## Choosing the right API
40//!
41//! miniextendr has several places where two or more APIs reach the same
42//! goal with different tradeoffs — a stricter / safer / more validated
43//! option, and a looser / easier / less protective one. The most common
44//! pairs are:
45//!
46//! | I'm reaching for... | Consider also | Why |
47//! |---|---|---|
48//! | default `IntoR` for `i64` / `u64` / `isize` / `usize` (silently widens to `REALSXP` on overflow) | `#[miniextendr(strict)]` → [`crate::strict`] helpers (panic on overflow) | strict catches the truncation bugs caused by R having no native 64-bit integer type |
49//! | [`Coerce`] (infallible widening) | [`TryCoerce`] (fallible) | the source range can exceed the target type |
50//! | `Rf_*_unchecked` FFI | checked variants | unchecked is only safe inside ALTREP callbacks, `with_r_unwind_protect`, or `with_r_thread` — MXL301 lint enforces |
51//! | `panic!(msg)` | `miniextendr_api::error!("msg", class = "...")` | typed conditions let R-side `tryCatch` handlers route by class |
52//! | raw `_dots: &Dots` | `#[miniextendr(dots = typed_list!(...))]` | validation moves from runtime to macro call site |
53//! | `#[derive(AltrepInteger)]` field-based | `#[altrep(manual)]` + handwritten traits | when custom storage or computed-on-access can't fit the derive |
54//! | hand-rolled [`TryFromSexp`] + [`IntoR`] | `#[derive(RSerializeNative)]` (serde feature) | serde is ergonomic for nested structs; hand-rolled is zero-overhead and fully controlled |
55//!
56//! Project-wide defaults are controlled by mutually-exclusive cargo
57//! features — see the "Project-wide Defaults" feature table below.
58//!
59//! ### Default opinion
60//!
61//! When in doubt, pick the **stricter** path. The framework's default
62//! stance is "fail loudly, leave a trail." The looser variants exist for
63//! cases where the cost is measured or the looser semantics are correct
64//! for your data — they are not the default.
65//!
66//! ## GC protection and ownership
67//!
68//! R's garbage collector can reclaim any SEXP that isn't protected. miniextendr
69//! provides three complementary protection mechanisms:
70//!
71//! | Strategy | Module | Lifetime | Release Order | Use Case |
72//! |----------|--------|----------|---------------|----------|
73//! | **PROTECT stack** | [`gc_protect`] | Within `.Call` | LIFO (stack) | Temporary allocations |
74//! | **VECSXP pool** | [`protect_pool`] | Until released or the pool drops | Any order | Values a struct owns; many values; cross-call roots |
75//! | **R ownership** | [`ExternalPtr`](struct@ExternalPtr) | Until R GCs | R decides | Rust data owned by R |
76//!
77//! Quick guide:
78//!
79//! **Temporary allocations during computation** -> [`ProtectScope`]
80//! ```ignore
81//! unsafe fn compute(x: SEXP) -> SEXP {
82//! let scope = ProtectScope::new();
83//! let temp = scope.protect(Rf_allocVector(REALSXP, 100));
84//! // ... work with temp ...
85//! result.into_raw()
86//! } // UNPROTECT(n) called automatically
87//! ```
88//!
89//! **Values a struct owns, many values, or any drop order** -> [`ProtectPool`]
90//! ```ignore
91//! // The per-call root set: keep each value until the pool drops.
92//! let mut roots = ProtectPool::new(ProtectPool::DEFAULT_CAPACITY);
93//! let ids = roots.root(vec![1, 2, 3]);
94//!
95//! // Or release one value at a time, in any order, even across `.Call`s.
96//! let key = roots.insert(backing_vec);
97//! roots.release(key);
98//! ```
99//!
100//! **One long-lived object** -> [`Preserved`] (one `R_PreserveObject` root)
101//!
102//! **Rust data owned by R** -> [`ExternalPtr`](struct@ExternalPtr)
103//! ```ignore
104//! #[miniextendr]
105//! fn create_model() -> ExternalPtr<MyModel> {
106//! ExternalPtr::new(MyModel::new())
107//! } // R owns it; Drop runs when R GCs
108//! ```
109//!
110//! Note: ALTREP trait methods receive raw SEXP pointers from R's runtime.
111//! These are safe to dereference because R guarantees valid SEXPs in ALTREP callbacks.
112//!
113//! ## Threading and safety
114//!
115//! R uses `longjmp` for errors, which can bypass Rust destructors. Generated
116//! wrappers run inline on R's main thread inside `R_UnwindProtect` by default.
117//! Opt-in `#[miniextendr(worker)]` functions (or crates using
118//! `worker-default`) run Rust logic on the worker and marshal R API calls back
119//! through `with_r_thread`. Most FFI wrappers are main-thread routed via
120//! `#[r_ffi_checked]`. Use unchecked variants only when you have arranged a
121//! safe context.
122//!
123//! The `nonapi` feature exposes legacy controls for R's process-global stack
124//! bounds. Disabling that check does **not** make R's API safe off the main
125//! thread; package code must keep R API work on the recorded main thread.
126//!
127//! ## Feature Flags
128//!
129//! ### Core Features
130//!
131//! | Feature | Description |
132//! |---------|-------------|
133//! | `nonapi` | Non-API R symbols (stack controls, mutable `DATAPTR`). May break with R updates. |
134//! | `rayon` | Parallel iterators via Rayon. Adds `RParallelIterator`, `RParallelExtend`. |
135//! | `connections` | Experimental R connection framework. **Unstable R API.** |
136//! | `indicatif` | Progress bars routed through R connections. Requires `nonapi` + `connections`. |
137//! | `vctrs` | vctrs class construction (`new_vctr`, `new_rcrd`, `new_list_of`) and `#[derive(Vctrs)]`. |
138//! | `worker-thread` | Worker dispatch infrastructure. It does not change proc-macro defaults by itself; without it, worker APIs are inline stubs. |
139//!
140//! ### Type Conversions (Scalars & Vectors)
141//!
142//! | Feature | Rust Type | R Type | Notes |
143//! |---------|-----------|--------|-------|
144//! | `either` | `Either<L, R>` | Tries L then R | Union-like dispatch |
145//! | `uuid` | `Uuid`, `Vec<Uuid>` | `character` | UUID ↔ string |
146//! | `regex` | `Regex` | `character(1)` | Compiles pattern from R |
147//! | `url` | `Url`, `Vec<Url>` | `character` | Validated URLs |
148//! | `time` | `OffsetDateTime`, `Date` | `POSIXct`, `Date` | Date/time conversions |
149//! | `jiff` | `Timestamp`, `Zoned`, civil types | R date/time classes | IANA timezone-aware conversions |
150//! | `ordered-float` | `OrderedFloat<f64>` | `numeric` | NaN-orderable floats |
151//! | `num-bigint` | `BigInt`, `BigUint` | `character` | Arbitrary precision via strings |
152//! | `rust_decimal` | `Decimal` | `character` | Fixed-point decimals |
153//! | `num-complex` | `Complex<f64>` | `complex` | Native R complex support |
154//! | `indexmap` | `IndexMap<String, T>` | named `list` | Preserves insertion order |
155//! | `bitflags` | `RFlags<T>` | `integer` | Bitflags ↔ integer |
156//! | `bitvec` | `RBitVec` | `logical` | Bit vectors ↔ logical |
157//! | `tinyvec` | `TinyVec<[T; N]>`, `ArrayVec<[T; N]>` | vectors | Small-vector optimization |
158//!
159//! ### Matrix & Array Libraries
160//!
161//! | Feature | Types | Conversions |
162//! |---------|-------|-------------|
163//! | `ndarray` | `Array1`–`Array6`, `ArrayD`, views | R vectors/matrices ↔ ndarray |
164//! | `nalgebra` | `DVector`, `DMatrix` | R vectors/matrices ↔ nalgebra |
165//! | `blas-lapack` | `linalg::{matrix_product, solve}`, `sys::{dgemm_, dgesv_}` | R's own BLAS/LAPACK (links `$(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)`) |
166//!
167//! ### Serialization
168//!
169//! | Feature | Traits/Modules | Description |
170//! |---------|----------------|-------------|
171//! | `serde` | `RSerializeNative`, `RDeserializeNative` | Direct Rust ↔ R native serialization |
172//! | `serde_json` | `RSerialize`, `RDeserialize` | JSON string serialization (includes `serde`) |
173//! | `borsh` | `Borsh<T>` | Binary serialization ↔ raw vectors via Borsh |
174//!
175//! ### Adapter Traits (Generic Operations)
176//!
177//! | Feature | Traits | Use Case |
178//! |---------|--------|----------|
179//! | `num-traits` | `RNum`, `RSigned`, `RFloat` | Generic numeric operations |
180//! | `bytes` | `RBuf`, `RBufMut` | Byte buffer operations |
181//!
182//! ### Text & Data Processing
183//!
184//! | Feature | Types/Functions | Description |
185//! |---------|-----------------|-------------|
186//! | `aho-corasick` | `AhoCorasick`, `aho_compile` | Fast multi-pattern string search |
187//! | `toml` | `TomlValue`, `toml_from_str` | TOML parsing and serialization |
188//! | `tabled` | `table_to_string` | ASCII/Unicode table formatting |
189//! | `sha2` | `sha256_str`, `sha512_bytes` | Cryptographic hashing |
190//! | `blake3` | `blake3_str`, `blake3_bytes` | BLAKE3 hashing (fast, 32-byte digests) |
191//! | `md5` | `md5_str`, `md5_bytes` | MD5 hashing (interop only — broken crypto) |
192//! | `globset` | `GlobSet`, `build_globset` | Shell-style glob matching (path-aware) |
193//! | `zstd` | `zstd_compress`, `zstd_decompress` | zstd whole-buffer compression |
194//!
195//! ### Random Number Generation
196//!
197//! | Feature | Types | Description |
198//! |---------|-------|-------------|
199//! | `rand` | `RRng`, `RDistributions` | Wraps R's RNG with `rand` traits |
200//! | `rand_distr` | Re-exports `rand_distr` | Additional distributions (Normal, Exp, etc.) |
201//!
202//! ### Binary Data
203//!
204//! | Feature | Types | Description |
205//! |---------|-------|-------------|
206//! | `raw_conversions` | `Raw<T>`, `RawSlice<T>` | POD types ↔ raw vectors via bytemuck |
207//!
208//! ### Project-wide Defaults (mutually exclusive where noted)
209//!
210//! | Feature | Description |
211//! |---------|-------------|
212//! | `r6-default` | Default class system: R6 (mutually exclusive with `s7-default`) |
213//! | `s7-default` | Default class system: S7 (mutually exclusive with `r6-default`) |
214//! | `worker-default` | Default to worker thread dispatch (implies `worker-thread`) |
215//! | `strict-default` | Default to strict mode for lossy integer conversions |
216//! | `coerce-default` | Default to coerce mode for type conversions |
217//! | `no-preconditions-default` | Drop the R-side type checks by default (`preconditions` keeps them per item) |
218//!
219//! ### Development / Diagnostics
220//!
221//! | Feature | Description |
222//! |---------|-------------|
223//! | `doc-lint` | Warn on roxygen doc comment mismatches (enabled by default) |
224//! | `macro-coverage` | Expose macro coverage test module for `cargo expand` auditing |
225//! | `growth-debug` | Track and report collection growth events (zero-cost when off) |
226//! | `full-integrations` | Every optional dependency integration (maintenance aggregate) |
227//! | `full-codegen` | Codegen/runtime selectors using `r6-default` (maintenance aggregate) |
228//! | `full-codegen-s7` | Codegen/runtime selectors using `s7-default` (maintenance aggregate) |
229//! | `full` | Integrations + `full-codegen` + diagnostics for local checks |
230// Re-export linkme for use by generated code (distributed_slice entries)
231#[doc(hidden)]
232pub use linkme;
233
234// Procedural macros (re-exported from miniextendr-macros)
235#[doc(hidden)]
236pub use miniextendr_macros::__mx_trait_impl_expand;
237#[doc(inline)]
238pub use miniextendr_macros::AllEqual;
239#[doc(inline)]
240pub use miniextendr_macros::ExternalPtr;
241#[doc(inline)]
242pub use miniextendr_macros::impl_typed_external;
243#[doc(inline)]
244pub use miniextendr_macros::list;
245#[doc(inline)]
246pub use miniextendr_macros::miniextendr;
247#[doc(inline)]
248pub use miniextendr_macros::miniextendr_init;
249#[doc(inline)]
250pub use miniextendr_macros::r_ffi_checked;
251#[doc(inline)]
252pub use miniextendr_macros::reexport;
253#[doc(inline)]
254pub use miniextendr_macros::typed_dataframe;
255#[doc(inline)]
256pub use miniextendr_macros::typed_list;
257#[doc(inline)]
258pub use miniextendr_macros::{IsNA, RNativeType};
259// Note: RFactor derive macro is re-exported - it shares the name with the RFactor trait
260// but they're in different namespaces (derive macros vs types/traits)
261#[cfg(feature = "vctrs")]
262#[doc(inline)]
263pub use miniextendr_macros::{PreferVctrs, Vctrs};
264// Note: MatchArg derive macro is re-exported - it shares the name with the MatchArg trait
265// but they're in different namespaces (derive macros vs types/traits), same as RFactor.
266// The same applies to the `IntoR` and `TryFromSexp` derive macros, which share names with
267// the `IntoR` / `TryFromSexp` traits — `#[derive(IntoR)]` (macro namespace) and the trait
268// (type namespace) coexist, exactly like serde's `Serialize`. `RCondition` follows
269// suit: the enum and the derive are re-exported together from `condition`.
270#[doc(inline)]
271pub use miniextendr_macros::{
272 Altrep, AltrepComplex, AltrepInteger, AltrepList, AltrepLogical, AltrepRaw, AltrepReal,
273 AltrepString, DataFrameRow, IntoList, IntoR, MatchArg, PreferExternalPtr, PreferList,
274 PreferRNativeType, RFactor, TryFromList, TryFromSexp,
275};
276
277pub mod altrep;
278pub mod altrep_bridge;
279pub mod altrep_data;
280pub mod altrep_ext;
281pub mod altrep_impl;
282pub mod altrep_sexp;
283pub mod altrep_traits;
284
285// Re-export for backward compatibility - RegisterAltrep was moved from altrep_registration to altrep
286#[doc(hidden)]
287pub mod altrep_registration {
288 pub use crate::altrep::RegisterAltrep;
289}
290/// Core type vocabulary for R values: `SEXPTYPE`, `R_xlen_t`, `Rcomplex`,
291/// `RLogical`, `Rboolean`, `RNativeType`, `cetype_t`.
292pub mod sexp_types;
293
294/// The `SEXP` newtype and inherent methods.
295pub mod sexp;
296
297/// `SexpExt` and `PairListExt` — the ergonomic extension traits on `SEXP`.
298pub mod sexp_ext;
299
300/// Raw R FFI bindings — `extern "C-unwind"` blocks for `Rf_*` / `R_*` /
301/// `INTEGER` / etc., plus the ALTREP method type aliases under
302/// [`sys::altrep`]. The escape hatch for code that genuinely needs the raw
303/// R C API.
304///
305/// **Almost no user code should reach into this module.** The framework
306/// expects you to use the crate-root re-exports for the type vocabulary
307/// ([`SEXP`], [`SexpExt`], [`SEXPTYPE`], [`R_xlen_t`], …) and the
308/// higher-level safe wrappers ([`IntoR`], [`TryFromSexp`],
309/// [`worker::with_r_thread`], [`unwind_protect::with_r_unwind_protect`],
310/// the `#[miniextendr]` proc-macro). `sys::` is only here so those
311/// wrappers — and the rare hand-rolled FFI in tests or benchmarks — have
312/// something to call.
313pub mod sys;
314
315// Crate-root re-exports for the ergonomic API surface.
316pub use sexp::{SEXP, SEXPREC};
317pub use sexp_ext::{PairListArgs, PairListExt, SexpExt};
318pub use sexp_types::{
319 IsNA, R_CFinalizer_t, R_xlen_t, RLogical, RNativeType, Rboolean, Rbyte, Rcomplex, SEXPTYPE,
320 cetype_t,
321};
322
323pub mod registry;
324
325/// Host-time generator of `wasm_registry.rs` — the WASM-side replacement for
326/// linkme. See the module for full rationale.
327///
328/// Host-only — the writer reads the live linkme distributed slices to format
329/// `wasm_registry.rs`, and linkme isn't available on wasm32 anyway.
330#[cfg(not(target_arch = "wasm32"))]
331pub mod wasm_registry_writer;
332
333// Re-export high-level ALTREP data traits
334pub use altrep_data::{
335 AltComplexData,
336 AltIntegerData,
337 AltListData,
338 AltLogicalData,
339 AltRawData,
340 AltRealData,
341 AltStringData,
342 AltrepBuffer,
343 AltrepDataptr,
344 AltrepExtract,
345 AltrepIteratorExt,
346 AltrepIteratorItem,
347 AltrepLen,
348 // Iterator-backed ALTREP types (R-native)
349 IterComplexData,
350 // Iterator-backed ALTREP types (with Coerce support)
351 IterIntCoerceData,
352 IterIntData,
353 IterIntFromBoolData,
354 IterListData,
355 IterLogicalData,
356 IterRLogicalData,
357 IterRawData,
358 IterRealCoerceData,
359 IterRealData,
360 IterState,
361 IterStringData,
362 Logical,
363 Sortedness,
364 // Sparse iterator-backed ALTREP types (compute-on-access)
365 SparseIterComplexData,
366 SparseIterIntData,
367 SparseIterLogicalData,
368 SparseIterRawData,
369 SparseIterRealData,
370 SparseIterState,
371 // Streaming ALTREP types (chunk-cached reader closures)
372 StreamingIntData,
373 StreamingRealData,
374 // Windowed iterator-backed ALTREP types
375 WindowedIterIntData,
376 WindowedIterRealData,
377 WindowedIterState,
378};
379// Re-export RBase enum, AltrepGuard, and AltrepSexp
380pub use altrep::RBase;
381pub use altrep_sexp::{AltrepSexp, ensure_materialized};
382pub use altrep_traits::AltrepGuard;
383
384// ALTREP package name global - set by C entrypoint before ALTREP registration
385// This is a pointer to a null-terminated C string provided by C code.
386// Default: c"unknown" for safety if not set.
387use std::sync::atomic::{AtomicPtr, Ordering};
388static ALTREP_PKG_NAME_PTR: AtomicPtr<std::ffi::c_char> =
389 AtomicPtr::new(c"unknown".as_ptr().cast_mut());
390
391/// Returns the current ALTREP package name as a C string pointer.
392/// This is set by the C entrypoint before ALTREP registration.
393#[doc(hidden)]
394pub struct AltrepPkgName;
395
396impl AltrepPkgName {
397 /// Get the package name pointer.
398 #[inline]
399 pub fn as_ptr() -> *const std::ffi::c_char {
400 ALTREP_PKG_NAME_PTR.load(Ordering::Acquire)
401 }
402}
403
404/// Opaque handle for ALTREP package name.
405/// Use `ALTREP_PKG_NAME.as_ptr()` to get the C string pointer.
406#[doc(hidden)]
407pub static ALTREP_PKG_NAME: AltrepPkgName = AltrepPkgName;
408
409/// Set the ALTREP package name. Called from C entrypoint.
410/// # Safety
411/// The provided pointer must point to a valid null-terminated C string
412/// that lives for the duration of the R session.
413///
414/// The strict requirement is narrower: R copies the bytes via `install()`
415/// inside each `R_make_alt*_class` call that consults this global (see
416/// `RegisterClass` in R's `src/main/altrep.c`), so the pointer only has to
417/// remain valid across those calls. We keep the session-lifetime contract
418/// because we don't track which registrations are still pending; a string
419/// literal passed from C satisfies both.
420#[doc(hidden)]
421#[unsafe(no_mangle)]
422pub unsafe extern "C" fn miniextendr_set_altrep_pkg_name(name: *const std::ffi::c_char) {
423 let name = if name.is_null() {
424 c"unknown".as_ptr()
425 } else {
426 name
427 };
428 ALTREP_PKG_NAME_PTR.store(name.cast_mut(), Ordering::Release);
429}
430
431// DllInfo global — stored during package_init, used by ALTREP class registration.
432// R needs DllInfo to associate ALTREP classes with their package for serialization.
433// Without it, readRDS in a fresh session can't find the class.
434static ALTREP_DLL_INFO: AtomicPtr<std::ffi::c_void> = AtomicPtr::new(std::ptr::null_mut());
435
436/// Get the stored DllInfo pointer for ALTREP class registration.
437#[doc(hidden)]
438pub fn altrep_dll_info() -> *mut sys::DllInfo {
439 ALTREP_DLL_INFO.load(Ordering::Acquire).cast()
440}
441
442/// Store the DllInfo pointer during package init.
443#[doc(hidden)]
444pub fn set_altrep_dll_info(dll: *mut sys::DllInfo) {
445 ALTREP_DLL_INFO.store(dll.cast(), Ordering::Release);
446}
447
448mod tuple_macros;
449
450pub mod from_r;
451pub mod into_r;
452pub mod into_r_error;
453pub use into_r::{Altrep, IntoR, IntoRAltrep};
454/// Container conversions for newtypes (`#[derive(TryFromSexp)]` /
455/// `#[derive(IntoR)]`) and string-parsed types
456/// (`try_from_sexp_via_str_parse!`). See the module docs, #844 and #1766.
457pub mod newtype;
458pub use into_r_error::IntoRError;
459pub use newtype::{IntoRNewtype, IntoRVecElement, TryFromSexpElement};
460pub mod into_r_as;
461pub use into_r_as::{IntoRAs, StorageCoerceError};
462pub mod pump;
463pub mod unwind_protect;
464pub mod worker;
465
466// Re-export commonly used worker items at root for convenience
467pub use worker::{Sendable, is_r_main_thread, with_r_thread};
468
469// Required exports for generated code and initialization
470pub use worker::miniextendr_runtime_init;
471
472// Advanced stack-configuration utilities; not permission for off-main R API use
473pub mod thread;
474
475// Collection growth debug instrumentation (diagnostics)
476#[cfg(feature = "growth-debug")]
477pub mod growth_debug;
478
479/// Track a collection growth (reallocation) event.
480///
481/// When the `growth-debug` feature is enabled, increments a thread-local counter
482/// for the named collection. When disabled, compiles to a no-op.
483///
484/// # Example
485///
486/// ```ignore
487/// let old_cap = vec.capacity();
488/// vec.push(item);
489/// if vec.capacity() != old_cap {
490/// track_growth!("my_vec");
491/// }
492/// ```
493#[cfg(feature = "growth-debug")]
494#[macro_export]
495macro_rules! track_growth {
496 ($name:expr) => {
497 $crate::growth_debug::record_growth($name)
498 };
499}
500
501/// Track a collection growth (reallocation) event.
502///
503/// No-op when `growth-debug` feature is disabled.
504#[cfg(not(feature = "growth-debug"))]
505#[macro_export]
506macro_rules! track_growth {
507 ($name:expr) => {};
508}
509
510/// Print and reset all growth counters.
511///
512/// When the `growth-debug` feature is enabled, prints all tracked growth events
513/// to stderr and resets the counters. When disabled, compiles to a no-op.
514#[cfg(feature = "growth-debug")]
515#[macro_export]
516macro_rules! report_growth {
517 () => {
518 $crate::growth_debug::report_and_reset()
519 };
520}
521
522/// Print and reset all growth counters.
523///
524/// No-op when `growth-debug` feature is disabled.
525#[cfg(not(feature = "growth-debug"))]
526#[macro_export]
527macro_rules! report_growth {
528 () => {};
529}
530
531/// Parse and evaluate **runtime** R source from Rust.
532///
533/// `r_str!` is sugar around [`expression::r_eval_str`]. It is the right tool
534/// when the R code is genuinely dynamic — built with `format!`, derived from
535/// user input, or otherwise not known at compile time. For code you can write
536/// literally, prefer [`r!`](crate::r), which gives a cheap compile-time
537/// sanity check on the token stream.
538///
539/// The argument is any expression evaluating to something `AsRef<str>`
540/// (`&str`, `String`, `&String`, …). It is parsed with `R_ParseVector` and
541/// evaluated with `Rf_eval`, with every intermediate SEXP protected and the
542/// parse status checked, so a syntax error becomes an `Err`, never a segfault
543/// or silent wrong answer.
544///
545/// # Forms
546///
547/// - `r_str!(code)` — evaluate in `R_GlobalEnv`.
548/// - `r_str!(code, env = e)` — evaluate in the environment SEXP `e`.
549///
550/// Both forms evaluate to `Result<SEXP, REvalError>`; the `SEXP` is **unprotected**
551/// (protect it before further allocations).
552///
553/// # Safety
554///
555/// Expands to an `unsafe` block. Must be reached from (or routed to) the R
556/// main thread — the underlying FFI is `#[r_ffi_checked]`, so calls from a
557/// worker thread are serialized onto the R thread.
558///
559/// # Example
560///
561/// ```ignore
562/// let obj = "mtcars";
563/// let code = format!("summary({obj})");
564/// let summary = r_str!(&code)?; // in R_GlobalEnv
565/// let three = r_str!("1L + 2L")?;
566/// let in_env = r_str!("x + 1", env = my_env)?;
567/// ```
568#[macro_export]
569macro_rules! r_str {
570 ($code:expr $(,)?) => {
571 unsafe {
572 $crate::expression::r_eval_str(
573 ::core::convert::AsRef::<str>::as_ref(&$code),
574 $crate::sys::R_GlobalEnv,
575 )
576 }
577 };
578 ($code:expr, env = $env:expr $(,)?) => {
579 unsafe {
580 $crate::expression::r_eval_str(::core::convert::AsRef::<str>::as_ref(&$code), $env)
581 }
582 };
583}
584
585/// Evaluate R code written as **Rust tokens**, validated at compile time.
586///
587/// `r!` takes a single R expression as a token stream, `stringify!`s it into a
588/// static R source string at build time, and evaluates it via
589/// [`expression::r_eval_str`] (the same protect-safe parse + eval path as
590/// [`r_str!`](crate::r_str)).
591///
592/// # What you get today
593///
594/// Because the argument is a Rust token tree, the Rust front-end already
595/// rejects **unbalanced delimiters** (`r!(f(1, 2)` won't compile) and
596/// lexically invalid tokens before R ever sees the string — a cheap
597/// compile-time guard over the pure-runtime [`r_str!`](crate::r_str). The
598/// source is lowered to a `&'static str` (`stringify!`), so there is no
599/// `format!` allocation at the call site.
600///
601/// This proc-macro additionally validates a conservative subset of known-bad
602/// R syntax constructs (trailing binary operators, consecutive non-unary
603/// binary operators, bare `if`/`while`/`for` without a body, etc.) and emits
604/// a precise compile error pointing at the offending token. Empty (missing)
605/// call arguments — `f(, x)`, `matrix(, 2, 2)` — are valid R and pass.
606///
607/// # What is deferred
608///
609/// Direct `Rf_lang*` call-tree lowering (skipping the runtime parser entirely)
610/// is tracked as a follow-up — see issue #938 (item 2). Until then `r!` parses
611/// its static string at first evaluation, exactly like `r_str!`.
612///
613/// # Non-goals
614///
615/// A complete R grammar validator is not achievable over Rust tokens:
616/// - Single-quoted strings (`'hello'`) and backtick-quoted names (`` `foo` ``)
617/// already die at the Rust lexer — nothing to validate.
618/// - `%op%` tokenises as `%`, ident, `%` and is accepted without analysis.
619/// - Anything the validator cannot confidently classify as wrong passes through
620/// unvalidated (conservative reject-only-known-bad design).
621///
622/// # Forms
623///
624/// - `r!(R tokens…)` — evaluate in `R_GlobalEnv`.
625/// - `r!(env: e; R tokens…)` — evaluate in the environment SEXP `e`. The
626/// leading `env: <expr> ;` is consumed as Rust, the rest is R source. (The
627/// `;` separator is used instead of a trailing `, env =` because R source is
628/// a free token stream — a trailing keyword can't be reliably split off it.)
629///
630/// Both evaluate to `Result<SEXP, REvalError>`; the `SEXP` is **unprotected**.
631///
632/// For genuinely dynamic code, use [`r_str!`](crate::r_str) instead.
633///
634/// # Note on `stringify!` spacing
635///
636/// `stringify!` normalises whitespace (`a+b` and `a + b` both stringify to
637/// `a + b`) but preserves token order and literal contents, which is all R's
638/// parser needs. String literals keep their quotes.
639///
640/// # Safety
641///
642/// Expands to an `unsafe` block; see [`r_str!`](crate::r_str).
643///
644/// # Example
645///
646/// ```ignore
647/// let three = r!(1L + 2L)?;
648/// let rows = r!(getFromNamespace(".theoph_rows", "dataframeflows")())?;
649/// let in_env = r!(env: my_env; x + 1)?;
650/// ```
651#[doc(inline)]
652pub use miniextendr_macros::r;
653
654// `indicatif` progress integration (R console)
655#[cfg(feature = "indicatif")]
656pub mod progress;
657#[cfg(feature = "indicatif")]
658pub use indicatif;
659
660// Legacy R-oriented stack sizing (always available; not an off-main R bridge)
661#[cfg(windows)]
662pub use thread::WINDOWS_R_STACK_SIZE;
663pub use thread::{DEFAULT_R_STACK_SIZE, RThreadBuilder};
664
665// Legacy process-global stack controls (requires nonapi; removal tracked in #1352)
666#[cfg(feature = "nonapi")]
667pub use thread::{StackCheckGuard, scope_with_r, spawn_with_r, with_stack_checking_disabled};
668
669// Panic telemetry hook for structured panic→R-error diagnostics
670pub mod panic_telemetry;
671
672// Unified FFI guard for catching panics at Rust-R boundaries
673pub mod ffi_guard;
674pub use ffi_guard::{GuardMode, guarded_ffi_call, guarded_ffi_call_with_fallback};
675
676// The unified owned data.frame type + conversion trait family
677pub mod dataframe;
678pub use dataframe::{
679 BuiltDataFrame, ColumnarFrame, DataFrame, DataFrameError, DataFrameShape, FromDataFrame,
680 GroupDeclaration, GroupKey, GroupedDataFrame, IntoDataFrame, IntoDataFrameSplit, RealKey,
681 SplitResults, group_rows,
682};
683
684// Closure-per-column DataFrame builder (parallel fill with `rayon`, serial
685// otherwise). Available regardless of the `rayon` feature (#1055).
686pub mod dataframe_builder;
687pub use dataframe_builder::RDataFrameBuilder;
688
689// Strict conversion helpers for #[miniextendr(strict)]
690pub mod strict;
691
692// Cached R class attribute SEXPs (POSIXct, Date, data.frame, etc.)
693pub mod cached_class;
694
695// Tagged condition value transport for the Rust→R boundary
696pub mod error_value;
697
698// Error handling helpers (r_warning, r_print!, r_println! macros)
699pub mod error;
700pub use error::r_warning;
701
702// RNG (random number generation) utilities
703pub mod rng;
704pub use rng::{RngGuard, with_rng};
705
706// Re-export from_r
707pub use from_r::{
708 SexpClassError, SexpError, SexpLengthError, SexpNaError, SexpTypeError, TryFromRoot,
709 TryFromSexp,
710};
711
712// Encoding / locale probing (mainly for debugging). The module is always
713// compiled; the symbols that reference non-API locale state from R's `Defn.h`
714// (`utf8locale`, `mbcslocale`, `known_to_be_latin1`) are gated inside the
715// module behind `#[cfg(feature = "nonapi")]` so a default build never links
716// them. Only R-exported symbols may be declared there — hidden ones abort
717// dyn.load (see sys::nonapi_encoding).
718pub mod encoding;
719
720// Expression evaluation helpers (RSymbol, RCall, REnv)
721pub mod expression;
722pub use expression::{RCall, REnv, REvalError, RSymbol, r_eval_str, r_eval_str_global};
723
724// S4 slot access and class checking helpers
725pub mod s4_helpers;
726
727pub mod backtrace;
728
729/// Shared truthiness parsing for boolean-ish environment-variable flags.
730pub(crate) mod env_flag;
731
732pub mod coerce;
733pub use coerce::{Coerce, CoerceError, Coerced, TryCoerce};
734
735/// Traits for R's `as.<class>()` coercion functions.
736///
737/// This module provides traits for implementing R's generic coercion methods
738/// (`as.data.frame()`, `as.list()`, `as.character()`, etc.) for Rust types
739/// wrapped in [`ExternalPtr`](struct@ExternalPtr).
740///
741/// See the [`r_coerce`] module documentation for usage examples.
742pub mod r_coerce;
743pub use r_coerce::{
744 // Core coercion traits (R's `as.<class>()` generics)
745 RCoerceCharacter,
746 RCoerceComplex,
747 RCoerceDataFrame,
748 RCoerceDate,
749 RCoerceEnvironment,
750 // Error type
751 RCoerceError,
752 RCoerceFactor,
753 RCoerceFunction,
754 RCoerceInteger,
755 RCoerceList,
756 RCoerceLogical,
757 RCoerceMatrix,
758 RCoerceNumeric,
759 RCoercePOSIXct,
760 RCoerceRaw,
761 RCoerceVector,
762 // Helpers
763 SUPPORTED_AS_GENERICS,
764 is_supported_as_generic,
765};
766
767pub mod condition;
768pub use condition::{ArgError, AsRError, RCondition};
769pub mod deferred_condition;
770pub use deferred_condition::{defer_condition, defer_message, defer_warning};
771pub mod convert;
772pub mod dots;
773pub mod list;
774pub mod missing;
775/// Return-visibility markers (`Invisible<T>` / `Visible<T>`).
776pub mod visibility;
777pub use visibility::{Invisible, Visible};
778/// The `NULL`-on-`None` return type (`Nullable<T>`).
779pub mod nullable;
780pub use nullable::Nullable;
781/// Condition-call markers (`Call` / `CallerCall`) for `#[miniextendr]` parameters.
782pub mod call_marker;
783pub use call_marker::{Call, CallerCall};
784/// The argument-count marker (`NArgs`) for `#[miniextendr]` parameters.
785pub mod nargs;
786pub use nargs::NArgs;
787/// Unevaluated-argument markers (`Quoted` / `Quosure`) for `#[miniextendr]` parameters.
788pub mod quoted;
789pub use quoted::{Quosure, Quoted};
790pub mod lazy_dots;
791pub use lazy_dots::LazyDots;
792/// Precondition markers (`Checked<T>` / `Unchecked<T>`) for `#[miniextendr]` parameters.
793pub mod precondition_marker;
794pub use precondition_marker::{Checked, Unchecked};
795
796/// Explicit R class-system return markers.
797pub mod wrap_as;
798pub use wrap_as::{
799 ConvertFrom, ConvertTo, WrapAsEnv, WrapAsR6, WrapAsS3, WrapAsS4, WrapAsS7, WrapAsVctrs,
800};
801pub mod named_vector;
802pub mod rcow;
803pub mod rvalue;
804pub use rvalue::RValue;
805pub mod strvec;
806pub mod typed_list;
807pub use convert::{
808 AsCharacter, AsCharacterVec, AsDataFrame, AsDataFrameExt, AsDisplay, AsDisplayVec,
809 AsExternalPtr, AsExternalPtrExt, AsFromStr, AsFromStrVec, AsList, AsListExt, AsNamedList,
810 AsNamedListExt, AsNamedVector, AsNamedVectorExt, AsNumeric, AsNumericVec, AsRNative,
811 AsRNativeExt, Collect, CollectNA, CollectNAInt, CollectStrings, ColumnSource,
812};
813#[cfg(feature = "vctrs")]
814pub use convert::{AsVctrs, AsVctrsExt};
815pub use into_r::Lazy;
816pub use list::{
817 BuiltList, IntoList, List, ListAccumulator, ListBuilder, ListMut, NamedList, NamedListBuilder,
818 TryFromList, collect_list,
819};
820pub use missing::{Missing, is_missing_arg};
821pub use named_vector::{AtomicElement, NamedVector};
822pub use rcow::{RBorrow, RCow};
823pub use strvec::{
824 ProtectedStrVec, ProtectedStrVecCowIter, ProtectedStrVecIter, StrVec, StrVecBuilder,
825 StrVecCowIter, StrVecIter,
826};
827pub use typed_list::{
828 TypeSpec, TypedEntry, TypedList, TypedListError, TypedListSpec, actual_type_string,
829 sexptype_name, validate_list,
830};
831
832// External pointer module - Box-like owned pointer wrapping R's EXTPTRSXP
833pub mod externalptr;
834
835// Matrix product / linear solve through R's own BLAS and LAPACK
836#[cfg(feature = "blas-lapack")]
837pub mod linalg;
838
839// Connection framework (unstable R API - use with caution)
840#[cfg(feature = "connections")]
841pub mod connection;
842// txtProgressBar handle — drives utils::txtProgressBar from Rust
843#[cfg(feature = "connections")]
844pub mod txt_progress_bar;
845pub use externalptr::{
846 ErasedExternalPtr,
847 ExternalPtr,
848 ExternalPtrMut,
849 ExternalPtrRef,
850 ExternalSlice,
851 IntoExternalPtr,
852 TypedExternal,
853 // ALTREP helpers (checked)
854 altrep_data1_as,
855 // ALTREP helpers (unchecked - for performance-critical callbacks)
856 altrep_data1_as_unchecked,
857 altrep_data1_mut,
858 altrep_data1_mut_unchecked,
859 altrep_data2_as,
860 altrep_data2_as_unchecked,
861};
862
863// TypedExternal implementations for std types
864pub mod externalptr_std;
865
866// GC protection toolkit (PROTECT stack RAII wrappers)
867pub mod gc_protect;
868pub use gc_protect::{
869 OwnedProtect, ProtectIndex, ProtectScope, Protected, Protector, ReprotectSlot, Root,
870};
871
872// One owned precious-list root (R_PreserveObject / R_ReleaseObject)
873pub mod preserved;
874pub use preserved::Preserved;
875
876// VECSXP pool with generational keys (slotmap-backed)
877pub mod protect_pool;
878pub use protect_pool::{ProtectKey, ProtectPool};
879
880// Reference-counted GC protection (BTreeMap + VECSXP backing)
881pub mod refcount_protect;
882pub use refcount_protect::{ArenaGuard, RefCountedArena, ThreadLocalArena};
883
884pub mod allocator;
885pub use allocator::RAllocator;
886
887// region: Trait ABI Support
888//
889// Cross-package trait dispatch using a stable C ABI.
890// See `trait_abi` module docs for details.
891
892/// ABI types for cross-package trait dispatch.
893///
894/// This module defines the stable, C-compatible types used for runtime trait
895/// dispatch across R package boundaries.
896pub mod abi;
897
898/// C-callable mx_abi functions (mx_wrap, mx_get, mx_query, mx_abi_register).
899///
900/// These are registered via `R_RegisterCCallable` during package init and
901/// loaded by consumer packages via `R_GetCCallable`.
902pub mod mx_abi;
903
904pub mod init;
905
906/// Runtime support for trait ABI operations.
907///
908/// Provides C-callable loading and type conversion helpers for trait ABI support.
909pub mod trait_abi;
910
911/// vctrs class construction and trait support.
912///
913/// Provides helpers for building vctrs-compatible R objects and traits
914/// for describing vctrs class metadata from Rust types.
915///
916/// Enable with `features = ["vctrs"]`.
917#[cfg(feature = "vctrs")]
918pub mod vctrs;
919#[cfg(feature = "vctrs")]
920pub use vctrs::{
921 IntoVctrs, VctrsBuildError, VctrsClass, VctrsKind, VctrsListOf, VctrsRecord, new_list_of,
922 new_rcrd, new_vctr,
923};
924
925// Re-export key ABI types at crate root for convenience
926pub use abi::{mx_base_vtable, mx_erased, mx_meth, mx_tag};
927pub use trait_abi::TraitView;
928// endregion
929
930// region: Marker Traits
931//
932// Marker traits for types derived with proc-macros.
933// These enable compile-time identification and blanket implementations.
934
935/// Marker traits for proc-macro derived types.
936pub mod markers;
937// endregion
938
939// region: Adapter Traits
940//
941// Built-in adapter traits with blanket implementations for standard library traits.
942// These allow any Rust type implementing Debug, Display, Hash, Ord, etc. to be
943// exposed to R without boilerplate.
944
945/// Built-in adapter traits for std library traits.
946///
947/// Provides [`RDebug`], [`RDisplay`], [`RHash`], [`ROrd`], [`RPartialOrd`],
948/// [`RError`], [`RFromStr`], [`RClone`], [`RCopy`], [`RDefault`], [`RIterator`],
949/// [`RExtend`], [`RFromIter`], [`RToVec`], and [`RMakeIter`] with blanket
950/// implementations where possible. Methods that share a name with a std
951/// method are `r_`-prefixed in Rust and keep the std name in R, so importing
952/// these traits leaves std calls alone. See module docs for usage.
953///
954/// [`RDebug`]: adapter_traits::RDebug
955/// [`RDisplay`]: adapter_traits::RDisplay
956/// [`RHash`]: adapter_traits::RHash
957/// [`ROrd`]: adapter_traits::ROrd
958/// [`RPartialOrd`]: adapter_traits::RPartialOrd
959/// [`RError`]: adapter_traits::RError
960/// [`RFromStr`]: adapter_traits::RFromStr
961/// [`RClone`]: adapter_traits::RClone
962/// [`RCopy`]: adapter_traits::RCopy
963/// [`RDefault`]: adapter_traits::RDefault
964/// [`RIterator`]: adapter_traits::RIterator
965/// [`RExtend`]: adapter_traits::RExtend
966/// [`RFromIter`]: adapter_traits::RFromIter
967/// [`RToVec`]: adapter_traits::RToVec
968/// [`RMakeIter`]: adapter_traits::RMakeIter
969pub mod adapter_traits;
970pub use adapter_traits::{
971 RClone, RCopy, RDebug, RDefault, RDisplay, RError, RExtend, RFromIter, RFromStr, RHash,
972 RIterator, RMakeIter, ROrd, RPartialOrd, RToVec,
973};
974
975/// This is used to ensure the macros of `miniextendr-macros` treat this crate as a "user crate"
976/// atleast in the `macro_coverage`
977#[doc(hidden)]
978extern crate self as miniextendr_api;
979
980#[cfg(feature = "macro-coverage")]
981#[doc(hidden)]
982pub mod macro_coverage;
983
984/// The crate-root marker `miniextendr_init!` defines in a package crate, for
985/// the `#[miniextendr]` items of `macro_coverage`: under `serde` their `Err`
986/// arms look up `serde_error_shape!` declarations by it. None is declared.
987#[cfg(all(feature = "macro-coverage", feature = "serde"))]
988enum __MiniextendrInitMarker {}
989// endregion
990
991// region: Optional integrations with external crates (feature-gated)
992//
993// All optional feature integrations are organized in the `optionals` module.
994// Types are re-exported at crate root for backwards compatibility.
995
996/// Optional feature integrations with third-party crates.
997///
998/// This module contains all feature-gated integrations with external crates.
999/// Each submodule is only compiled when its corresponding feature is enabled.
1000/// See the [module documentation][optionals] for a complete list of available features.
1001pub mod optionals;
1002
1003// Re-export optional types at crate root for backwards compatibility
1004#[cfg(feature = "rayon")]
1005pub use optionals::parallel;
1006#[cfg(feature = "rayon")]
1007pub use optionals::rayon_bridge;
1008#[cfg(feature = "rayon")]
1009pub use optionals::{RParallelExtend, RParallelIterator};
1010
1011#[cfg(feature = "rand")]
1012pub use optionals::rand;
1013#[cfg(feature = "rand_distr")]
1014pub use optionals::rand_distr;
1015#[cfg(feature = "rand")]
1016pub use optionals::rand_impl;
1017#[cfg(feature = "rand")]
1018pub use optionals::{RDistributionOps, RDistributions, RRng, RRngOps};
1019
1020#[cfg(feature = "either")]
1021pub use optionals::either_impl;
1022#[cfg(feature = "either")]
1023pub use optionals::{Either, Left, Right};
1024
1025#[cfg(feature = "ndarray")]
1026pub use optionals::ndarray_impl;
1027#[cfg(feature = "ndarray")]
1028pub use optionals::{
1029 ArcArray1, ArcArray2, Array0, Array1, Array2, Array3, Array4, Array5, Array6, ArrayD,
1030 ArrayView0, ArrayView1, ArrayView2, ArrayView3, ArrayView4, ArrayView5, ArrayView6, ArrayViewD,
1031 ArrayViewMut0, ArrayViewMut1, ArrayViewMut2, ArrayViewMut3, ArrayViewMut4, ArrayViewMut5,
1032 ArrayViewMut6, ArrayViewMutD, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, RNdArrayOps, RNdIndex,
1033 RNdSlice, RNdSlice2D, ShapeBuilder,
1034};
1035
1036#[cfg(feature = "nalgebra")]
1037pub use optionals::nalgebra_impl;
1038#[cfg(feature = "nalgebra")]
1039pub use optionals::{DMatrix, DVector, RMatrixOps, RVectorOps, SMatrix, SVector};
1040
1041#[cfg(feature = "num-bigint")]
1042pub use optionals::num_bigint_impl;
1043#[cfg(feature = "num-bigint")]
1044pub use optionals::{BigInt, BigUint, RBigIntBitOps, RBigIntOps, RBigUintBitOps, RBigUintOps};
1045
1046#[cfg(feature = "rust_decimal")]
1047pub use optionals::rust_decimal_impl;
1048#[cfg(feature = "rust_decimal")]
1049pub use optionals::{Decimal, RDecimalOps};
1050
1051#[cfg(feature = "ordered-float")]
1052pub use optionals::ordered_float_impl;
1053#[cfg(feature = "ordered-float")]
1054pub use optionals::{OrderedFloat, ROrderedFloatOps};
1055
1056#[cfg(feature = "num-complex")]
1057pub use optionals::num_complex_impl;
1058#[cfg(feature = "num-complex")]
1059pub use optionals::{Complex, RComplexOps};
1060
1061#[cfg(feature = "num-traits")]
1062pub use optionals::num_traits_impl;
1063#[cfg(feature = "num-traits")]
1064pub use optionals::{RFloat, RNum, RSigned};
1065
1066#[cfg(feature = "uuid")]
1067pub use optionals::uuid_impl;
1068#[cfg(feature = "uuid")]
1069pub use optionals::{RUuidOps, Uuid, uuid_helpers};
1070
1071#[cfg(feature = "regex")]
1072pub use optionals::regex_impl;
1073#[cfg(feature = "regex")]
1074pub use optionals::{CaptureGroups, RCaptureGroups, RRegexOps, Regex};
1075
1076#[cfg(feature = "url")]
1077pub use optionals::url_impl;
1078#[cfg(feature = "url")]
1079pub use optionals::{RUrlOps, Url, url_helpers};
1080
1081#[cfg(feature = "aho-corasick")]
1082pub use optionals::aho_corasick_impl;
1083#[cfg(feature = "aho-corasick")]
1084pub use optionals::{
1085 AhoCorasick, RAhoCorasickOps, aho_compile, aho_count_matches, aho_find_all, aho_find_all_flat,
1086 aho_find_first, aho_is_match, aho_replace_all,
1087};
1088
1089#[cfg(feature = "indexmap")]
1090pub use optionals::indexmap_impl;
1091#[cfg(feature = "indexmap")]
1092pub use optionals::{IndexMap, RIndexMapOps};
1093
1094#[cfg(feature = "time")]
1095pub use optionals::time_impl;
1096#[cfg(feature = "time")]
1097pub use optionals::{Date, Duration, OffsetDateTime, RDateTimeFormat, RDuration};
1098#[cfg(feature = "time")]
1099pub use time;
1100
1101#[cfg(feature = "jiff")]
1102pub use jiff;
1103#[cfg(feature = "jiff")]
1104pub use optionals::jiff_impl;
1105#[cfg(feature = "jiff")]
1106pub use optionals::{
1107 JiffDate, JiffDateTime, JiffTime, JiffTimestampVec, JiffZonedVec, RDate, RDateTime,
1108 RSignedDuration, RSpan, RTime, RTimestamp, RZoned, SignedDuration, Span, Timestamp, Zoned,
1109};
1110
1111#[cfg(feature = "serde_json")]
1112pub use optionals::serde_impl;
1113#[cfg(feature = "toml")]
1114pub use optionals::toml_impl;
1115#[cfg(feature = "serde_json")]
1116pub use optionals::{
1117 FactorHandling, JsonOptions, JsonValue, NaHandling, RDeserialize, RJsonBridge, RJsonValueOps,
1118 RSerialize, SpecialFloatHandling, json_from_sexp, json_from_sexp_permissive,
1119 json_from_sexp_strict, json_from_sexp_with, json_into_sexp,
1120};
1121#[cfg(feature = "toml")]
1122pub use optionals::{RTomlOps, TomlValue, toml_from_str, toml_to_string, toml_to_string_pretty};
1123
1124#[cfg(feature = "bytes")]
1125pub use optionals::bytes_impl;
1126#[cfg(feature = "bytes")]
1127pub use optionals::{Buf, BufMut, Bytes, BytesMut, RBuf, RBufMut};
1128
1129#[cfg(feature = "sha2")]
1130pub use optionals::sha2_impl;
1131#[cfg(feature = "sha2")]
1132pub use optionals::{sha256_bytes, sha256_str, sha512_bytes, sha512_str};
1133
1134#[cfg(feature = "blake3")]
1135pub use optionals::blake3_impl;
1136#[cfg(feature = "blake3")]
1137pub use optionals::{blake3_bytes, blake3_hex, blake3_str};
1138
1139#[cfg(feature = "md5")]
1140pub use optionals::md5_impl;
1141#[cfg(feature = "md5")]
1142pub use optionals::{md5_bytes, md5_hex, md5_str};
1143
1144#[cfg(feature = "globset")]
1145pub use optionals::globset_impl;
1146#[cfg(feature = "globset")]
1147pub use optionals::{
1148 Glob, GlobBuilder, GlobOptions, GlobSet, GlobSetBuilder, build_globset, globset_is_match,
1149 globset_matches,
1150};
1151
1152#[cfg(feature = "zstd")]
1153pub use optionals::zstd_impl;
1154#[cfg(feature = "zstd")]
1155pub use optionals::{zstd_compress, zstd_decompress};
1156
1157#[cfg(feature = "borsh")]
1158pub use optionals::borsh_impl;
1159#[cfg(feature = "borsh")]
1160pub use optionals::{Borsh, RBorshOps, borsh_from_raw, borsh_to_raw};
1161
1162#[cfg(feature = "bitflags")]
1163pub use bitflags;
1164#[cfg(feature = "bitflags")]
1165pub use optionals::bitflags_impl;
1166#[cfg(feature = "bitflags")]
1167pub use optionals::{Flags, RFlags};
1168
1169#[cfg(feature = "bitvec")]
1170pub use optionals::bitvec_impl;
1171#[cfg(feature = "bitvec")]
1172pub use optionals::{BitVec, Lsb0, Msb0, RBitVec};
1173
1174#[cfg(feature = "tabled")]
1175pub use optionals::tabled_impl;
1176#[cfg(feature = "tabled")]
1177pub use optionals::{
1178 Builder, Table, Tabled, builder_to_string, table_from_vecs, table_to_string,
1179 table_to_string_opts, table_to_string_styled,
1180};
1181
1182#[cfg(feature = "tinyvec")]
1183pub use optionals::tinyvec_impl;
1184#[cfg(feature = "tinyvec")]
1185pub use optionals::{Array, ArrayVec, TinyVec};
1186
1187#[cfg(feature = "arrow")]
1188pub use optionals::arrow_impl;
1189#[cfg(feature = "arrow")]
1190pub use optionals::{
1191 ArrayRef, ArrowArray, BooleanArray, DataType, Date32Array, DictionaryArray, Field,
1192 Float64Array, Int32Array, RecordBatch, Schema, StringArray, StringDictionaryArray,
1193 TimestampSecondArray, UInt8Array,
1194};
1195
1196#[cfg(feature = "datafusion")]
1197pub use optionals::RSessionContext;
1198#[cfg(feature = "datafusion")]
1199pub use optionals::datafusion_impl;
1200
1201/// N-dimensional R arrays with const generic dimension count.
1202pub mod rarray;
1203pub use rarray::{RArray, RArray3D, RMatrix, RVector};
1204
1205/// Direct R serialization via serde (no JSON intermediate).
1206///
1207/// Provides efficient type-preserving conversions between Rust types and native R objects:
1208/// - [`AsSerialize<T>`][serde::AsSerialize] - Wrapper for returning `Serialize` types from `#[miniextendr]` functions
1209/// - [`RSerializeNative`][serde::RSerializeNative] - Convert Rust → R (struct → named list)
1210/// - [`RDeserializeNative`][serde::RDeserializeNative] - Convert R → Rust (named list → struct)
1211///
1212/// Enable with `features = ["serde"]`.
1213///
1214/// See the [`serde`] module documentation for type mappings and examples.
1215#[cfg(feature = "serde")]
1216pub mod serde;
1217/// Re-export the upstream `serde` crate (aliased to avoid conflict with [`mod serde`]).
1218///
1219/// Downstream crates can use `miniextendr_api::serde_crate::{Serialize, Deserialize}`
1220/// and `#[serde(crate = "miniextendr_api::serde_crate")]` to avoid a direct `serde` dep.
1221#[cfg(feature = "serde")]
1222pub use ::serde as serde_crate;
1223
1224/// Integration with the `bytemuck` crate for POD type conversions.
1225///
1226/// Provides explicit, safe conversions between Rust POD (Plain Old Data) types
1227/// and R raw vectors:
1228/// - `Raw<T>` - Single POD value (headerless, native layout)
1229/// - `RawSlice<T>` - Sequence of POD values (headerless)
1230/// - `RawTagged<T>` / `RawSliceTagged<T>` - With header metadata
1231///
1232/// Enable with `features = ["raw_conversions"]`.
1233///
1234/// ```ignore
1235/// use bytemuck::{Pod, Zeroable};
1236/// use miniextendr_api::raw_conversions::{Raw, RawSlice};
1237///
1238/// #[derive(Copy, Clone, Pod, Zeroable)]
1239/// #[repr(C)]
1240/// struct Vec3 { x: f32, y: f32, z: f32 }
1241///
1242/// #[miniextendr]
1243/// fn encode(x: f64, y: f64, z: f64) -> Raw<Vec3> {
1244/// Raw(Vec3 { x: x as f32, y: y as f32, z: z as f32 })
1245/// }
1246/// ```
1247#[cfg(feature = "raw_conversions")]
1248pub mod raw_conversions;
1249#[cfg(feature = "raw_conversions")]
1250pub use raw_conversions::{
1251 Pod, Raw, RawError, RawHeader, RawSlice, RawSliceTagged, RawTagged, Zeroable, raw_from_bytes,
1252 raw_slice_from_bytes, raw_slice_to_bytes, raw_to_bytes,
1253};
1254
1255/// `match.arg`-style string conversion for enums.
1256///
1257/// Provides the [`MatchArg`] trait for converting Rust enums to/from R character
1258/// strings with partial matching, like R's `match.arg()`.
1259/// Use `#[derive(MatchArg)]` on C-style enums to auto-generate the implementation.
1260pub mod match_arg;
1261#[cfg(feature = "either")]
1262pub use match_arg::match_arg_either_or;
1263pub use match_arg::{
1264 MatchArg, MatchArgAlias, MatchArgError, choices_sexp, match_arg_from_sexp,
1265 match_arg_missing_or, match_arg_null_or, match_arg_option_from_sexp, match_arg_param,
1266 match_arg_param_with_default, match_arg_vec_from_sexp, match_arg_vec_into_sexp,
1267};
1268
1269/// Factor support for enum ↔ R factor conversions.
1270///
1271/// Provides the [`RFactor`] trait for converting Rust enums to/from R factors.
1272/// Use `#[derive(RFactor)]` on C-style enums to auto-generate the implementation.
1273///
1274/// # Example
1275///
1276/// ```ignore
1277/// use miniextendr_api::RFactor;
1278///
1279/// #[derive(Copy, Clone, RFactor)]
1280/// enum Color { Red, Green, Blue }
1281///
1282/// #[miniextendr]
1283/// fn color_name(c: Color) -> &'static str {
1284/// match c {
1285/// Color::Red => "red",
1286/// Color::Green => "green",
1287/// Color::Blue => "blue",
1288/// }
1289/// }
1290/// ```
1291pub mod factor;
1292pub use factor::{
1293 Factor, FactorMut, FactorOptionVec, FactorVec, RFactor, UnitEnumFactor, build_factor,
1294 build_levels_sexp, build_levels_sexp_cached, factor_from_sexp,
1295};
1296
1297/// Convenience re-exports for common miniextendr items.
1298///
1299/// A single `use miniextendr_api::prelude::*;` brings into scope the most
1300/// commonly used macros, traits, types, and helpers.
1301pub mod prelude;
1302// endregion