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 (`ffi`, `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//! - Worker-thread pattern for panic isolation and `Drop` safety (`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 the cdylib-based wrapper generator and committed into
35//! `R/miniextendr_wrappers.R` so CRAN builds do not require codegen.
36//!
37//! ## GC protection and ownership
38//!
39//! R's garbage collector can reclaim any SEXP that isn't protected. miniextendr
40//! provides three complementary protection mechanisms:
41//!
42//! | Strategy | Module | Lifetime | Release Order | Use Case |
43//! |----------|--------|----------|---------------|----------|
44//! | **PROTECT stack** | [`gc_protect`] | Within `.Call` | LIFO (stack) | Temporary allocations |
45//! | **Preserve list** | [`preserve`] | Across `.Call`s | Any order | Long-lived R objects |
46//! | **R ownership** | [`ExternalPtr`](struct@ExternalPtr) | Until R GCs | R decides | Rust data owned by R |
47//!
48//! Quick guide:
49//!
50//! **Temporary allocations during computation** -> [`ProtectScope`]
51//! ```ignore
52//! unsafe fn compute(x: SEXP) -> SEXP {
53//! let scope = ProtectScope::new();
54//! let temp = scope.protect(Rf_allocVector(REALSXP, 100));
55//! // ... work with temp ...
56//! result.into_raw()
57//! } // UNPROTECT(n) called automatically
58//! ```
59//!
60//! **R objects surviving across `.Call`s** -> [`preserve`]
61//! ```ignore
62//! // In RAllocator or similar long-lived context
63//! let cell = unsafe { preserve::insert(backing_vec) };
64//! // ... use across multiple .Calls ...
65//! unsafe { preserve::release(cell) };
66//! ```
67//!
68//! **Rust data owned by R** -> [`ExternalPtr`](struct@ExternalPtr)
69//! ```ignore
70//! #[miniextendr]
71//! fn create_model() -> ExternalPtr<MyModel> {
72//! ExternalPtr::new(MyModel::new())
73//! } // R owns it; Drop runs when R GCs
74//! ```
75//!
76//! Note: ALTREP trait methods receive raw SEXP pointers from R's runtime.
77//! These are safe to dereference because R guarantees valid SEXPs in ALTREP callbacks.
78//!
79//! ## Threading and safety
80//!
81//! R uses `longjmp` for errors, which can bypass Rust destructors. The default
82//! pattern is to run Rust logic on a worker thread and marshal R API calls back
83//! to the main R thread via `with_r_thread`. Most FFI wrappers are
84//! main-thread routed via `#[r_ffi_checked]`. Use unchecked variants only when
85//! you have arranged a safe context.
86//!
87//! With the `nonapi` feature, miniextendr can disable R's stack checking to allow
88//! calls from other threads. R is still not thread-safe; serialize all R API use.
89//!
90//! ## Feature Flags
91//!
92//! ### Core Features
93//!
94//! | Feature | Description |
95//! |---------|-------------|
96//! | `nonapi` | Non-API R symbols (stack controls, mutable `DATAPTR`). May break with R updates. |
97//! | `rayon` | Parallel iterators via Rayon. Adds `RParallelIterator`, `RParallelExtend`. |
98//! | `connections` | Experimental R connection framework. **Unstable R API.** |
99//! | `indicatif` | Progress bars via R console. Requires `nonapi`. |
100//! | `vctrs` | vctrs class construction (`new_vctr`, `new_rcrd`, `new_list_of`) and `#[derive(Vctrs)]`. |
101//! | `worker-thread` | Worker thread for panic isolation and `Drop` safety. Without it, stubs run inline. |
102//!
103//! ### Type Conversions (Scalars & Vectors)
104//!
105//! | Feature | Rust Type | R Type | Notes |
106//! |---------|-----------|--------|-------|
107//! | `either` | `Either<L, R>` | Tries L then R | Union-like dispatch |
108//! | `uuid` | `Uuid`, `Vec<Uuid>` | `character` | UUID ↔ string |
109//! | `regex` | `Regex` | `character(1)` | Compiles pattern from R |
110//! | `url` | `Url`, `Vec<Url>` | `character` | Validated URLs |
111//! | `time` | `OffsetDateTime`, `Date` | `POSIXct`, `Date` | Date/time conversions |
112//! | `ordered-float` | `OrderedFloat<f64>` | `numeric` | NaN-orderable floats |
113//! | `num-bigint` | `BigInt`, `BigUint` | `character` | Arbitrary precision via strings |
114//! | `rust_decimal` | `Decimal` | `character` | Fixed-point decimals |
115//! | `num-complex` | `Complex<f64>` | `complex` | Native R complex support |
116//! | `indexmap` | `IndexMap<String, T>` | named `list` | Preserves insertion order |
117//! | `bitflags` | `RFlags<T>` | `integer` | Bitflags ↔ integer |
118//! | `bitvec` | `RBitVec` | `logical` | Bit vectors ↔ logical |
119//! | `tinyvec` | `TinyVec<[T; N]>`, `ArrayVec<[T; N]>` | vectors | Small-vector optimization |
120//!
121//! ### Matrix & Array Libraries
122//!
123//! | Feature | Types | Conversions |
124//! |---------|-------|-------------|
125//! | `ndarray` | `Array1`–`Array6`, `ArrayD`, views | R vectors/matrices ↔ ndarray |
126//! | `nalgebra` | `DVector`, `DMatrix` | R vectors/matrices ↔ nalgebra |
127//!
128//! ### Serialization
129//!
130//! | Feature | Traits/Modules | Description |
131//! |---------|----------------|-------------|
132//! | `serde` | `RSerializeNative`, `RDeserializeNative` | Direct Rust ↔ R native serialization |
133//! | `serde_json` | `RSerialize`, `RDeserialize` | JSON string serialization (includes `serde`) |
134//! | `borsh` | `Borsh<T>` | Binary serialization ↔ raw vectors via Borsh |
135//!
136//! ### Adapter Traits (Generic Operations)
137//!
138//! | Feature | Traits | Use Case |
139//! |---------|--------|----------|
140//! | `num-traits` | `RNum`, `RSigned`, `RFloat` | Generic numeric operations |
141//! | `bytes` | `RBuf`, `RBufMut` | Byte buffer operations |
142//!
143//! ### Text & Data Processing
144//!
145//! | Feature | Types/Functions | Description |
146//! |---------|-----------------|-------------|
147//! | `aho-corasick` | `AhoCorasick`, `aho_compile` | Fast multi-pattern string search |
148//! | `toml` | `TomlValue`, `toml_from_str` | TOML parsing and serialization |
149//! | `tabled` | `table_to_string` | ASCII/Unicode table formatting |
150//! | `sha2` | `sha256_str`, `sha512_bytes` | Cryptographic hashing |
151//!
152//! ### Random Number Generation
153//!
154//! | Feature | Types | Description |
155//! |---------|-------|-------------|
156//! | `rand` | `RRng`, `RDistributions` | Wraps R's RNG with `rand` traits |
157//! | `rand_distr` | Re-exports `rand_distr` | Additional distributions (Normal, Exp, etc.) |
158//!
159//! ### Binary Data
160//!
161//! | Feature | Types | Description |
162//! |---------|-------|-------------|
163//! | `raw_conversions` | `Raw<T>`, `RawSlice<T>` | POD types ↔ raw vectors via bytemuck |
164//!
165//! ### Project-wide Defaults (mutually exclusive where noted)
166//!
167//! | Feature | Description |
168//! |---------|-------------|
169//! | `default-r6` | Default class system: R6 (mutually exclusive with `default-s7`) |
170//! | `default-s7` | Default class system: S7 (mutually exclusive with `default-r6`) |
171//! | `default-worker` | Default to worker thread dispatch (implies `worker-thread`) |
172//! | `default-strict` | Default to strict mode for lossy integer conversions |
173//! | `default-coerce` | Default to coerce mode for type conversions |
174//!
175//! ### Development / Diagnostics
176//!
177//! | Feature | Description |
178//! |---------|-------------|
179//! | `doc-lint` | Warn on roxygen doc comment mismatches (enabled by default) |
180//! | `macro-coverage` | Expose macro coverage test module for `cargo expand` auditing |
181//! | `debug-preserve` | Enable `preserve::count()` diagnostic helpers (tests/benchmarks only) |
182//! | `growth-debug` | Track and report collection growth events (zero-cost when off) |
183//! | `refcount-fast-hash` | Use ahash for refcount arenas (enabled by default, not DOS-resistant) |
184// Re-export linkme for use by generated code (distributed_slice entries)
185#[doc(hidden)]
186pub use linkme;
187
188// Procedural macros (re-exported from miniextendr-macros)
189#[doc(hidden)]
190pub use miniextendr_macros::__mx_trait_impl_expand;
191#[doc(inline)]
192pub use miniextendr_macros::ExternalPtr;
193#[doc(inline)]
194pub use miniextendr_macros::RNativeType;
195#[doc(inline)]
196pub use miniextendr_macros::impl_typed_external;
197#[doc(inline)]
198pub use miniextendr_macros::list;
199#[doc(inline)]
200pub use miniextendr_macros::miniextendr;
201#[doc(inline)]
202pub use miniextendr_macros::miniextendr_init;
203#[doc(inline)]
204pub use miniextendr_macros::r_ffi_checked;
205#[doc(inline)]
206pub use miniextendr_macros::typed_list;
207// Note: RFactor derive macro is re-exported - it shares the name with the RFactor trait
208// but they're in different namespaces (derive macros vs types/traits)
209#[cfg(feature = "vctrs")]
210#[doc(inline)]
211pub use miniextendr_macros::Vctrs;
212// Note: MatchArg derive macro is re-exported - it shares the name with the MatchArg trait
213// but they're in different namespaces (derive macros vs types/traits), same as RFactor.
214#[doc(inline)]
215pub use miniextendr_macros::{
216 Altrep, AltrepComplex, AltrepInteger, AltrepList, AltrepLogical, AltrepRaw, AltrepReal,
217 AltrepString, DataFrameRow, IntoList, MatchArg, PreferDataFrame, PreferExternalPtr, PreferList,
218 PreferRNativeType, RFactor, TryFromList,
219};
220
221pub mod altrep;
222pub mod altrep_bridge;
223pub mod altrep_data;
224pub mod altrep_ext;
225pub mod altrep_impl;
226pub mod altrep_sexp;
227pub mod altrep_traits;
228
229// Re-export for backward compatibility - RegisterAltrep was moved from altrep_registration to altrep
230#[doc(hidden)]
231pub mod altrep_registration {
232 pub use crate::altrep::RegisterAltrep;
233}
234/// Raw R FFI bindings and low-level SEXP utilities.
235///
236/// Most users should prefer safe wrappers from higher-level modules.
237pub mod ffi;
238
239/// Automatic registration internals.
240///
241/// Items annotated with `#[miniextendr]` self-register at link time.
242/// The C entrypoint calls [`registry::miniextendr_register_routines`] to
243/// finalize registration with R. Users don't interact with this module.
244pub mod registry;
245
246// Re-export high-level ALTREP data traits
247pub use altrep_data::{
248 AltComplexData,
249 AltIntegerData,
250 AltListData,
251 AltLogicalData,
252 AltRawData,
253 AltRealData,
254 AltStringData,
255 AltrepDataptr,
256 AltrepExtract,
257 AltrepLen,
258 // Iterator-backed ALTREP types (R-native)
259 IterComplexData,
260 // Iterator-backed ALTREP types (with Coerce support)
261 IterIntCoerceData,
262 IterIntData,
263 IterIntFromBoolData,
264 IterListData,
265 IterLogicalData,
266 IterRawData,
267 IterRealCoerceData,
268 IterRealData,
269 IterState,
270 IterStringData,
271 Logical,
272 Sortedness,
273 // Sparse iterator-backed ALTREP types (compute-on-access)
274 SparseIterComplexData,
275 SparseIterIntData,
276 SparseIterLogicalData,
277 SparseIterRawData,
278 SparseIterRealData,
279 SparseIterState,
280 // Streaming ALTREP types (chunk-cached reader closures)
281 StreamingIntData,
282 StreamingRealData,
283 // Windowed iterator-backed ALTREP types
284 WindowedIterIntData,
285 WindowedIterRealData,
286 WindowedIterState,
287};
288// Re-export RBase enum, AltrepGuard, and AltrepSexp
289pub use altrep::RBase;
290pub use altrep_sexp::{AltrepSexp, ensure_materialized};
291pub use altrep_traits::AltrepGuard;
292
293// ALTREP package name global - set by C entrypoint before ALTREP registration
294// This is a pointer to a null-terminated C string provided by C code.
295// Default: c"unknown" for safety if not set.
296use std::sync::atomic::{AtomicPtr, Ordering};
297static ALTREP_PKG_NAME_PTR: AtomicPtr<std::ffi::c_char> =
298 AtomicPtr::new(c"unknown".as_ptr().cast_mut());
299
300/// Returns the current ALTREP package name as a C string pointer.
301/// This is set by the C entrypoint before ALTREP registration.
302#[doc(hidden)]
303pub struct AltrepPkgName;
304
305impl AltrepPkgName {
306 /// Get the package name pointer.
307 #[inline]
308 pub fn as_ptr() -> *const std::ffi::c_char {
309 ALTREP_PKG_NAME_PTR.load(Ordering::Acquire)
310 }
311}
312
313/// Opaque handle for ALTREP package name.
314/// Use `ALTREP_PKG_NAME.as_ptr()` to get the C string pointer.
315#[doc(hidden)]
316pub static ALTREP_PKG_NAME: AltrepPkgName = AltrepPkgName;
317
318/// Set the ALTREP package name. Called from C entrypoint.
319/// # Safety
320/// The provided pointer must point to a valid null-terminated C string
321/// that lives for the duration of the R session.
322#[doc(hidden)]
323#[unsafe(no_mangle)]
324pub unsafe extern "C" fn miniextendr_set_altrep_pkg_name(name: *const std::ffi::c_char) {
325 let name = if name.is_null() {
326 c"unknown".as_ptr()
327 } else {
328 name
329 };
330 ALTREP_PKG_NAME_PTR.store(name.cast_mut(), Ordering::Release);
331}
332
333// DllInfo global — stored during package_init, used by ALTREP class registration.
334// R needs DllInfo to associate ALTREP classes with their package for serialization.
335// Without it, readRDS in a fresh session can't find the class.
336static ALTREP_DLL_INFO: AtomicPtr<std::ffi::c_void> = AtomicPtr::new(std::ptr::null_mut());
337
338/// Get the stored DllInfo pointer for ALTREP class registration.
339#[doc(hidden)]
340pub fn altrep_dll_info() -> *mut ffi::DllInfo {
341 ALTREP_DLL_INFO.load(Ordering::Acquire).cast()
342}
343
344/// Store the DllInfo pointer during package init.
345#[doc(hidden)]
346pub fn set_altrep_dll_info(dll: *mut ffi::DllInfo) {
347 ALTREP_DLL_INFO.store(dll.cast(), Ordering::Release);
348}
349
350// Note: SexpExt is pub(crate), imported directly in modules that need it
351pub mod from_r;
352pub mod into_r;
353pub mod into_r_error;
354pub use into_r::{Altrep, IntoR, IntoRAltrep};
355pub use into_r_error::IntoRError;
356pub mod into_r_as;
357pub use into_r_as::{IntoRAs, StorageCoerceError};
358pub mod unwind_protect;
359pub mod worker;
360
361// Re-export commonly used worker items at root for convenience
362pub use worker::{Sendable, is_r_main_thread, with_r_thread};
363
364// Required exports for generated code and initialization
365pub use worker::miniextendr_runtime_init;
366
367// Thread safety utilities for calling R from non-main threads
368pub mod thread;
369
370// Collection growth debug instrumentation (diagnostics)
371#[cfg(feature = "growth-debug")]
372pub mod growth_debug;
373
374/// Track a collection growth (reallocation) event.
375///
376/// When the `growth-debug` feature is enabled, increments a thread-local counter
377/// for the named collection. When disabled, compiles to a no-op.
378///
379/// # Example
380///
381/// ```ignore
382/// let old_cap = vec.capacity();
383/// vec.push(item);
384/// if vec.capacity() != old_cap {
385/// track_growth!("my_vec");
386/// }
387/// ```
388#[cfg(feature = "growth-debug")]
389#[macro_export]
390macro_rules! track_growth {
391 ($name:expr) => {
392 $crate::growth_debug::record_growth($name)
393 };
394}
395
396/// Track a collection growth (reallocation) event.
397///
398/// No-op when `growth-debug` feature is disabled.
399#[cfg(not(feature = "growth-debug"))]
400#[macro_export]
401macro_rules! track_growth {
402 ($name:expr) => {};
403}
404
405/// Print and reset all growth counters.
406///
407/// When the `growth-debug` feature is enabled, prints all tracked growth events
408/// to stderr and resets the counters. When disabled, compiles to a no-op.
409#[cfg(feature = "growth-debug")]
410#[macro_export]
411macro_rules! report_growth {
412 () => {
413 $crate::growth_debug::report_and_reset()
414 };
415}
416
417/// Print and reset all growth counters.
418///
419/// No-op when `growth-debug` feature is disabled.
420#[cfg(not(feature = "growth-debug"))]
421#[macro_export]
422macro_rules! report_growth {
423 () => {};
424}
425
426// `indicatif` progress integration (R console)
427#[cfg(feature = "indicatif")]
428pub mod progress;
429#[cfg(feature = "indicatif")]
430pub use indicatif;
431
432// Stack size constants and builder (always available)
433#[cfg(windows)]
434pub use thread::WINDOWS_R_STACK_SIZE;
435pub use thread::{DEFAULT_R_STACK_SIZE, RThreadBuilder};
436
437// Stack checking control (requires nonapi feature)
438#[cfg(feature = "nonapi")]
439pub use thread::{StackCheckGuard, scope_with_r, spawn_with_r, with_stack_checking_disabled};
440
441// Panic telemetry hook for structured panic→R-error diagnostics
442pub mod panic_telemetry;
443
444// Unified FFI guard for catching panics at Rust-R boundaries
445pub mod ffi_guard;
446pub use ffi_guard::{GuardMode, guarded_ffi_call, guarded_ffi_call_with_fallback};
447
448// Runtime wrapper for R data.frame objects
449pub mod dataframe;
450pub use dataframe::{DataFrameError, DataFrameView};
451
452// Strict conversion helpers for #[miniextendr(strict)]
453pub mod strict;
454
455// Cached R class attribute SEXPs (POSIXct, Date, data.frame, etc.)
456pub mod cached_class;
457
458// Error value transport for #[miniextendr(error_in_r)]
459pub mod error_value;
460
461// Error handling helpers (r_warning, r_print!, r_println! macros)
462pub mod error;
463pub use error::r_warning;
464
465// RNG (random number generation) utilities
466pub mod rng;
467pub use rng::{RngGuard, with_rng};
468
469// Re-export from_r
470pub use from_r::{SexpError, SexpLengthError, SexpNaError, SexpTypeError, TryFromSexp};
471
472// Encoding / locale probing (mainly for debugging; some parts require `nonapi`)
473// NOTE: Disabled because it references non-exported symbols from R's Defn.h
474// (e.g., known_to_be_utf8, utf8locale) that cause dlopen failures at runtime.
475// #[cfg(feature = "nonapi")]
476pub mod encoding;
477
478// Expression evaluation helpers (RSymbol, RCall, REnv)
479pub mod expression;
480pub use expression::{RCall, REnv, RSymbol};
481
482// S4 slot access and class checking helpers
483pub mod s4_helpers;
484
485// Note: RNativeType is pub(crate), imported directly in modules that need it
486
487pub mod backtrace;
488
489pub mod coerce;
490pub use coerce::{Coerce, CoerceError, Coerced, TryCoerce};
491
492/// Traits for R's `as.<class>()` coercion functions.
493///
494/// This module provides traits for implementing R's generic coercion methods
495/// (`as.data.frame()`, `as.list()`, `as.character()`, etc.) for Rust types
496/// wrapped in [`ExternalPtr`](struct@ExternalPtr).
497///
498/// See the [`as_coerce`] module documentation for usage examples.
499pub mod as_coerce;
500pub use as_coerce::{
501 // Core coercion traits
502 AsCharacter,
503 // Error type
504 AsCoerceError,
505 AsComplex,
506 AsDataFrame,
507 AsDate,
508 AsEnvironment,
509 AsFactor,
510 AsFunction,
511 AsInteger,
512 AsList as AsListCoerce,
513 AsLogical,
514 AsMatrix,
515 AsNumeric,
516 AsPOSIXct,
517 AsRaw,
518 AsVector,
519 // Helpers
520 SUPPORTED_AS_GENERICS,
521 is_supported_as_generic,
522};
523
524pub mod condition;
525pub mod convert;
526/// Support for R `...` arguments represented as a validated list.
527pub mod dots;
528pub mod list;
529pub mod missing;
530pub mod named_vector;
531pub mod strvec;
532pub mod typed_list;
533pub use convert::{
534 AsDisplay, AsDisplayVec, AsExternalPtr, AsExternalPtrExt, AsFromStr, AsFromStrVec, AsList,
535 AsListExt, AsNamedList, AsNamedListExt, AsNamedVector, AsNamedVectorExt, AsRNative,
536 AsRNativeExt, Collect, CollectNA, CollectNAInt, CollectStrings, DataFrame, IntoDataFrame,
537 ToDataFrame, ToDataFrameExt,
538};
539#[cfg(feature = "serde")]
540pub use convert::{AsSerializeRow, SerializeDataFrame};
541pub use into_r::Lazy;
542pub use list::{
543 IntoList, List, ListAccumulator, ListBuilder, ListMut, NamedList, TryFromList, collect_list,
544};
545pub use missing::{Missing, is_missing_arg};
546pub use named_vector::{AtomicElement, NamedVector};
547pub use strvec::{
548 ProtectedStrVec, ProtectedStrVecCowIter, ProtectedStrVecIter, StrVec, StrVecBuilder,
549 StrVecCowIter, StrVecIter,
550};
551pub use typed_list::{
552 TypeSpec, TypedEntry, TypedList, TypedListError, TypedListSpec, actual_type_string,
553 sexptype_name, validate_list,
554};
555
556// External pointer module - Box-like owned pointer wrapping R's EXTPTRSXP
557pub mod externalptr;
558
559// Connection framework (unstable R API - use with caution)
560#[cfg(feature = "connections")]
561pub mod connection;
562pub use externalptr::{
563 ErasedExternalPtr,
564 ExternalPtr,
565 ExternalSlice,
566 IntoExternalPtr,
567 TypedExternal,
568 // ALTREP helpers (checked)
569 altrep_data1_as,
570 // ALTREP helpers (unchecked - for performance-critical callbacks)
571 altrep_data1_as_unchecked,
572 altrep_data1_mut,
573 altrep_data1_mut_unchecked,
574 altrep_data2_as,
575 altrep_data2_as_unchecked,
576};
577
578// TypedExternal implementations for std types
579pub mod externalptr_std;
580
581// Deprecated: DLL preserve list. Use ProtectPool or R_PreserveObject instead.
582// Kept for benchmark comparisons.
583pub mod preserve;
584
585// GC protection toolkit (PROTECT stack RAII wrappers)
586pub mod gc_protect;
587pub use gc_protect::{OwnedProtect, ProtectIndex, ProtectScope, Protector, ReprotectSlot, Root};
588
589// VECSXP pool with generational keys (slotmap-backed)
590pub mod protect_pool;
591pub use protect_pool::{ProtectKey, ProtectPool};
592
593// Reference-counted GC protection (BTreeMap + VECSXP backing)
594pub mod refcount_protect;
595pub use refcount_protect::{
596 Arena, ArenaGuard, HashMapArena, MapStorage, RefCountedArena, RefCountedGuard,
597 ThreadLocalArena, ThreadLocalArenaOps, ThreadLocalHashArena,
598};
599
600pub mod allocator;
601pub use allocator::RAllocator;
602
603pub mod r_memory;
604
605// region: Trait ABI Support
606//
607// Cross-package trait dispatch using a stable C ABI.
608// See `trait_abi` module docs for details.
609
610/// ABI types for cross-package trait dispatch.
611///
612/// This module defines the stable, C-compatible types used for runtime trait
613/// dispatch across R package boundaries.
614pub mod abi;
615
616/// C-callable mx_abi functions (mx_wrap, mx_get, mx_query, mx_abi_register).
617///
618/// These are registered via `R_RegisterCCallable` during package init and
619/// loaded by consumer packages via `R_GetCCallable`.
620pub mod mx_abi;
621
622/// Package initialization (`miniextendr_init!` support).
623///
624/// Consolidates all init steps into [`init::package_init`].
625pub mod init;
626
627/// Runtime support for trait ABI operations.
628///
629/// Provides C-callable loading and type conversion helpers for trait ABI support.
630pub mod trait_abi;
631
632/// vctrs class construction and trait support.
633///
634/// Provides helpers for building vctrs-compatible R objects and traits
635/// for describing vctrs class metadata from Rust types.
636///
637/// Enable with `features = ["vctrs"]`.
638#[cfg(feature = "vctrs")]
639pub mod vctrs;
640#[cfg(feature = "vctrs")]
641pub use vctrs::{
642 IntoVctrs, VctrsBuildError, VctrsClass, VctrsKind, VctrsListOf, VctrsRecord, new_list_of,
643 new_rcrd, new_vctr,
644};
645
646// Re-export key ABI types at crate root for convenience
647pub use abi::{mx_base_vtable, mx_erased, mx_meth, mx_tag};
648pub use trait_abi::TraitView;
649// endregion
650
651// region: Marker Traits
652//
653// Marker traits for types derived with proc-macros.
654// These enable compile-time identification and blanket implementations.
655
656/// Marker traits for proc-macro derived types.
657pub mod markers;
658pub use markers::{PrefersDataFrame, PrefersExternalPtr, PrefersList, PrefersRNativeType};
659// endregion
660
661// region: Adapter Traits
662//
663// Built-in adapter traits with blanket implementations for standard library traits.
664// These allow any Rust type implementing Debug, Display, Hash, Ord, etc. to be
665// exposed to R without boilerplate.
666
667/// Built-in adapter traits for std library traits.
668///
669/// Provides [`RDebug`], [`RDisplay`], [`RHash`], [`ROrd`], [`RPartialOrd`],
670/// [`RError`], [`RFromStr`], [`RClone`], [`RCopy`], [`RDefault`], [`RIterator`],
671/// [`RExtend`], and [`RFromIter`] with blanket implementations where possible.
672/// See module docs for usage.
673///
674/// [`RDebug`]: adapter_traits::RDebug
675/// [`RDisplay`]: adapter_traits::RDisplay
676/// [`RHash`]: adapter_traits::RHash
677/// [`ROrd`]: adapter_traits::ROrd
678/// [`RPartialOrd`]: adapter_traits::RPartialOrd
679/// [`RError`]: adapter_traits::RError
680/// [`RFromStr`]: adapter_traits::RFromStr
681/// [`RClone`]: adapter_traits::RClone
682/// [`RCopy`]: adapter_traits::RCopy
683/// [`RDefault`]: adapter_traits::RDefault
684/// [`RIterator`]: adapter_traits::RIterator
685/// [`RExtend`]: adapter_traits::RExtend
686/// [`RFromIter`]: adapter_traits::RFromIter
687pub mod adapter_traits;
688pub use adapter_traits::{
689 RClone, RCopy, RDebug, RDefault, RDisplay, RError, RExtend, RFromIter, RFromStr, RHash,
690 RIterator, RMakeIter, ROrd, RPartialOrd, RToVec,
691};
692
693/// This is used to ensure the macros of `miniextendr-macros` treat this crate as a "user crate"
694/// atleast in the `macro_coverage`
695#[doc(hidden)]
696extern crate self as miniextendr_api;
697
698#[cfg(feature = "macro-coverage")]
699#[doc(hidden)]
700pub mod macro_coverage;
701// endregion
702
703// region: Optional integrations with external crates (feature-gated)
704//
705// All optional feature integrations are organized in the `optionals` module.
706// Types are re-exported at crate root for backwards compatibility.
707
708/// Optional feature integrations with third-party crates.
709///
710/// This module contains all feature-gated integrations with external crates.
711/// Each submodule is only compiled when its corresponding feature is enabled.
712/// See the [module documentation][optionals] for a complete list of available features.
713pub mod optionals;
714
715// Re-export optional types at crate root for backwards compatibility
716#[cfg(feature = "rayon")]
717pub use optionals::rayon_bridge;
718#[cfg(feature = "rayon")]
719pub use optionals::{RParallelExtend, RParallelIterator};
720
721#[cfg(feature = "rand_distr")]
722pub use optionals::rand_distr;
723#[cfg(feature = "rand")]
724pub use optionals::rand_impl;
725#[cfg(feature = "rand")]
726pub use optionals::{RDistributionOps, RDistributions, RRng, RRngOps};
727
728#[cfg(feature = "either")]
729pub use optionals::either_impl;
730#[cfg(feature = "either")]
731pub use optionals::{Either, Left, Right};
732
733#[cfg(feature = "ndarray")]
734pub use optionals::ndarray_impl;
735#[cfg(feature = "ndarray")]
736pub use optionals::{
737 ArcArray1, ArcArray2, Array0, Array1, Array2, Array3, Array4, Array5, Array6, ArrayD,
738 ArrayView0, ArrayView1, ArrayView2, ArrayView3, ArrayView4, ArrayView5, ArrayView6, ArrayViewD,
739 ArrayViewMut0, ArrayViewMut1, ArrayViewMut2, ArrayViewMut3, ArrayViewMut4, ArrayViewMut5,
740 ArrayViewMut6, ArrayViewMutD, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, RNdArrayOps, RNdIndex,
741 RNdSlice, RNdSlice2D, ShapeBuilder,
742};
743
744#[cfg(feature = "nalgebra")]
745pub use optionals::nalgebra_impl;
746#[cfg(feature = "nalgebra")]
747pub use optionals::{DMatrix, DVector, RMatrixOps, RVectorOps, SMatrix, SVector};
748
749#[cfg(feature = "num-bigint")]
750pub use optionals::num_bigint_impl;
751#[cfg(feature = "num-bigint")]
752pub use optionals::{BigInt, BigUint, RBigIntBitOps, RBigIntOps, RBigUintBitOps, RBigUintOps};
753
754#[cfg(feature = "rust_decimal")]
755pub use optionals::rust_decimal_impl;
756#[cfg(feature = "rust_decimal")]
757pub use optionals::{Decimal, RDecimalOps};
758
759#[cfg(feature = "ordered-float")]
760pub use optionals::ordered_float_impl;
761#[cfg(feature = "ordered-float")]
762pub use optionals::{OrderedFloat, ROrderedFloatOps};
763
764#[cfg(feature = "num-complex")]
765pub use optionals::num_complex_impl;
766#[cfg(feature = "num-complex")]
767pub use optionals::{Complex, RComplexOps};
768
769#[cfg(feature = "num-traits")]
770pub use optionals::num_traits_impl;
771#[cfg(feature = "num-traits")]
772pub use optionals::{RFloat, RNum, RSigned};
773
774#[cfg(feature = "uuid")]
775pub use optionals::uuid_impl;
776#[cfg(feature = "uuid")]
777pub use optionals::{RUuidOps, Uuid, uuid_helpers};
778
779#[cfg(feature = "regex")]
780pub use optionals::regex_impl;
781#[cfg(feature = "regex")]
782pub use optionals::{CaptureGroups, RCaptureGroups, RRegexOps, Regex};
783
784#[cfg(feature = "url")]
785pub use optionals::url_impl;
786#[cfg(feature = "url")]
787pub use optionals::{RUrlOps, Url, url_helpers};
788
789#[cfg(feature = "aho-corasick")]
790pub use optionals::aho_corasick_impl;
791#[cfg(feature = "aho-corasick")]
792pub use optionals::{
793 AhoCorasick, RAhoCorasickOps, aho_compile, aho_count_matches, aho_find_all, aho_find_all_flat,
794 aho_find_first, aho_is_match, aho_replace_all,
795};
796
797#[cfg(feature = "indexmap")]
798pub use optionals::indexmap_impl;
799#[cfg(feature = "indexmap")]
800pub use optionals::{IndexMap, RIndexMapOps};
801
802#[cfg(feature = "time")]
803pub use optionals::time_impl;
804#[cfg(feature = "time")]
805pub use optionals::{Date, Duration, OffsetDateTime, RDateTimeFormat, RDuration};
806#[cfg(feature = "time")]
807pub use time;
808
809#[cfg(feature = "serde_json")]
810pub use optionals::serde_impl;
811#[cfg(feature = "toml")]
812pub use optionals::toml_impl;
813#[cfg(feature = "serde_json")]
814pub use optionals::{
815 FactorHandling, JsonOptions, JsonValue, NaHandling, RDeserialize, RJsonBridge, RJsonValueOps,
816 RSerialize, SpecialFloatHandling, json_from_sexp, json_from_sexp_permissive,
817 json_from_sexp_strict, json_from_sexp_with, json_into_sexp,
818};
819#[cfg(feature = "toml")]
820pub use optionals::{RTomlOps, TomlValue, toml_from_str, toml_to_string, toml_to_string_pretty};
821
822#[cfg(feature = "bytes")]
823pub use optionals::bytes_impl;
824#[cfg(feature = "bytes")]
825pub use optionals::{Buf, BufMut, Bytes, BytesMut, RBuf, RBufMut};
826
827#[cfg(feature = "sha2")]
828pub use optionals::sha2_impl;
829#[cfg(feature = "sha2")]
830pub use optionals::{sha256_bytes, sha256_str, sha512_bytes, sha512_str};
831
832#[cfg(feature = "borsh")]
833pub use optionals::borsh_impl;
834#[cfg(feature = "borsh")]
835pub use optionals::{Borsh, RBorshOps, borsh_from_raw, borsh_to_raw};
836
837#[cfg(feature = "bitflags")]
838pub use bitflags;
839#[cfg(feature = "bitflags")]
840pub use optionals::bitflags_impl;
841#[cfg(feature = "bitflags")]
842pub use optionals::{Flags, RFlags};
843
844#[cfg(feature = "bitvec")]
845pub use optionals::bitvec_impl;
846#[cfg(feature = "bitvec")]
847pub use optionals::{BitVec, Lsb0, Msb0, RBitVec};
848
849#[cfg(feature = "tabled")]
850pub use optionals::tabled_impl;
851#[cfg(feature = "tabled")]
852pub use optionals::{
853 Builder, Table, Tabled, builder_to_string, table_from_vecs, table_to_string,
854 table_to_string_opts, table_to_string_styled,
855};
856
857#[cfg(feature = "tinyvec")]
858pub use optionals::tinyvec_impl;
859#[cfg(feature = "tinyvec")]
860pub use optionals::{Array, ArrayVec, TinyVec};
861
862#[cfg(feature = "arrow")]
863pub use optionals::arrow_impl;
864#[cfg(feature = "arrow")]
865pub use optionals::{
866 ArrayRef, ArrowArray, BooleanArray, DataType, Date32Array, DictionaryArray, Field,
867 Float64Array, Int32Array, RecordBatch, Schema, StringArray, StringDictionaryArray,
868 TimestampSecondArray, UInt8Array,
869};
870
871#[cfg(feature = "datafusion")]
872pub use optionals::RSessionContext;
873#[cfg(feature = "datafusion")]
874pub use optionals::datafusion_impl;
875
876/// N-dimensional R arrays with const generic dimension count.
877pub mod rarray;
878pub use rarray::{RArray, RArray3D, RMatrix, RVector};
879
880/// Direct R serialization via serde (no JSON intermediate).
881///
882/// Provides efficient type-preserving conversions between Rust types and native R objects:
883/// - [`AsSerialize<T>`][serde::AsSerialize] - Wrapper for returning `Serialize` types from `#[miniextendr]` functions
884/// - [`RSerializeNative`][serde::RSerializeNative] - Convert Rust → R (struct → named list)
885/// - [`RDeserializeNative`][serde::RDeserializeNative] - Convert R → Rust (named list → struct)
886///
887/// Enable with `features = ["serde"]`.
888///
889/// See the [`serde`] module documentation for type mappings and examples.
890#[cfg(feature = "serde")]
891pub mod serde;
892/// Re-export the upstream `serde` crate (aliased to avoid conflict with [`mod serde`]).
893///
894/// Downstream crates can use `miniextendr_api::serde_crate::{Serialize, Deserialize}`
895/// and `#[serde(crate = "miniextendr_api::serde_crate")]` to avoid a direct `serde` dep.
896#[cfg(feature = "serde")]
897pub use ::serde as serde_crate;
898
899/// Integration with the `bytemuck` crate for POD type conversions.
900///
901/// Provides explicit, safe conversions between Rust POD (Plain Old Data) types
902/// and R raw vectors:
903/// - `Raw<T>` - Single POD value (headerless, native layout)
904/// - `RawSlice<T>` - Sequence of POD values (headerless)
905/// - `RawTagged<T>` / `RawSliceTagged<T>` - With header metadata
906///
907/// Enable with `features = ["raw_conversions"]`.
908///
909/// ```ignore
910/// use bytemuck::{Pod, Zeroable};
911/// use miniextendr_api::raw_conversions::{Raw, RawSlice};
912///
913/// #[derive(Copy, Clone, Pod, Zeroable)]
914/// #[repr(C)]
915/// struct Vec3 { x: f32, y: f32, z: f32 }
916///
917/// #[miniextendr]
918/// fn encode(x: f64, y: f64, z: f64) -> Raw<Vec3> {
919/// Raw(Vec3 { x: x as f32, y: y as f32, z: z as f32 })
920/// }
921/// ```
922#[cfg(feature = "raw_conversions")]
923pub mod raw_conversions;
924#[cfg(feature = "raw_conversions")]
925pub use raw_conversions::{
926 Pod, Raw, RawError, RawHeader, RawSlice, RawSliceTagged, RawTagged, Zeroable, raw_from_bytes,
927 raw_slice_from_bytes, raw_slice_to_bytes, raw_to_bytes,
928};
929
930/// `match.arg`-style string conversion for enums.
931///
932/// Provides the [`MatchArg`] trait for converting Rust enums to/from R character
933/// strings with partial matching, like R's `match.arg()`.
934/// Use `#[derive(MatchArg)]` on C-style enums to auto-generate the implementation.
935pub mod match_arg;
936pub use match_arg::{MatchArg, MatchArgError, choices_sexp, match_arg_from_sexp};
937
938/// Factor support for enum ↔ R factor conversions.
939///
940/// Provides the [`RFactor`] trait for converting Rust enums to/from R factors.
941/// Use `#[derive(RFactor)]` on C-style enums to auto-generate the implementation.
942///
943/// # Example
944///
945/// ```ignore
946/// use miniextendr_api::RFactor;
947///
948/// #[derive(Copy, Clone, RFactor)]
949/// enum Color { Red, Green, Blue }
950///
951/// #[miniextendr]
952/// fn color_name(c: Color) -> &'static str {
953/// match c {
954/// Color::Red => "red",
955/// Color::Green => "green",
956/// Color::Blue => "blue",
957/// }
958/// }
959/// ```
960pub mod factor;
961pub use factor::{
962 Factor, FactorMut, FactorOptionVec, FactorVec, RFactor, build_factor, build_levels_sexp,
963 build_levels_sexp_cached, factor_from_sexp,
964};
965
966/// Convenience re-exports for common miniextendr items.
967///
968/// A single `use miniextendr_api::prelude::*;` brings into scope the most
969/// commonly used macros, traits, types, and helpers.
970pub mod prelude;
971// endregion