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