Skip to main content

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}