extendr_api/robj/
rinternals.rs
1use crate::*;
2use extendr_ffi::{
3 get_var, R_CFinalizer_t, R_ExternalPtrAddr, R_ExternalPtrProtected, R_ExternalPtrTag,
4 R_GetCurrentSrcref, R_GetSrcFilename, R_IsNamespaceEnv, R_IsPackageEnv, R_MakeExternalPtr,
5 R_MissingArg, R_NamespaceEnvSpec, R_PackageEnvName, R_RegisterCFinalizerEx, R_UnboundValue,
6 R_xlen_t, Rboolean, Rf_PairToVectorList, Rf_VectorToPairList, Rf_allocMatrix, Rf_allocVector,
7 Rf_asChar, Rf_asCharacterFactor, Rf_coerceVector, Rf_conformable, Rf_duplicate, Rf_findFun,
8 Rf_isArray, Rf_isComplex, Rf_isEnvironment, Rf_isExpression, Rf_isFactor, Rf_isFrame,
9 Rf_isFunction, Rf_isInteger, Rf_isLanguage, Rf_isList, Rf_isLogical, Rf_isMatrix, Rf_isNewList,
10 Rf_isNull, Rf_isNumber, Rf_isObject, Rf_isPrimitive, Rf_isReal, Rf_isS4, Rf_isString,
11 Rf_isSymbol, Rf_isTs, Rf_isUserBinop, Rf_isVector, Rf_isVectorAtomic, Rf_isVectorList,
12 Rf_isVectorizable, Rf_ncols, Rf_nrows, Rf_xlengthgets, ALTREP, TYPEOF,
13};
14pub trait Rinternals: Types + Conversions {
18 fn is_null(&self) -> bool {
20 unsafe { Rf_isNull(self.get()).into() }
21 }
22
23 fn is_symbol(&self) -> bool {
25 unsafe { Rf_isSymbol(self.get()).into() }
26 }
27
28 fn is_logical(&self) -> bool {
30 unsafe { Rf_isLogical(self.get()).into() }
31 }
32
33 fn is_real(&self) -> bool {
35 unsafe { Rf_isReal(self.get()).into() }
36 }
37
38 fn is_complex(&self) -> bool {
40 unsafe { Rf_isComplex(self.get()).into() }
41 }
42
43 fn is_expressions(&self) -> bool {
45 unsafe { Rf_isExpression(self.get()).into() }
46 }
47
48 fn is_environment(&self) -> bool {
50 unsafe { Rf_isEnvironment(self.get()).into() }
51 }
52
53 fn is_promise(&self) -> bool {
55 self.sexptype() == SEXPTYPE::PROMSXP
56 }
57
58 fn is_string(&self) -> bool {
60 unsafe { Rf_isString(self.get()).into() }
61 }
62
63 fn is_object(&self) -> bool {
65 unsafe { Rf_isObject(self.get()).into() }
66 }
67
68 fn is_s4(&self) -> bool {
70 unsafe { Rf_isS4(self.get()).into() }
71 }
72
73 fn is_external_pointer(&self) -> bool {
75 self.rtype() == Rtype::ExternalPtr
76 }
77
78 fn get_current_srcref(val: i32) -> Robj {
80 unsafe { Robj::from_sexp(R_GetCurrentSrcref(val as std::ffi::c_int)) }
81 }
82
83 fn get_src_filename(&self) -> Robj {
85 unsafe { Robj::from_sexp(R_GetSrcFilename(self.get())) }
86 }
87
88 fn as_character_vector(&self) -> Robj {
90 unsafe { Robj::from_sexp(Rf_asChar(self.get())) }
91 }
92
93 fn coerce_vector(&self, sexptype: SEXPTYPE) -> Robj {
95 single_threaded(|| unsafe { Robj::from_sexp(Rf_coerceVector(self.get(), sexptype)) })
96 }
97
98 fn pair_to_vector_list(&self) -> Robj {
100 single_threaded(|| unsafe { Robj::from_sexp(Rf_PairToVectorList(self.get())) })
101 }
102
103 fn vector_to_pair_list(&self) -> Robj {
105 single_threaded(|| unsafe { Robj::from_sexp(Rf_VectorToPairList(self.get())) })
106 }
107
108 fn as_character_factor(&self) -> Robj {
110 single_threaded(|| unsafe { Robj::from_sexp(Rf_asCharacterFactor(self.get())) })
111 }
112
113 fn alloc_matrix(sexptype: SEXPTYPE, rows: i32, cols: i32) -> Robj {
115 single_threaded(|| unsafe { Robj::from_sexp(Rf_allocMatrix(sexptype, rows, cols)) })
116 }
117
118 fn duplicate(&self) -> Robj {
121 single_threaded(|| unsafe { Robj::from_sexp(Rf_duplicate(self.get())) })
122 }
123
124 fn find_function<K: TryInto<Symbol, Error = Error>>(&self, key: K) -> Result<Robj> {
140 let key: Symbol = key.try_into()?;
141 if !self.is_environment() {
142 return Err(Error::NotFound(key.into()));
143 }
144 unsafe {
161 let sexp = self.get();
162 if let Ok(var) = catch_r_error(|| Rf_findFun(key.get(), sexp)) {
163 Ok(Robj::from_sexp(var))
164 } else {
165 Err(Error::NotFound(key.into()))
166 }
167 }
168 }
169
170 fn find_var<K: TryInto<Symbol, Error = Error>>(&self, key: K) -> Result<Robj> {
179 let key: Symbol = key.try_into()?;
180 if !self.is_environment() {
181 return Err(Error::NotFound(key.into()));
182 }
183 unsafe {
200 let sexp = self.get();
201 if let Ok(var) = catch_r_error(|| get_var(key.get(), sexp)) {
202 if var != R_UnboundValue {
203 Ok(Robj::from_sexp(var))
204 } else {
205 Err(Error::NotFound(key.into()))
206 }
207 } else {
208 Err(Error::NotFound(key.into()))
209 }
210 }
211 }
212
213 #[cfg(feature = "non-api")]
214 fn eval_promise(&self) -> Result<Robj> {
224 if self.is_promise() {
225 self.as_promise().unwrap().eval()
226 } else {
227 Ok(self.as_robj().clone())
228 }
229 }
230
231 fn ncols(&self) -> usize {
233 unsafe { Rf_ncols(self.get()) as usize }
234 }
235
236 fn nrows(&self) -> usize {
238 unsafe { Rf_nrows(self.get()) as usize }
239 }
240
241 #[doc(hidden)]
243 unsafe fn make_external_ptr<T>(p: *mut T, prot: Robj) -> Robj {
244 let type_name: Robj = std::any::type_name::<T>().into();
245 Robj::from_sexp(single_threaded(|| {
246 R_MakeExternalPtr(
247 p as *mut ::std::os::raw::c_void,
248 type_name.get(),
249 prot.get(),
250 )
251 }))
252 }
253
254 #[doc(hidden)]
256 unsafe fn external_ptr_addr<T>(&self) -> *mut T {
257 R_ExternalPtrAddr(self.get()).cast()
258 }
259
260 #[doc(hidden)]
262 unsafe fn external_ptr_tag(&self) -> Robj {
263 Robj::from_sexp(R_ExternalPtrTag(self.get()))
264 }
265
266 #[doc(hidden)]
268 unsafe fn external_ptr_protected(&self) -> Robj {
269 Robj::from_sexp(R_ExternalPtrProtected(self.get()))
270 }
271
272 #[doc(hidden)]
273 unsafe fn register_c_finalizer(&self, func: R_CFinalizer_t) {
274 single_threaded(|| R_RegisterCFinalizerEx(self.get(), func, Rboolean::TRUE));
277 }
278
279 fn xlengthgets(&self, new_len: usize) -> Result<Robj> {
282 unsafe {
283 if self.is_vector() {
284 Ok(single_threaded(|| {
285 Robj::from_sexp(Rf_xlengthgets(self.get(), new_len as R_xlen_t))
286 }))
287 } else {
288 Err(Error::ExpectedVector(self.as_robj().clone()))
289 }
290 }
291 }
292
293 fn alloc_vector(sexptype: SEXPTYPE, len: usize) -> Robj {
295 single_threaded(|| unsafe { Robj::from_sexp(Rf_allocVector(sexptype, len as R_xlen_t)) })
296 }
297
298 fn conformable(a: &Robj, b: &Robj) -> bool {
300 single_threaded(|| unsafe { Rf_conformable(a.get(), b.get()).into() })
301 }
302
303 fn is_array(&self) -> bool {
305 unsafe { Rf_isArray(self.get()).into() }
306 }
307
308 fn is_factor(&self) -> bool {
310 unsafe { Rf_isFactor(self.get()).into() }
311 }
312
313 fn is_frame(&self) -> bool {
315 unsafe { Rf_isFrame(self.get()).into() }
316 }
317
318 fn is_function(&self) -> bool {
320 unsafe { Rf_isFunction(self.get()).into() }
321 }
322
323 fn is_integer(&self) -> bool {
325 unsafe { Rf_isInteger(self.get()).into() }
326 }
327
328 fn is_language(&self) -> bool {
330 unsafe { Rf_isLanguage(self.get()).into() }
331 }
332
333 fn is_pairlist(&self) -> bool {
335 unsafe { Rf_isList(self.get()).into() }
336 }
337
338 fn is_matrix(&self) -> bool {
340 unsafe { Rf_isMatrix(self.get()).into() }
341 }
342
343 fn is_list(&self) -> bool {
345 unsafe { Rf_isNewList(self.get()).into() }
346 }
347
348 fn is_number(&self) -> bool {
350 unsafe { Rf_isNumber(self.get()).into() }
351 }
352
353 fn is_primitive(&self) -> bool {
355 unsafe { Rf_isPrimitive(self.get()).into() }
356 }
357
358 fn is_ts(&self) -> bool {
360 unsafe { Rf_isTs(self.get()).into() }
361 }
362
363 fn is_user_binop(&self) -> bool {
365 unsafe { Rf_isUserBinop(self.get()).into() }
366 }
367
368 #[cfg(feature = "non-api")]
369 fn is_valid_string(&self) -> bool {
371 unsafe { extendr_ffi::Rf_isValidString(self.get()).into() }
372 }
373
374 #[cfg(feature = "non-api")]
375 fn is_valid_string_f(&self) -> bool {
377 unsafe { extendr_ffi::Rf_isValidStringF(self.get()).into() }
378 }
379
380 fn is_vector(&self) -> bool {
382 unsafe { Rf_isVector(self.get()).into() }
383 }
384
385 fn is_vector_atomic(&self) -> bool {
387 unsafe { Rf_isVectorAtomic(self.get()).into() }
388 }
389
390 fn is_vector_list(&self) -> bool {
392 unsafe { Rf_isVectorList(self.get()).into() }
393 }
394
395 fn is_vectorizable(&self) -> bool {
397 unsafe { Rf_isVectorizable(self.get()).into() }
398 }
399
400 fn is_raw(&self) -> bool {
402 self.rtype() == Rtype::Raw
403 }
404
405 fn is_char(&self) -> bool {
407 self.rtype() == Rtype::Rstr
408 }
409
410 #[doc(hidden)]
413 fn check_external_ptr_type<T>(&self) -> bool {
414 if self.sexptype() == SEXPTYPE::EXTPTRSXP {
415 let tag = unsafe { self.external_ptr_tag() };
416 if tag.as_str() == Some(std::any::type_name::<T>()) {
417 return true;
418 }
419 }
420 false
421 }
422
423 fn is_missing_arg(&self) -> bool {
424 unsafe { self.get() == R_MissingArg }
425 }
426
427 fn is_unbound_value(&self) -> bool {
428 unsafe { self.get() == R_UnboundValue }
429 }
430
431 fn is_package_env(&self) -> bool {
432 unsafe { R_IsPackageEnv(self.get()).into() }
433 }
434
435 fn package_env_name(&self) -> Robj {
436 unsafe { Robj::from_sexp(R_PackageEnvName(self.get())) }
437 }
438
439 fn is_namespace_env(&self) -> bool {
440 unsafe { R_IsNamespaceEnv(self.get()).into() }
441 }
442
443 fn namespace_env_spec(&self) -> Robj {
444 unsafe { Robj::from_sexp(R_NamespaceEnvSpec(self.get())) }
445 }
446
447 fn is_altrep(&self) -> bool {
449 unsafe { ALTREP(self.get()) != 0 }
450 }
451
452 fn is_altinteger(&self) -> bool {
454 unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::INTSXP }
455 }
456
457 fn is_altreal(&self) -> bool {
459 unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::REALSXP }
460 }
461
462 fn is_altlogical(&self) -> bool {
464 unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::LGLSXP }
465 }
466
467 fn is_altraw(&self) -> bool {
469 unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::RAWSXP }
470 }
471
472 fn is_altstring(&self) -> bool {
474 unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::STRSXP }
475 }
476
477 #[cfg(use_r_altlist)]
479 fn is_altlist(&self) -> bool {
480 unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::VECSXP }
481 }
482
483 fn deparse(&self) -> Result<String> {
485 use crate as extendr_api;
486 let strings: Strings = call!("deparse", self.as_robj())?.try_into()?;
487 if strings.len() == 1 {
488 Ok(String::from(strings.elt(0).as_str()))
489 } else {
490 Ok(strings
491 .iter()
492 .map(|s| s.as_str())
493 .collect::<Vec<_>>()
494 .join(""))
495 }
496 }
497}
498
499impl Rinternals for Robj {}