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::{Rboolean, 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 #[cfg(not(r_4_5))]
58 fn Rf_isFrame(x: SEXP) -> Rboolean;
59
60 #[cfg(r_4_5)]
61 fn Rf_isDataFrame(x: SEXP) -> Rboolean;
62}
63
64/// 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.
65///
66/// # Safety
67///
68/// This function dereferences a raw SEXP pointer.
69/// The caller must ensure that `x` is a valid SEXP pointer to an environment.
70#[inline]
71pub unsafe fn get_parent_env(x: SEXP) -> SEXP {
72 #[cfg(not(r_4_5))]
73 {
74 ENCLOS(x)
75 }
76 #[cfg(r_4_5)]
77 {
78 R_ParentEnv(x)
79 }
80}
81
82/// Returns a variable from an environment
83///
84/// # Safety
85///
86/// This function dereferences raw SEXP pointers.
87/// The caller must ensure that `symbol` and `env` are valid SEXP pointers.
88#[inline]
89pub unsafe fn get_var(symbol: SEXP, env: SEXP) -> SEXP {
90 #[cfg(not(r_4_5))]
91 {
92 Rf_findVar(symbol, env)
93 }
94 #[cfg(r_4_5)]
95 {
96 R_getVar(symbol, env)
97 }
98}
99
100/// Returns the value of the requested variable in an environment
101///
102/// # Safety
103///
104/// This function dereferences raw SEXP pointers.
105/// The caller must ensure that `symbol` and `env` are valid SEXP pointers.
106#[inline]
107pub unsafe fn get_var_in_frame(symbol: SEXP, env: SEXP) -> SEXP {
108 #[cfg(not(r_4_5))]
109 {
110 Rf_findVarInFrame(symbol, env)
111 }
112 #[cfg(r_4_5)]
113 {
114 R_getVarEx(env, symbol)
115 }
116}
117
118/// Return the environment of a closure
119///
120/// # Safety
121///
122/// This function dereferences a raw SEXP pointer.
123/// The caller must ensure that `x` is a valid SEXP pointer to a closure.
124#[inline]
125pub unsafe fn get_closure_env(x: SEXP) -> SEXP {
126 #[cfg(not(r_4_5))]
127 {
128 CLOENV(x)
129 }
130 #[cfg(r_4_5)]
131 {
132 R_ClosureEnv(x)
133 }
134}
135
136/// Return the body of a closure
137///
138/// # Safety
139///
140/// This function dereferences a raw SEXP pointer.
141/// The caller must ensure that `x` is a valid SEXP pointer to a closure.
142#[inline]
143pub unsafe fn get_closure_body(x: SEXP) -> SEXP {
144 #[cfg(not(r_4_5))]
145 {
146 BODY(x)
147 }
148 #[cfg(r_4_5)]
149 {
150 R_ClosureBody(x)
151 }
152}
153
154/// Access a closure's arguments
155///
156/// # Safety
157///
158/// This function dereferences a raw SEXP pointer.
159/// The caller must ensure that `x` is a valid SEXP pointer to a closure.
160#[inline]
161pub unsafe fn get_closure_formals(x: SEXP) -> SEXP {
162 #[cfg(not(r_4_5))]
163 {
164 FORMALS(x)
165 }
166 #[cfg(r_4_5)]
167 {
168 R_ClosureFormals(x)
169 }
170}
171
172/// Access a DATAPTR
173///
174/// # Safety
175///
176/// This function dereferences a raw SEXP pointer.
177/// The caller must ensure that `x` is a valid SEXP pointer.
178#[inline]
179pub unsafe fn dataptr(x: SEXP) -> *const ::std::os::raw::c_void {
180 #[cfg(not(r_4_5))]
181 {
182 DATAPTR(x) as *const _
183 }
184 #[cfg(r_4_5)]
185 {
186 DATAPTR_RO(x)
187 }
188}
189
190/// Check is data.frame
191///
192/// # Safety
193///
194/// This function dereferences a raw SEXP pointer.
195/// The caller must ensure that `x` is a valid SEXP pointer.
196#[inline]
197pub unsafe fn is_data_frame(x: SEXP) -> Rboolean {
198 #[cfg(not(r_4_5))]
199 {
200 Rf_isFrame(x)
201 }
202 #[cfg(r_4_5)]
203 {
204 Rf_isDataFrame(x)
205 }
206}