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