extendr_api/robj/
rinternals.rs1use crate::*;
2
3pub trait Rinternals: Types + Conversions {
7 fn is_null(&self) -> bool {
9 unsafe { Rf_isNull(self.get()).into() }
10 }
11
12 fn is_symbol(&self) -> bool {
14 unsafe { Rf_isSymbol(self.get()).into() }
15 }
16
17 fn is_logical(&self) -> bool {
19 unsafe { Rf_isLogical(self.get()).into() }
20 }
21
22 fn is_real(&self) -> bool {
24 unsafe { Rf_isReal(self.get()).into() }
25 }
26
27 fn is_complex(&self) -> bool {
29 unsafe { Rf_isComplex(self.get()).into() }
30 }
31
32 fn is_expressions(&self) -> bool {
34 unsafe { Rf_isExpression(self.get()).into() }
35 }
36
37 fn is_environment(&self) -> bool {
39 unsafe { Rf_isEnvironment(self.get()).into() }
40 }
41
42 fn is_promise(&self) -> bool {
44 self.sexptype() == SEXPTYPE::PROMSXP
45 }
46
47 fn is_string(&self) -> bool {
49 unsafe { Rf_isString(self.get()).into() }
50 }
51
52 fn is_object(&self) -> bool {
54 unsafe { Rf_isObject(self.get()).into() }
55 }
56
57 fn is_s4(&self) -> bool {
59 unsafe { Rf_isS4(self.get()).into() }
60 }
61
62 fn is_external_pointer(&self) -> bool {
64 self.rtype() == Rtype::ExternalPtr
65 }
66
67 fn get_current_srcref(val: i32) -> Robj {
69 unsafe { Robj::from_sexp(R_GetCurrentSrcref(val as std::ffi::c_int)) }
70 }
71
72 fn get_src_filename(&self) -> Robj {
74 unsafe { Robj::from_sexp(R_GetSrcFilename(self.get())) }
75 }
76
77 fn as_character_vector(&self) -> Robj {
79 unsafe { Robj::from_sexp(Rf_asChar(self.get())) }
80 }
81
82 fn coerce_vector(&self, sexptype: SEXPTYPE) -> Robj {
84 single_threaded(|| unsafe { Robj::from_sexp(Rf_coerceVector(self.get(), sexptype)) })
85 }
86
87 fn pair_to_vector_list(&self) -> Robj {
89 single_threaded(|| unsafe { Robj::from_sexp(Rf_PairToVectorList(self.get())) })
90 }
91
92 fn vector_to_pair_list(&self) -> Robj {
94 single_threaded(|| unsafe { Robj::from_sexp(Rf_VectorToPairList(self.get())) })
95 }
96
97 fn as_character_factor(&self) -> Robj {
99 single_threaded(|| unsafe { Robj::from_sexp(Rf_asCharacterFactor(self.get())) })
100 }
101
102 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 fn duplicate(&self) -> Robj {
110 single_threaded(|| unsafe { Robj::from_sexp(Rf_duplicate(self.get())) })
111 }
112
113 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 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 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 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 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 fn ncols(&self) -> usize {
222 unsafe { Rf_ncols(self.get()) as usize }
223 }
224
225 fn nrows(&self) -> usize {
227 unsafe { Rf_nrows(self.get()) as usize }
228 }
229
230 #[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 #[doc(hidden)]
245 unsafe fn external_ptr_addr<T>(&self) -> *mut T {
246 R_ExternalPtrAddr(self.get()).cast()
247 }
248
249 #[doc(hidden)]
251 unsafe fn external_ptr_tag(&self) -> Robj {
252 Robj::from_sexp(R_ExternalPtrTag(self.get()))
253 }
254
255 #[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 single_threaded(|| R_RegisterCFinalizerEx(self.get(), func, Rboolean::TRUE));
266 }
267
268 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 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 fn conformable(a: &Robj, b: &Robj) -> bool {
289 single_threaded(|| unsafe { Rf_conformable(a.get(), b.get()).into() })
290 }
291
292 fn is_array(&self) -> bool {
294 unsafe { Rf_isArray(self.get()).into() }
295 }
296
297 fn is_factor(&self) -> bool {
299 unsafe { Rf_isFactor(self.get()).into() }
300 }
301
302 fn is_frame(&self) -> bool {
304 unsafe { Rf_isFrame(self.get()).into() }
305 }
306
307 fn is_function(&self) -> bool {
309 unsafe { Rf_isFunction(self.get()).into() }
310 }
311
312 fn is_integer(&self) -> bool {
314 unsafe { Rf_isInteger(self.get()).into() }
315 }
316
317 fn is_language(&self) -> bool {
319 unsafe { Rf_isLanguage(self.get()).into() }
320 }
321
322 fn is_pairlist(&self) -> bool {
324 unsafe { Rf_isList(self.get()).into() }
325 }
326
327 fn is_matrix(&self) -> bool {
329 unsafe { Rf_isMatrix(self.get()).into() }
330 }
331
332 fn is_list(&self) -> bool {
334 unsafe { Rf_isNewList(self.get()).into() }
335 }
336
337 fn is_number(&self) -> bool {
339 unsafe { Rf_isNumber(self.get()).into() }
340 }
341
342 fn is_primitive(&self) -> bool {
344 unsafe { Rf_isPrimitive(self.get()).into() }
345 }
346
347 fn is_ts(&self) -> bool {
349 unsafe { Rf_isTs(self.get()).into() }
350 }
351
352 fn is_user_binop(&self) -> bool {
354 unsafe { Rf_isUserBinop(self.get()).into() }
355 }
356
357 #[cfg(feature = "non-api")]
358 fn is_valid_string(&self) -> bool {
360 unsafe { Rf_isValidString(self.get()).into() }
361 }
362
363 #[cfg(feature = "non-api")]
364 fn is_valid_string_f(&self) -> bool {
366 unsafe { Rf_isValidStringF(self.get()).into() }
367 }
368
369 fn is_vector(&self) -> bool {
371 unsafe { Rf_isVector(self.get()).into() }
372 }
373
374 fn is_vector_atomic(&self) -> bool {
376 unsafe { Rf_isVectorAtomic(self.get()).into() }
377 }
378
379 fn is_vector_list(&self) -> bool {
381 unsafe { Rf_isVectorList(self.get()).into() }
382 }
383
384 fn is_vectorizable(&self) -> bool {
386 unsafe { Rf_isVectorizable(self.get()).into() }
387 }
388
389 fn is_raw(&self) -> bool {
391 self.rtype() == Rtype::Raw
392 }
393
394 fn is_char(&self) -> bool {
396 self.rtype() == Rtype::Rstr
397 }
398
399 #[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 fn is_altrep(&self) -> bool {
438 unsafe { ALTREP(self.get()) != 0 }
439 }
440
441 fn is_altinteger(&self) -> bool {
443 unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::INTSXP }
444 }
445
446 fn is_altreal(&self) -> bool {
448 unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::REALSXP }
449 }
450
451 fn is_altlogical(&self) -> bool {
453 unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::LGLSXP }
454 }
455
456 fn is_altraw(&self) -> bool {
458 unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::RAWSXP }
459 }
460
461 fn is_altstring(&self) -> bool {
463 unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::STRSXP }
464 }
465
466 #[cfg(use_r_altlist)]
468 fn is_altlist(&self) -> bool {
469 unsafe { ALTREP(self.get()) != 0 && TYPEOF(self.get()) == SEXPTYPE::VECSXP }
470 }
471
472 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 {}