extendr_ffi/
backports.rs

1//! Backport functions
2//!
3//! R's C API is changing and is stabilizing. As such some functions
4//! that were available in previous versions of R are not available
5//! in later versions of R, or they cause a warning in `R CMD check`.
6//!
7//! Use the functions in this module to ensure backwards compatibility.
8
9// R 4.5 backports notes saved in wayback machine here:
10// https://web.archive.org/web/20250325171443/https://rstudio.github.io/r-manuals/r-exts/The-R-API.html#moving-into-c-api-compliance
11
12use crate::SEXP;
13
14extern "C" {
15    #[cfg(not(r_4_5))]
16    fn ENCLOS(x: SEXP) -> SEXP;
17
18    #[cfg(r_4_5)]
19    fn R_ParentEnv(x: SEXP) -> SEXP;
20
21    #[cfg(not(r_4_5))]
22    fn Rf_findVar(arg1: SEXP, arg2: SEXP) -> SEXP;
23
24    #[cfg(r_4_5)]
25    fn R_getVar(arg1: SEXP, arg2: SEXP) -> SEXP;
26
27    #[cfg(not(r_4_5))]
28    fn Rf_findVarInFrame(arg1: SEXP, arg2: SEXP) -> SEXP;
29
30    #[cfg(r_4_5)]
31    fn R_getVarEx(arg1: SEXP, arg2: SEXP) -> SEXP;
32
33    #[cfg(not(r_4_5))]
34    fn CLOENV(x: SEXP) -> SEXP;
35
36    #[cfg(r_4_5)]
37    fn R_ClosureEnv(x: SEXP) -> SEXP;
38
39    #[cfg(not(r_4_5))]
40    fn BODY(x: SEXP) -> SEXP;
41
42    #[cfg(r_4_5)]
43    fn R_ClosureBody(x: SEXP) -> SEXP;
44
45    #[cfg(not(r_4_5))]
46    fn FORMALS(x: SEXP) -> SEXP;
47
48    #[cfg(r_4_5)]
49    fn R_ClosureFormals(x: SEXP) -> SEXP;
50
51    #[cfg(not(r_4_5))]
52    fn DATAPTR(x: SEXP) -> *mut ::std::os::raw::c_void;
53
54    #[cfg(r_4_5)]
55    fn DATAPTR_RO(x: SEXP) -> *const ::std::os::raw::c_void;
56}
57
58/// Returns the enclosing environment of env, which will usually be of type ENVSXP, except for the special environment R_EmptyEnv, which terminates the environment chain; its enclosing environment is R_NilValue.
59///
60/// # Safety
61///
62/// This function dereferences a raw SEXP pointer.
63/// The caller must ensure that `x` is a valid SEXP pointer to an environment.
64#[inline]
65pub unsafe fn get_parent_env(x: SEXP) -> SEXP {
66    #[cfg(not(r_4_5))]
67    {
68        ENCLOS(x)
69    }
70    #[cfg(r_4_5)]
71    {
72        R_ParentEnv(x)
73    }
74}
75
76/// Returns a variable from an environment
77///
78/// # Safety
79///
80/// This function dereferences raw SEXP pointers.
81/// The caller must ensure that `symbol` and `env` are valid SEXP pointers.
82#[inline]
83pub unsafe fn get_var(symbol: SEXP, env: SEXP) -> SEXP {
84    #[cfg(not(r_4_5))]
85    {
86        Rf_findVar(symbol, env)
87    }
88    #[cfg(r_4_5)]
89    {
90        R_getVar(symbol, env)
91    }
92}
93
94/// Returns the value of the requested variable in an environment
95///
96/// # Safety
97///
98/// This function dereferences raw SEXP pointers.
99/// The caller must ensure that `symbol` and `env` are valid SEXP pointers.
100#[inline]
101pub unsafe fn get_var_in_frame(symbol: SEXP, env: SEXP) -> SEXP {
102    #[cfg(not(r_4_5))]
103    {
104        Rf_findVarInFrame(symbol, env)
105    }
106    #[cfg(r_4_5)]
107    {
108        R_getVarEx(env, symbol)
109    }
110}
111
112/// Return the environment of a closure
113///
114/// # Safety
115///
116/// This function dereferences a raw SEXP pointer.
117/// The caller must ensure that `x` is a valid SEXP pointer to a closure.
118#[inline]
119pub unsafe fn get_closure_env(x: SEXP) -> SEXP {
120    #[cfg(not(r_4_5))]
121    {
122        CLOENV(x)
123    }
124    #[cfg(r_4_5)]
125    {
126        R_ClosureEnv(x)
127    }
128}
129
130/// Return the body of a closure
131///
132/// # Safety
133///
134/// This function dereferences a raw SEXP pointer.
135/// The caller must ensure that `x` is a valid SEXP pointer to a closure.
136#[inline]
137pub unsafe fn get_closure_body(x: SEXP) -> SEXP {
138    #[cfg(not(r_4_5))]
139    {
140        BODY(x)
141    }
142    #[cfg(r_4_5)]
143    {
144        R_ClosureBody(x)
145    }
146}
147
148/// Access a closure's arguments
149///
150/// # Safety
151///
152/// This function dereferences a raw SEXP pointer.
153/// The caller must ensure that `x` is a valid SEXP pointer to a closure.
154#[inline]
155pub unsafe fn get_closure_formals(x: SEXP) -> SEXP {
156    #[cfg(not(r_4_5))]
157    {
158        FORMALS(x)
159    }
160    #[cfg(r_4_5)]
161    {
162        R_ClosureFormals(x)
163    }
164}
165
166/// Access a DATAPTR
167///
168/// # Safety
169///
170/// This function dereferences a raw SEXP pointer.
171/// The caller must ensure that `x` is a valid SEXP pointer.
172#[inline]
173pub unsafe fn dataptr(x: SEXP) -> *const ::std::os::raw::c_void {
174    #[cfg(not(r_4_5))]
175    {
176        DATAPTR(x) as *const _
177    }
178    #[cfg(r_4_5)]
179    {
180        DATAPTR_RO(x)
181    }
182}