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}