Skip to main content

extendr_ffi/
lib.rs

1//! Low level bindings to R's C API
2//!
3//! `extendr-ffi` powers the `extendr-api` library.
4#![allow(non_upper_case_globals)]
5#![allow(non_camel_case_types)]
6#![allow(non_snake_case)]
7#![allow(improper_ctypes)]
8
9pub mod altrep;
10pub use altrep::*;
11mod symbols;
12pub use symbols::*;
13pub mod backports;
14pub use backports::*;
15
16#[cfg(feature = "non-api")]
17mod non_api;
18#[cfg(feature = "non-api")]
19pub use non_api::*;
20
21#[non_exhaustive]
22#[repr(transparent)]
23#[derive(Debug)]
24pub struct SEXPREC(std::ffi::c_void);
25
26extern "C" {
27    /// Returns the [SEXPTYPE] of `x`
28    pub fn TYPEOF(x: SEXP) -> SEXPTYPE;
29}
30
31#[repr(u32)]
32#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
33/// A C type with enumeration constants FALSE and TRUE defined.
34pub enum Rboolean {
35    #[doc = ", MAYBE"]
36    FALSE = 0,
37    #[doc = ", MAYBE"]
38    TRUE = 1,
39}
40
41#[doc = "These are very similar to those in Rdynpriv.h,\nbut we maintain them separately to give us more freedom to do\nsome computations on the internal versions that are derived from\nthese definitions."]
42#[repr(C)]
43#[derive(Debug, Copy, Clone)]
44pub struct R_CMethodDef {
45    pub name: *const ::std::os::raw::c_char,
46    pub fun: DL_FUNC,
47    pub numArgs: ::std::os::raw::c_int,
48    pub types: *mut R_NativePrimitiveArgType,
49}
50pub type R_NativePrimitiveArgType = ::std::os::raw::c_uint;
51pub type R_ExternalMethodDef = R_CallMethodDef;
52pub type R_FortranMethodDef = R_CMethodDef;
53
54pub type Rbyte = ::std::os::raw::c_uchar;
55#[doc = "type for length of (standard, not long) vectors etc"]
56pub type R_len_t = ::std::os::raw::c_int;
57#[repr(u32)]
58/// Enum of possible SEXP types
59#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
60pub enum SEXPTYPE {
61    #[doc = "nil = NULL"]
62    NILSXP = 0,
63    #[doc = "symbols"]
64    SYMSXP = 1,
65    #[doc = "lists of dotted pairs"]
66    LISTSXP = 2,
67    #[doc = "closures"]
68    CLOSXP = 3,
69    #[doc = "environments"]
70    ENVSXP = 4,
71    #[doc = "promises: \\[un\\]evaluated closure arguments"]
72    PROMSXP = 5,
73    #[doc = "language constructs (special lists)"]
74    LANGSXP = 6,
75    #[doc = "special forms"]
76    SPECIALSXP = 7,
77    #[doc = "builtin non-special forms"]
78    BUILTINSXP = 8,
79    #[doc = "\"scalar\" string type (internal only)"]
80    CHARSXP = 9,
81    #[doc = "logical vectors"]
82    LGLSXP = 10,
83    #[doc = "integer vectors"]
84    INTSXP = 13,
85    #[doc = "real variables"]
86    REALSXP = 14,
87    #[doc = "complex variables"]
88    CPLXSXP = 15,
89    #[doc = "string vectors"]
90    STRSXP = 16,
91    #[doc = "dot-dot-dot object"]
92    DOTSXP = 17,
93    #[doc = "make \"any\" args work"]
94    ANYSXP = 18,
95    #[doc = "generic vectors"]
96    VECSXP = 19,
97    #[doc = "expressions vectors"]
98    EXPRSXP = 20,
99    #[doc = "byte code"]
100    BCODESXP = 21,
101    #[doc = "external pointer"]
102    EXTPTRSXP = 22,
103    #[doc = "weak reference"]
104    WEAKREFSXP = 23,
105    #[doc = "raw bytes"]
106    RAWSXP = 24,
107    #[cfg(not(r_4_4))]
108    S4SXP = 25,
109    #[cfg(r_4_4)]
110    #[doc = "S4 non-vector"]
111    OBJSXP = 25,
112    #[doc = "fresh node created in new page"]
113    NEWSXP = 30,
114    #[doc = "node released by GC"]
115    FREESXP = 31,
116    #[doc = "Closure or Builtin"]
117    FUNSXP = 99,
118}
119pub type SEXP = *mut SEXPREC;
120
121#[repr(u32)]
122#[doc = "cetype_t is an identifier reseved by POSIX, but it is\nwell established as public.  Could remap by a #define though"]
123#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
124pub enum cetype_t {
125    CE_NATIVE = 0,
126    CE_UTF8 = 1,
127    CE_LATIN1 = 2,
128    CE_BYTES = 3,
129    CE_SYMBOL = 5,
130    CE_ANY = 99,
131}
132#[doc = "Finalization interface"]
133pub type R_CFinalizer_t = ::std::option::Option<unsafe extern "C" fn(arg1: SEXP)>;
134pub type Int32 = ::std::os::raw::c_uint;
135#[doc = "R 4.3 redefined `Rcomplex` to a union for compatibility with Fortran.\n But the old definition is compatible both the union version\n and the struct version.\n See: <https://github.com/extendr/extendr/issues/524>\n <div rustbindgen replaces=\"Rcomplex\"></div>"]
136#[repr(C)]
137#[derive(Debug, Copy, Clone)]
138pub struct Rcomplex {
139    pub r: f64,
140    pub i: f64,
141}
142
143#[doc = "R_xlen_t is defined as int on 32-bit platforms, and\n that confuses Rust. Keeping it always as ptrdiff_t works\n fine even on 32-bit.\n <div rustbindgen replaces=\"R_xlen_t\"></div>"]
144pub type R_xlen_t = isize;
145
146#[repr(C)]
147#[derive(Debug, Copy, Clone)]
148pub struct _DllInfo {
149    _unused: [u8; 0],
150}
151pub type DllInfo = _DllInfo;
152
153#[repr(u32)]
154#[doc = "PARSE_NULL will not be returned by R_ParseVector"]
155#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
156pub enum ParseStatus {
157    PARSE_NULL = 0,
158    PARSE_OK = 1,
159    PARSE_INCOMPLETE = 2,
160    PARSE_ERROR = 3,
161    PARSE_EOF = 4,
162}
163
164#[doc = "Called with a variable argument set after casting to a compatible\nfunction pointer."]
165pub type DL_FUNC = ::std::option::Option<unsafe extern "C" fn() -> *mut ::std::os::raw::c_void>;
166
167#[repr(C)]
168#[derive(Debug, Copy, Clone)]
169pub struct R_CallMethodDef {
170    pub name: *const ::std::os::raw::c_char,
171    pub fun: DL_FUNC,
172    pub numArgs: ::std::os::raw::c_int,
173}
174
175pub type R_outpstream_t = *mut R_outpstream_st;
176#[repr(C)]
177#[derive(Debug, Copy, Clone)]
178pub struct R_outpstream_st {
179    pub data: R_pstream_data_t,
180    pub type_: R_pstream_format_t,
181    pub version: ::std::os::raw::c_int,
182    pub OutChar: ::std::option::Option<
183        unsafe extern "C" fn(arg1: R_outpstream_t, arg2: ::std::os::raw::c_int),
184    >,
185    pub OutBytes: ::std::option::Option<
186        unsafe extern "C" fn(
187            arg1: R_outpstream_t,
188            arg2: *mut ::std::os::raw::c_void,
189            arg3: ::std::os::raw::c_int,
190        ),
191    >,
192    pub OutPersistHookFunc:
193        ::std::option::Option<unsafe extern "C" fn(arg1: SEXP, arg2: SEXP) -> SEXP>,
194    pub OutPersistHookData: SEXP,
195}
196
197pub type R_pstream_data_t = *mut ::std::os::raw::c_void;
198#[repr(u32)]
199#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
200pub enum R_pstream_format_t {
201    R_pstream_any_format = 0,
202    R_pstream_ascii_format = 1,
203    R_pstream_binary_format = 2,
204    R_pstream_xdr_format = 3,
205    R_pstream_asciihex_format = 4,
206}
207pub type R_inpstream_t = *mut R_inpstream_st;
208#[repr(C)]
209#[derive(Debug, Copy, Clone)]
210pub struct R_inpstream_st {
211    pub data: R_pstream_data_t,
212    pub type_: R_pstream_format_t,
213    pub InChar:
214        ::std::option::Option<unsafe extern "C" fn(arg1: R_inpstream_t) -> ::std::os::raw::c_int>,
215    pub InBytes: ::std::option::Option<
216        unsafe extern "C" fn(
217            arg1: R_inpstream_t,
218            arg2: *mut ::std::os::raw::c_void,
219            arg3: ::std::os::raw::c_int,
220        ),
221    >,
222    pub InPersistHookFunc:
223        ::std::option::Option<unsafe extern "C" fn(arg1: SEXP, arg2: SEXP) -> SEXP>,
224    pub InPersistHookData: SEXP,
225    pub native_encoding: [::std::os::raw::c_char; 64usize],
226    pub nat2nat_obj: *mut ::std::os::raw::c_void,
227    pub nat2utf8_obj: *mut ::std::os::raw::c_void,
228}
229
230extern "C" {
231    #[doc = "IEEE NaN"]
232    pub static R_NaN: f64;
233    #[doc = "IEEE Inf"]
234    pub static R_PosInf: f64;
235    #[doc = "IEEE -Inf"]
236    pub static R_NegInf: f64;
237    #[doc = "NA_REAL: IEEE"]
238    pub static R_NaReal: f64;
239    #[doc = "NA_INTEGER:= INT_MIN currently"]
240    pub static R_NaInt: ::std::os::raw::c_int;
241    #[doc = "NA_STRING is a SEXP, so defined in Rinternals.h"]
242    pub fn R_IsNA(arg1: f64) -> ::std::os::raw::c_int;
243    pub fn R_IsNaN(arg1: f64) -> ::std::os::raw::c_int;
244    pub fn R_finite(arg1: f64) -> ::std::os::raw::c_int;
245    pub fn Rprintf(arg1: *const ::std::os::raw::c_char, ...);
246    pub fn REprintf(arg1: *const ::std::os::raw::c_char, ...);
247    pub fn CAR(e: SEXP) -> SEXP;
248    pub fn CDR(e: SEXP) -> SEXP;
249    pub fn COMPLEX(x: SEXP) -> *mut Rcomplex;
250    pub fn COMPLEX_GET_REGION(sx: SEXP, i: R_xlen_t, n: R_xlen_t, buf: *mut Rcomplex) -> R_xlen_t;
251    pub fn DATAPTR(x: SEXP) -> *mut ::std::os::raw::c_void;
252    pub fn DATAPTR_RO(x: SEXP) -> *const ::std::os::raw::c_void;
253    pub fn DATAPTR_OR_NULL(x: SEXP) -> *const ::std::os::raw::c_void;
254    pub fn GetRNGstate();
255    pub fn PutRNGstate();
256    pub fn INTEGER(x: SEXP) -> *mut ::std::os::raw::c_int;
257    pub fn LOGICAL(x: SEXP) -> *mut ::std::os::raw::c_int;
258    pub fn LENGTH(x: SEXP) -> ::std::os::raw::c_int;
259    pub fn XLENGTH(x: SEXP) -> R_xlen_t;
260    pub fn RAW(x: SEXP) -> *mut Rbyte;
261    pub fn REAL(x: SEXP) -> *mut f64;
262    pub fn INTEGER_GET_REGION(
263        sx: SEXP,
264        i: R_xlen_t,
265        n: R_xlen_t,
266        buf: *mut ::std::os::raw::c_int,
267    ) -> R_xlen_t;
268    pub fn INTEGER_IS_SORTED(x: SEXP) -> ::std::os::raw::c_int;
269    pub fn INTEGER_NO_NA(x: SEXP) -> ::std::os::raw::c_int;
270    pub fn REAL_IS_SORTED(x: SEXP) -> ::std::os::raw::c_int;
271    pub fn REAL_NO_NA(x: SEXP) -> ::std::os::raw::c_int;
272    pub fn STRING_IS_SORTED(x: SEXP) -> ::std::os::raw::c_int;
273    pub fn STRING_NO_NA(x: SEXP) -> ::std::os::raw::c_int;
274    pub fn LOGICAL_GET_REGION(
275        sx: SEXP,
276        i: R_xlen_t,
277        n: R_xlen_t,
278        buf: *mut ::std::os::raw::c_int,
279    ) -> R_xlen_t;
280    pub fn MARK_NOT_MUTABLE(x: SEXP);
281    pub fn PRINTNAME(x: SEXP) -> SEXP;
282    #[doc = "The nil object"]
283    pub static R_NilValue: SEXP;
284    #[doc = "The base environment; formerly R_NilValue"]
285    pub static R_BaseEnv: SEXP;
286    #[doc = "The (fake) namespace for base"]
287    pub static R_BaseNamespace: SEXP;
288    #[doc = "NA_STRING as a CHARSXP"]
289    pub static R_NaString: SEXP;
290    #[doc = "srcref related functions"]
291    pub fn R_CHAR(x: SEXP) -> *const ::std::os::raw::c_char;
292    pub fn R_CleanTempDir();
293    #[doc = "External pointer interface"]
294    pub fn R_MakeExternalPtr(p: *mut ::std::os::raw::c_void, tag: SEXP, prot: SEXP) -> SEXP;
295    pub fn R_ExternalPtrAddr(s: SEXP) -> *mut ::std::os::raw::c_void;
296    pub fn R_ExternalPtrTag(s: SEXP) -> SEXP;
297    pub fn R_ExternalPtrProtected(s: SEXP) -> SEXP;
298    pub fn R_ClearExternalPtr(s: SEXP);
299    pub fn R_SetExternalPtrAddr(s: SEXP, p: *mut ::std::os::raw::c_void);
300    pub fn R_SetExternalPtrTag(s: SEXP, tag: SEXP);
301    pub fn R_SetExternalPtrProtected(s: SEXP, p: SEXP);
302    pub fn R_compute_identical(arg1: SEXP, arg2: SEXP, arg3: ::std::os::raw::c_int) -> Rboolean;
303    #[doc = "C stack limit"]
304    pub static mut R_CStackLimit: usize;
305    pub fn R_do_slot(obj: SEXP, name: SEXP) -> SEXP;
306    pub fn R_do_slot_assign(obj: SEXP, name: SEXP, value: SEXP) -> SEXP;
307    #[doc = "An empty environment at the root of the\nenvironment tree"]
308    pub static R_EmptyEnv: SEXP;
309    pub fn R_forceSymbols(info: *mut DllInfo, value: Rboolean) -> Rboolean;
310    pub fn R_GetCurrentEnv() -> SEXP;
311    #[doc = "srcref related functions"]
312    pub fn R_GetCurrentSrcref(arg1: ::std::os::raw::c_int) -> SEXP;
313    pub fn R_GetSrcFilename(arg1: SEXP) -> SEXP;
314    #[doc = "The \"global\" environment"]
315    pub static R_GlobalEnv: SEXP;
316    pub fn R_has_slot(obj: SEXP, name: SEXP) -> ::std::os::raw::c_int;
317    pub fn R_IsNamespaceEnv(rho: SEXP) -> Rboolean;
318    pub fn R_IsPackageEnv(rho: SEXP) -> Rboolean;
319    pub fn R_existsVarInFrame(rho: SEXP, symbol: SEXP) -> Rboolean;
320    pub fn R_removeVarFromFrame(symbol: SEXP, env: SEXP);
321    pub fn R_lsInternal3(env: SEXP, all: Rboolean, sorted: Rboolean) -> SEXP;
322    pub fn R_EnvironmentIsLocked(env: SEXP) -> Rboolean;
323    pub fn R_BindingIsLocked(symbol: SEXP, env: SEXP) -> Rboolean;
324    pub fn R_MakeUnwindCont() -> SEXP;
325    #[doc = "Missing argument marker"]
326    pub static R_MissingArg: SEXP;
327    pub fn R_NamespaceEnvSpec(rho: SEXP) -> SEXP;
328    #[doc = "Environment and Binding Features"]
329    pub fn R_NewEnv(arg1: SEXP, arg2: ::std::os::raw::c_int, arg3: ::std::os::raw::c_int) -> SEXP;
330    pub fn R_PackageEnvName(rho: SEXP) -> SEXP;
331    pub fn R_ParseVector(
332        arg1: SEXP,
333        arg2: ::std::os::raw::c_int,
334        arg3: *mut ParseStatus,
335        arg4: SEXP,
336    ) -> SEXP;
337    #[doc = "preserve objects across GCs"]
338    pub fn R_PreserveObject(arg1: SEXP);
339    pub fn R_RegisterCFinalizerEx(s: SEXP, fun: R_CFinalizer_t, onexit: Rboolean);
340    pub fn R_registerRoutines(
341        info: *mut DllInfo,
342        croutines: *const R_CMethodDef,
343        callRoutines: *const R_CallMethodDef,
344        fortranRoutines: *const R_FortranMethodDef,
345        externalRoutines: *const R_ExternalMethodDef,
346    ) -> ::std::os::raw::c_int;
347    pub fn R_ReleaseObject(arg1: SEXP);
348    pub fn R_RunExitFinalizers();
349    pub fn R_Serialize(s: SEXP, ops: R_outpstream_t);
350    #[doc = "Current srcref, for debuggers"]
351    pub static R_Srcref: SEXP;
352    pub fn R_tryEval(arg1: SEXP, arg2: SEXP, arg3: *mut ::std::os::raw::c_int) -> SEXP;
353    pub fn R_tryEvalSilent(arg1: SEXP, arg2: SEXP, arg3: *mut ::std::os::raw::c_int) -> SEXP;
354    #[cfg(not(r_4_5))]
355    #[doc = "Unbound marker"]
356    pub static R_UnboundValue: SEXP;
357    pub fn R_unif_index(arg1: f64) -> f64;
358    pub fn R_Unserialize(ips: R_inpstream_t) -> SEXP;
359    pub fn R_UnwindProtect(
360        fun: ::std::option::Option<unsafe extern "C" fn(data: *mut ::std::os::raw::c_void) -> SEXP>,
361        data: *mut ::std::os::raw::c_void,
362        cleanfun: ::std::option::Option<
363            unsafe extern "C" fn(data: *mut ::std::os::raw::c_void, jump: Rboolean),
364        >,
365        cleandata: *mut ::std::os::raw::c_void,
366        cont: SEXP,
367    ) -> SEXP;
368    pub fn R_useDynamicSymbols(info: *mut DllInfo, value: Rboolean) -> Rboolean;
369    pub fn RAW_GET_REGION(sx: SEXP, i: R_xlen_t, n: R_xlen_t, buf: *mut Rbyte) -> R_xlen_t;
370    pub fn REAL_GET_REGION(sx: SEXP, i: R_xlen_t, n: R_xlen_t, buf: *mut f64) -> R_xlen_t;
371    pub fn Rf_allocMatrix(
372        arg1: SEXPTYPE,
373        arg2: ::std::os::raw::c_int,
374        arg3: ::std::os::raw::c_int,
375    ) -> SEXP;
376    pub fn Rf_allocVector(arg1: SEXPTYPE, arg2: R_xlen_t) -> SEXP;
377    pub fn Rf_asChar(arg1: SEXP) -> SEXP;
378    pub fn Rf_asCharacterFactor(x: SEXP) -> SEXP;
379    pub fn Rf_coerceVector(arg1: SEXP, arg2: SEXPTYPE) -> SEXP;
380    pub fn Rf_conformable(arg1: SEXP, arg2: SEXP) -> Rboolean;
381    pub fn Rf_cons(arg1: SEXP, arg2: SEXP) -> SEXP;
382    pub fn Rf_defineVar(arg1: SEXP, arg2: SEXP, arg3: SEXP);
383    pub fn Rf_dimgets(arg1: SEXP, arg2: SEXP) -> SEXP;
384    pub fn Rf_dimnamesgets(arg1: SEXP, arg2: SEXP) -> SEXP;
385    pub fn Rf_duplicate(arg1: SEXP) -> SEXP;
386    pub fn Rf_error(arg1: *const ::std::os::raw::c_char, ...) -> !;
387    pub fn Rf_errorcall(call: SEXP, arg1: *const ::std::os::raw::c_char, ...) -> !;
388    pub fn Rf_warningcall(call: SEXP, arg1: *const ::std::os::raw::c_char, ...);
389    pub fn Rf_findFun(arg1: SEXP, arg2: SEXP) -> SEXP;
390    pub fn Rf_GetArrayDimnames(arg1: SEXP) -> SEXP;
391    pub fn Rf_getAttrib(arg1: SEXP, arg2: SEXP) -> SEXP;
392    pub fn Rf_GetColNames(arg1: SEXP) -> SEXP;
393    pub fn Rf_GetRowNames(arg1: SEXP) -> SEXP;
394    pub fn Rf_initialize_R(
395        ac: ::std::os::raw::c_int,
396        av: *mut *mut ::std::os::raw::c_char,
397    ) -> ::std::os::raw::c_int;
398    pub fn Rf_install(arg1: *const ::std::os::raw::c_char) -> SEXP;
399    pub fn Rf_isArray(arg1: SEXP) -> Rboolean;
400    pub fn Rf_isComplex(s: SEXP) -> Rboolean;
401    pub fn Rf_isEnvironment(s: SEXP) -> Rboolean;
402    pub fn Rf_isExpression(s: SEXP) -> Rboolean;
403    pub fn Rf_isFactor(arg1: SEXP) -> Rboolean;
404    pub fn Rf_isFunction(arg1: SEXP) -> Rboolean;
405    pub fn Rf_isInteger(arg1: SEXP) -> Rboolean;
406    pub fn Rf_isLanguage(arg1: SEXP) -> Rboolean;
407    pub fn Rf_isList(arg1: SEXP) -> Rboolean;
408    pub fn Rf_isLogical(s: SEXP) -> Rboolean;
409    pub fn Rf_isMatrix(arg1: SEXP) -> Rboolean;
410    pub fn Rf_isNewList(arg1: SEXP) -> Rboolean;
411    pub fn Rf_isNull(s: SEXP) -> Rboolean;
412    pub fn Rf_isNumber(arg1: SEXP) -> Rboolean;
413    pub fn Rf_isObject(s: SEXP) -> Rboolean;
414    pub fn Rf_isPrimitive(arg1: SEXP) -> Rboolean;
415    pub fn Rf_isReal(s: SEXP) -> Rboolean;
416    pub fn Rf_isString(s: SEXP) -> Rboolean;
417    pub fn Rf_isSymbol(s: SEXP) -> Rboolean;
418    pub fn Rf_isTs(arg1: SEXP) -> Rboolean;
419    pub fn Rf_isUserBinop(arg1: SEXP) -> Rboolean;
420    pub fn Rf_isVector(arg1: SEXP) -> Rboolean;
421    pub fn Rf_isVectorAtomic(arg1: SEXP) -> Rboolean;
422    pub fn Rf_isVectorizable(arg1: SEXP) -> Rboolean;
423    pub fn Rf_isVectorList(arg1: SEXP) -> Rboolean;
424    pub fn Rf_lang1(arg1: SEXP) -> SEXP;
425    pub fn Rf_lcons(arg1: SEXP, arg2: SEXP) -> SEXP;
426    pub fn Rf_mkCharLenCE(
427        arg1: *const ::std::os::raw::c_char,
428        arg2: ::std::os::raw::c_int,
429        arg3: cetype_t,
430    ) -> SEXP;
431    pub fn Rf_namesgets(arg1: SEXP, arg2: SEXP) -> SEXP;
432    pub fn Rf_ncols(arg1: SEXP) -> ::std::os::raw::c_int;
433    pub fn Rf_NoDevices() -> ::std::os::raw::c_int;
434    pub fn Rf_nrows(arg1: SEXP) -> ::std::os::raw::c_int;
435    pub fn Rf_NumDevices() -> ::std::os::raw::c_int;
436    pub fn Rf_PairToVectorList(x: SEXP) -> SEXP;
437    pub fn Rf_PrintValue(arg1: SEXP);
438    pub fn Rf_protect(arg1: SEXP) -> SEXP;
439    pub fn Rf_runif(arg1: f64, arg2: f64) -> f64;
440    pub fn Rf_ScalarInteger(arg1: ::std::os::raw::c_int) -> SEXP;
441    pub fn Rf_setAttrib(arg1: SEXP, arg2: SEXP, arg3: SEXP) -> SEXP;
442    pub fn Rf_unprotect(arg1: ::std::os::raw::c_int);
443    pub fn Rf_VectorToPairList(x: SEXP) -> SEXP;
444    pub fn Rf_xlength(arg1: SEXP) -> R_xlen_t;
445    pub fn Rf_xlengthgets(arg1: SEXP, arg2: R_xlen_t) -> SEXP;
446    pub fn SET_INTEGER_ELT(x: SEXP, i: R_xlen_t, v: ::std::os::raw::c_int);
447    pub fn SET_OBJECT(x: SEXP, v: ::std::os::raw::c_int);
448    pub fn SET_REAL_ELT(x: SEXP, i: R_xlen_t, v: f64);
449    pub fn SET_STRING_ELT(x: SEXP, i: R_xlen_t, v: SEXP);
450    pub fn SET_TAG(x: SEXP, y: SEXP);
451    pub fn SET_VECTOR_ELT(x: SEXP, i: R_xlen_t, v: SEXP) -> SEXP;
452    pub fn SETCDR(x: SEXP, y: SEXP) -> SEXP;
453    pub fn setup_Rmainloop();
454    pub fn REAL_ELT(x: SEXP, i: R_xlen_t) -> f64;
455    pub fn COMPLEX_ELT(x: SEXP, i: R_xlen_t) -> Rcomplex;
456    pub fn INTEGER_ELT(x: SEXP, i: R_xlen_t) -> ::std::os::raw::c_int;
457    pub fn STRING_ELT(x: SEXP, i: R_xlen_t) -> SEXP;
458    pub fn LOGICAL_ELT(x: SEXP, i: R_xlen_t) -> ::std::os::raw::c_int;
459    pub fn STRING_PTR_RO(x: SEXP) -> *const SEXP;
460    pub fn TAG(e: SEXP) -> SEXP;
461    pub fn VECTOR_ELT(x: SEXP, i: R_xlen_t) -> SEXP;
462    pub fn SETLEVELS(x: SEXP, v: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
463    // pub fn Rf_isS4(arg1: SEXP) -> Rboolean;
464
465}
466
467/// # Safety
468///
469/// This function dereferences a raw SEXP pointer.
470/// The caller must ensure that `x` is a valid SEXP.
471pub unsafe fn Rf_isS4(arg1: SEXP) -> Rboolean {
472    unsafe {
473        if secret::Rf_isS4_original(arg1) == 0 {
474            Rboolean::FALSE
475        } else {
476            Rboolean::TRUE
477        }
478    }
479}
480
481mod secret {
482    use super::*;
483    extern "C" {
484        #[link_name = "Rf_isS4"]
485        pub fn Rf_isS4_original(arg1: SEXP) -> u32;
486    }
487}
488
489impl From<Rboolean> for bool {
490    fn from(value: Rboolean) -> Self {
491        match value {
492            Rboolean::FALSE => false,
493            Rboolean::TRUE => true,
494        }
495    }
496}
497
498impl From<bool> for Rboolean {
499    fn from(value: bool) -> Self {
500        match value {
501            true => Rboolean::TRUE,
502            false => Rboolean::FALSE,
503        }
504    }
505}
506
507#[cfg(test)]
508mod tests {
509    use super::*;
510    use std::os::raw;
511
512    // Generate constant static strings.
513    // Much more efficient than CString.
514    // Generates asciiz.
515    macro_rules! cstr {
516        ($s: expr) => {
517            concat!($s, "\0").as_ptr() as *const raw::c_char
518        };
519    }
520
521    // Generate mutable static strings.
522    // Much more efficient than CString.
523    // Generates asciiz.
524    macro_rules! cstr_mut {
525        ($s: expr) => {
526            concat!($s, "\0").as_ptr() as *mut raw::c_char
527        };
528    }
529
530    // Thanks to @qinwf and @scottmmjackson for showing the way here.
531    fn start_R() {
532        unsafe {
533            if std::env::var("R_HOME").is_err() {
534                // env! gets the build-time R_HOME made in build.rs
535                std::env::set_var("R_HOME", env!("R_HOME"));
536            }
537
538            // Due to Rf_initEmbeddedR using __libc_stack_end
539            // We can't call Rf_initEmbeddedR.
540            // Instead we must follow rustr's example and call the parts.
541
542            //let res = unsafe { Rf_initEmbeddedR(1, args.as_mut_ptr()) };
543            if cfg!(target_os = "windows") && cfg!(target_arch = "x86") {
544                Rf_initialize_R(
545                    4,
546                    [
547                        cstr_mut!("R"),
548                        cstr_mut!("--arch=i386"),
549                        cstr_mut!("--slave"),
550                        cstr_mut!("--no-save"),
551                    ]
552                    .as_mut_ptr(),
553                );
554            } else {
555                Rf_initialize_R(
556                    3,
557                    [cstr_mut!("R"), cstr_mut!("--slave"), cstr_mut!("--no-save")].as_mut_ptr(),
558                );
559            }
560
561            // In case you are curious.
562            // Maybe 8MB is a bit small.
563            // eprintln!("R_CStackLimit={:016x}", R_CStackLimit);
564
565            if cfg!(not(target_os = "windows")) {
566                R_CStackLimit = usize::MAX;
567            }
568
569            setup_Rmainloop();
570        }
571    }
572
573    // Run some R code. Check the result.
574    #[test]
575    fn test_eval() {
576        start_R();
577        use crate::*;
578        extern "C" {
579            pub fn R_ParseEvalString(arg1: *const ::std::os::raw::c_char, arg2: SEXP) -> SEXP;
580        }
581        unsafe {
582            println!("Evaluating 1");
583            let val = Rf_protect(R_ParseEvalString(cstr!("1"), R_NilValue));
584            Rf_PrintValue(val);
585            assert_eq!(TYPEOF(val), SEXPTYPE::REALSXP);
586            assert_eq!(*REAL(val), 1.);
587            Rf_unprotect(1);
588        }
589        // There is one pathological example of `Rf_is*` where `TRUE` is not 1,
590        // but 16. We show here that the casting is done as intended
591        unsafe {
592            let sexp = R_ParseEvalString(cstr!(r#"new("factor")"#), R_GlobalEnv);
593            Rf_protect(sexp);
594            Rf_PrintValue(sexp);
595
596            assert_eq!(Rboolean::TRUE, Rboolean::TRUE);
597            // assert_eq!(Rboolean::from(is_s4), Rboolean::TRUE);
598            // assert_eq!(
599            //     std::mem::discriminant(&Rf_isS4(sexp)),
600            //     std::mem::discriminant(&Rboolean::TRUE),
601            // );
602            assert!(<Rboolean as Into<bool>>::into(Rf_isS4(sexp)));
603            assert!(
604                (Rboolean::FALSE == Rf_isS4(sexp)) || (Rboolean::TRUE == Rf_isS4(sexp)),
605                "PartialEq implementation is broken"
606            );
607            assert!(Rboolean::TRUE == Rf_isS4(sexp));
608            assert_eq!(Rf_isS4(sexp), Rboolean::TRUE);
609            Rf_unprotect(1);
610        }
611    }
612}