extendr_api/robj/
rinternals.rs

1use crate::*;
2
3///////////////////////////////////////////////////////////////
4/// The following impls wrap specific Rinternals.h functions.
5///
6pub trait Rinternals: Types + Conversions {
7    /// Return true if this is the null object.
8    fn is_null(&self) -> bool {
9        unsafe { Rf_isNull(self.get()).into() }
10    }
11
12    /// Return true if this is a symbol.
13    fn is_symbol(&self) -> bool {
14        unsafe { Rf_isSymbol(self.get()).into() }
15    }
16
17    /// Return true if this is a boolean (logical) vector
18    fn is_logical(&self) -> bool {
19        unsafe { Rf_isLogical(self.get()).into() }
20    }
21
22    /// Return true if this is a real (f64) vector.
23    fn is_real(&self) -> bool {
24        unsafe { Rf_isReal(self.get()).into() }
25    }
26
27    /// Return true if this is a complex vector.
28    fn is_complex(&self) -> bool {
29        unsafe { Rf_isComplex(self.get()).into() }
30    }
31
32    /// Return true if this is an expression.
33    fn is_expressions(&self) -> bool {
34        unsafe { Rf_isExpression(self.get()).into() }
35    }
36
37    /// Return true if this is an environment.
38    fn is_environment(&self) -> bool {
39        unsafe { Rf_isEnvironment(self.get()).into() }
40    }
41
42    /// Return true if this is an environment.
43    fn is_promise(&self) -> bool {
44        self.sexptype() == SEXPTYPE::PROMSXP
45    }
46
47    /// Return true if this is a string.
48    fn is_string(&self) -> bool {
49        unsafe { Rf_isString(self.get()).into() }
50    }
51
52    /// Return true if this is an object (ie. has a class attribute).
53    fn is_object(&self) -> bool {
54        unsafe { Rf_isObject(self.get()).into() }
55    }
56
57    /// Return true if this is a S4 object.
58    fn is_s4(&self) -> bool {
59        unsafe { Rf_isS4(self.get()).into() }
60    }
61
62    /// Return true if this is an expression.
63    fn is_external_pointer(&self) -> bool {
64        self.rtype() == Rtype::ExternalPtr
65    }
66
67    /// Get the source ref.
68    fn get_current_srcref(val: i32) -> Robj {
69        unsafe { Robj::from_sexp(R_GetCurrentSrcref(val as std::ffi::c_int)) }
70    }
71
72    /// Get the source filename.
73    fn get_src_filename(&self) -> Robj {
74        unsafe { Robj::from_sexp(R_GetSrcFilename(self.get())) }
75    }
76
77    /// Convert to a string vector.
78    fn as_character_vector(&self) -> Robj {
79        unsafe { Robj::from_sexp(Rf_asChar(self.get())) }
80    }
81
82    /// Convert to vectors of many kinds.
83    fn coerce_vector(&self, sexptype: SEXPTYPE) -> Robj {
84        single_threaded(|| unsafe { Robj::from_sexp(Rf_coerceVector(self.get(), sexptype)) })
85    }
86
87    /// Convert a pairlist (LISTSXP) to a vector list (VECSXP).
88    fn pair_to_vector_list(&self) -> Robj {
89        single_threaded(|| unsafe { Robj::from_sexp(Rf_PairToVectorList(self.get())) })
90    }
91
92    /// Convert a vector list (VECSXP) to a pair list (LISTSXP)
93    fn vector_to_pair_list(&self) -> Robj {
94        single_threaded(|| unsafe { Robj::from_sexp(Rf_VectorToPairList(self.get())) })
95    }
96
97    /// Convert a factor to a string vector.
98    fn as_character_factor(&self) -> Robj {
99        single_threaded(|| unsafe { Robj::from_sexp(Rf_asCharacterFactor(self.get())) })
100    }
101
102    /// Allocate a matrix object.
103    fn alloc_matrix(sexptype: SEXPTYPE, rows: i32, cols: i32) -> Robj {
104        single_threaded(|| unsafe { Robj::from_sexp(Rf_allocMatrix(sexptype, rows, cols)) })
105    }
106
107    /// Do a deep copy of this object.
108    /// Note that clone() only adds a reference.
109    fn duplicate(&self) -> Robj {
110        single_threaded(|| unsafe { Robj::from_sexp(Rf_duplicate(self.get())) })
111    }
112
113    /// Find a function in an environment ignoring other variables.
114    ///
115    /// This evaulates promises if they are found.
116    ///
117    /// See also [global_function()].
118    /// ```
119    /// use extendr_api::prelude::*;
120    /// test! {
121    ///    let my_fun = base_env().find_function(sym!(ls)).unwrap();
122    ///    assert_eq!(my_fun.is_function(), true);
123    ///
124    ///    // Note: this may crash on some versions of windows which don't support unwinding.
125    ///    // assert!(base_env().find_function(sym!(qwertyuiop)).is_none());
126    /// }
127    /// ```
128    fn find_function<K: TryInto<Symbol, Error = Error>>(&self, key: K) -> Result<Robj> {
129        let key: Symbol = key.try_into()?;
130        if !self.is_environment() {
131            return Err(Error::NotFound(key.into()));
132        }
133        // This may be better:
134        // let mut env: Robj = self.into();
135        // loop {
136        //     if let Some(var) = env.local(&key) {
137        //         if let Some(var) = var.eval_promise() {
138        //             if var.is_function() {
139        //                 break Some(var);
140        //             }
141        //         }
142        //     }
143        //     if let Some(parent) = env.parent() {
144        //         env = parent;
145        //     } else {
146        //         break None;
147        //     }
148        // }
149        unsafe {
150            let sexp = self.get();
151            if let Ok(var) = catch_r_error(|| Rf_findFun(key.get(), sexp)) {
152                Ok(Robj::from_sexp(var))
153            } else {
154                Err(Error::NotFound(key.into()))
155            }
156        }
157    }
158
159    /// Find a variable in an environment.
160    ///
161    // //TODO: fix me, as this variable is hidden behind non-api as of this writing
162    // See also [global_var()].
163    ///
164    /// Note that many common variables and functions are contained in promises
165    /// which must be evaluated and this function may throw an R error.
166    ///
167    fn find_var<K: TryInto<Symbol, Error = Error>>(&self, key: K) -> Result<Robj> {
168        let key: Symbol = key.try_into()?;
169        if !self.is_environment() {
170            return Err(Error::NotFound(key.into()));
171        }
172        // Alternative:
173        // let mut env: Robj = self.into();
174        // loop {
175        //     if let Some(var) = env.local(&key) {
176        //         println!("v1={:?}", var);
177        //         if let Some(var) = var.eval_promise() {
178        //             println!("v2={:?}", var);
179        //             break Some(var);
180        //         }
181        //     }
182        //     if let Some(parent) = env.parent() {
183        //         env = parent;
184        //     } else {
185        //         break None;
186        //     }
187        // }
188        unsafe {
189            let sexp = self.get();
190            if let Ok(var) = catch_r_error(|| Rf_findVar(key.get(), sexp)) {
191                if var != R_UnboundValue {
192                    Ok(Robj::from_sexp(var))
193                } else {
194                    Err(Error::NotFound(key.into()))
195                }
196            } else {
197                Err(Error::NotFound(key.into()))
198            }
199        }
200    }
201
202    #[cfg(feature = "non-api")]
203    /// If this object is a promise, evaluate it, otherwise return the object.
204    /// ```
205    /// use extendr_api::prelude::*;
206    /// test! {
207    ///    let iris_promise = global_env().find_var(sym!(iris)).unwrap();
208    ///    let iris_dataframe = iris_promise.eval_promise().unwrap();
209    ///    assert_eq!(iris_dataframe.is_frame(), true);
210    /// }
211    /// ```
212    fn eval_promise(&self) -> Result<Robj> {
213        if self.is_promise() {
214            self.as_promise().unwrap().eval()
215        } else {
216            Ok(self.as_robj().clone())
217        }
218    }
219
220    /// Number of columns of a matrix
221    fn ncols(&self) -> usize {
222        unsafe { Rf_ncols(self.get()) as usize }
223    }
224
225    /// Number of rows of a matrix
226    fn nrows(&self) -> usize {
227        unsafe { Rf_nrows(self.get()) as usize }
228    }
229
230    /// Internal function used to implement `#[extendr]` impl
231    #[doc(hidden)]
232    unsafe fn make_external_ptr<T>(p: *mut T, prot: Robj) -> Robj {
233        let type_name: Robj = std::any::type_name::<T>().into();
234        Robj::from_sexp(single_threaded(|| {
235            R_MakeExternalPtr(
236                p as *mut ::std::os::raw::c_void,
237                type_name.get(),
238                prot.get(),
239            )
240        }))
241    }
242
243    /// Internal function used to implement `#[extendr]` impl
244    #[doc(hidden)]
245    unsafe fn external_ptr_addr<T>(&self) -> *mut T {
246        R_ExternalPtrAddr(self.get()).cast()
247    }
248
249    /// Internal function used to implement `#[extendr]` impl
250    #[doc(hidden)]
251    unsafe fn external_ptr_tag(&self) -> Robj {
252        Robj::from_sexp(R_ExternalPtrTag(self.get()))
253    }
254
255    /// Internal function used to implement `#[extendr]` impl
256    #[doc(hidden)]
257    unsafe fn external_ptr_protected(&self) -> Robj {
258        Robj::from_sexp(R_ExternalPtrProtected(self.get()))
259    }
260
261    #[doc(hidden)]
262    unsafe fn register_c_finalizer(&self, func: R_CFinalizer_t) {
263        // Use R_RegisterCFinalizerEx() and set onexit to 1 (TRUE) to invoke the
264        // finalizer on a shutdown of the R session as well.
265        single_threaded(|| R_RegisterCFinalizerEx(self.get(), func, Rboolean::TRUE));
266    }
267
268    /// Copy a vector and resize it.
269    /// See. <https://github.com/hadley/r-internals/blob/master/vectors.md>
270    fn xlengthgets(&self, new_len: usize) -> Result<Robj> {
271        unsafe {
272            if self.is_vector() {
273                Ok(single_threaded(|| {
274                    Robj::from_sexp(Rf_xlengthgets(self.get(), new_len as R_xlen_t))
275                }))
276            } else {
277                Err(Error::ExpectedVector(self.as_robj().clone()))
278            }
279        }
280    }
281
282    /// Allocated an owned object of a certain type.
283    fn alloc_vector(sexptype: SEXPTYPE, len: usize) -> Robj {
284        single_threaded(|| unsafe { Robj::from_sexp(Rf_allocVector(sexptype, len as R_xlen_t)) })
285    }
286
287    /// Return true if two arrays have identical dims.
288    fn conformable(a: &Robj, b: &Robj) -> bool {
289        single_threaded(|| unsafe { Rf_conformable(a.get(), b.get()).into() })
290    }
291
292    /// Return true if this is an array.
293    fn is_array(&self) -> bool {
294        unsafe { Rf_isArray(self.get()).into() }
295    }
296
297    /// Return true if this is factor.
298    fn is_factor(&self) -> bool {
299        unsafe { Rf_isFactor(self.get()).into() }
300    }
301
302    /// Return true if this is a data frame.
303    fn is_frame(&self) -> bool {
304        unsafe { Rf_isFrame(self.get()).into() }
305    }
306
307    /// Return true if this is a function or a primitive (CLOSXP, BUILTINSXP or SPECIALSXP)
308    fn is_function(&self) -> bool {
309        unsafe { Rf_isFunction(self.get()).into() }
310    }
311
312    /// Return true if this is an integer vector (INTSXP) but not a factor.
313    fn is_integer(&self) -> bool {
314        unsafe { Rf_isInteger(self.get()).into() }
315    }
316
317    /// Return true if this is a language object (LANGSXP).
318    fn is_language(&self) -> bool {
319        unsafe { Rf_isLanguage(self.get()).into() }
320    }
321
322    /// Return true if this is NILSXP or LISTSXP.
323    fn is_pairlist(&self) -> bool {
324        unsafe { Rf_isList(self.get()).into() }
325    }
326
327    /// Return true if this is a matrix.
328    fn is_matrix(&self) -> bool {
329        unsafe { Rf_isMatrix(self.get()).into() }
330    }
331
332    /// Return true if this is NILSXP or VECSXP.
333    fn is_list(&self) -> bool {
334        unsafe { Rf_isNewList(self.get()).into() }
335    }
336
337    /// Return true if this is INTSXP, LGLSXP or REALSXP but not a factor.
338    fn is_number(&self) -> bool {
339        unsafe { Rf_isNumber(self.get()).into() }
340    }
341
342    /// Return true if this is a primitive function BUILTINSXP, SPECIALSXP.
343    fn is_primitive(&self) -> bool {
344        unsafe { Rf_isPrimitive(self.get()).into() }
345    }
346
347    /// Return true if this is a time series vector (see tsp).
348    fn is_ts(&self) -> bool {
349        unsafe { Rf_isTs(self.get()).into() }
350    }
351
352    /// Return true if this is a user defined binop.
353    fn is_user_binop(&self) -> bool {
354        unsafe { Rf_isUserBinop(self.get()).into() }
355    }
356
357    #[cfg(feature = "non-api")]
358    /// Return true if this is a valid string.
359    fn is_valid_string(&self) -> bool {
360        unsafe { Rf_isValidString(self.get()).into() }
361    }
362
363    #[cfg(feature = "non-api")]
364    /// Return true if this is a valid string.
365    fn is_valid_string_f(&self) -> bool {
366        unsafe { Rf_isValidStringF(self.get()).into() }
367    }
368
369    /// Return true if this is a vector.
370    fn is_vector(&self) -> bool {
371        unsafe { Rf_isVector(self.get()).into() }
372    }
373
374    /// Return true if this is an atomic vector.
375    fn is_vector_atomic(&self) -> bool {
376        unsafe { Rf_isVectorAtomic(self.get()).into() }
377    }
378
379    /// Return true if this is a vector list.
380    fn is_vector_list(&self) -> bool {
381        unsafe { Rf_isVectorList(self.get()).into() }
382    }
383
384    /// Return true if this is can be made into a vector.
385    fn is_vectorizable(&self) -> bool {
386        unsafe { Rf_isVectorizable(self.get()).into() }
387    }
388
389    /// Return true if this is RAWSXP.
390    fn is_raw(&self) -> bool {
391        self.rtype() == Rtype::Raw
392    }
393
394    /// Return true if this is CHARSXP.
395    fn is_char(&self) -> bool {
396        self.rtype() == Rtype::Rstr
397    }
398
399    /// Check an external pointer tag.
400    /// This is used to wrap R objects.
401    #[doc(hidden)]
402    fn check_external_ptr_type<T>(&self) -> bool {
403        if self.sexptype() == SEXPTYPE::EXTPTRSXP {
404            let tag = unsafe { self.external_ptr_tag() };
405            if tag.as_str() == Some(std::any::type_name::<T>()) {
406                return true;
407            }
408        }
409        false
410    }
411
412    fn is_missing_arg(&self) -> bool {
413        unsafe { self.get() == R_MissingArg }
414    }
415
416    fn is_unbound_value(&self) -> bool {
417        unsafe { self.get() == R_UnboundValue }
418    }
419
420    fn is_package_env(&self) -> bool {
421        unsafe { R_IsPackageEnv(self.get()).into() }
422    }
423
424    fn package_env_name(&self) -> Robj {
425        unsafe { Robj::from_sexp(R_PackageEnvName(self.get())) }
426    }
427
428    fn is_namespace_env(&self) -> bool {
429        unsafe { R_IsNamespaceEnv(self.get()).into() }
430    }
431
432    fn namespace_env_spec(&self) -> Robj {
433        unsafe { Robj::from_sexp(R_NamespaceEnvSpec(self.get())) }
434    }
435
436    /// Returns `true` if this is an ALTREP object.
437    fn is_altrep(&self) -> bool {
438        unsafe { ALTREP(self.get()) != 0 }
439    }
440
441    /// Returns `true` if this is an integer ALTREP object.
442    fn is_altinteger(&self) -> bool {
443        unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::INTSXP }
444    }
445
446    /// Returns `true` if this is an real ALTREP object.
447    fn is_altreal(&self) -> bool {
448        unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::REALSXP }
449    }
450
451    /// Returns `true` if this is an logical ALTREP object.
452    fn is_altlogical(&self) -> bool {
453        unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::LGLSXP }
454    }
455
456    /// Returns `true` if this is a raw ALTREP object.
457    fn is_altraw(&self) -> bool {
458        unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::RAWSXP }
459    }
460
461    /// Returns `true` if this is an integer ALTREP object.
462    fn is_altstring(&self) -> bool {
463        unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::STRSXP }
464    }
465
466    /// Returns `true` if this is an integer ALTREP object.
467    #[cfg(use_r_altlist)]
468    fn is_altlist(&self) -> bool {
469        unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::VECSXP }
470    }
471
472    /// Generate a text representation of this object.
473    fn deparse(&self) -> Result<String> {
474        use crate as extendr_api;
475        let strings: Strings = call!("deparse", self.as_robj())?.try_into()?;
476        if strings.len() == 1 {
477            Ok(String::from(strings.elt(0).as_str()))
478        } else {
479            Ok(strings
480                .iter()
481                .map(|s| s.as_str())
482                .collect::<Vec<_>>()
483                .join(""))
484        }
485    }
486}
487
488impl Rinternals for Robj {}