extendr_api/robj/mod.rs
1//! R object handling.
2//!
3//! See. [Writing R Extensions](https://cran.r-project.org/doc/manuals/R-exts.html)
4//!
5//! Fundamental principals:
6//!
7//! * Any function that can break the protection mechanism is unsafe.
8//! * Users should be able to do almost everything without using `libR_sys`.
9//! * The interface should be friendly to R users without Rust experience.
10//!
11
12use std::collections::HashMap;
13use std::iter::IntoIterator;
14use std::ops::{Range, RangeInclusive};
15use std::os::raw;
16
17use extendr_ffi::{
18 dataptr, R_IsNA, R_NilValue, R_compute_identical, R_tryEval, Rboolean, Rcomplex, Rf_getAttrib,
19 Rf_setAttrib, Rf_xlength, COMPLEX, INTEGER, LOGICAL, PRINTNAME, RAW, REAL, SEXPTYPE,
20 SEXPTYPE::*, STRING_ELT, STRING_PTR_RO, TYPEOF, XLENGTH,
21};
22
23use crate::scalar::{Rbool, Rfloat, Rint};
24use crate::*;
25pub use into_robj::*;
26pub use iter::*;
27pub use operators::Operators;
28use prelude::{c64, Rcplx};
29pub use rinternals::Rinternals;
30
31mod debug;
32mod into_robj;
33mod operators;
34mod rinternals;
35mod try_from_robj;
36
37#[cfg(test)]
38mod tests;
39
40/// Wrapper for an R S-expression pointer (SEXP).
41///
42/// Create R objects from rust types and iterators:
43///
44/// ```
45/// use extendr_api::prelude::*;
46/// test! {
47/// // Different ways of making integer scalar 1.
48/// let non_na : Option<i32> = Some(1);
49/// let a : Robj = vec![1].into();
50/// let b = r!(1);
51/// let c = r!(vec![1]);
52/// let d = r!(non_na);
53/// let e = r!([1]);
54/// assert_eq!(a, b);
55/// assert_eq!(a, c);
56/// assert_eq!(a, d);
57/// assert_eq!(a, e);
58///
59/// // Different ways of making boolean scalar TRUE.
60/// let a : Robj = true.into();
61/// let b = r!(TRUE);
62/// assert_eq!(a, b);
63///
64/// // Create a named list
65/// let a = list!(a = 1, b = "x");
66/// assert_eq!(a.len(), 2);
67///
68/// // Use an iterator (like 1:10)
69/// let a = r!(1 ..= 10);
70/// assert_eq!(a, r!([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]));
71///
72/// // Use an iterator (like (1:10)[(1:10) %% 3 == 0])
73/// let a = (1 ..= 10).filter(|v| v % 3 == 0).collect_robj();
74/// assert_eq!(a, r!([3, 6, 9]));
75/// }
76/// ```
77///
78/// Convert to/from Rust vectors.
79///
80/// ```
81/// use extendr_api::prelude::*;
82/// test! {
83/// let a : Robj = r!(vec![1., 2., 3., 4.]);
84/// let b : Vec<f64> = a.as_real_vector().unwrap();
85/// assert_eq!(a.len(), 4);
86/// assert_eq!(b, vec![1., 2., 3., 4.]);
87/// }
88/// ```
89///
90/// Iterate over names and values.
91///
92/// ```
93/// use extendr_api::prelude::*;
94/// test! {
95/// let abc = list!(a = 1, b = "x", c = vec![1, 2]);
96/// let names : Vec<_> = abc.names().unwrap().collect();
97/// let names_and_values : Vec<_> = abc.as_list().unwrap().iter().collect();
98/// assert_eq!(names, vec!["a", "b", "c"]);
99/// assert_eq!(names_and_values, vec![("a", r!(1)), ("b", r!("x")), ("c", r!(vec![1, 2]))]);
100/// }
101/// ```
102///
103/// NOTE: as much as possible we wish to make this object safe (ie. no segfaults).
104///
105/// If you avoid using unsafe functions it is more likely that you will avoid
106/// panics and segfaults. We will take great trouble to ensure that this
107/// is true.
108///
109#[repr(transparent)]
110pub struct Robj {
111 inner: SEXP,
112}
113
114impl Clone for Robj {
115 fn clone(&self) -> Self {
116 unsafe { Robj::from_sexp(self.get()) }
117 }
118}
119
120impl Default for Robj {
121 fn default() -> Self {
122 Robj::null()
123 }
124}
125
126pub trait GetSexp {
127 /// Get a copy of the underlying SEXP.
128 ///
129 /// # Safety
130 ///
131 /// Access to a raw SEXP pointer can cause undefined behaviour and is not thread safe.
132 unsafe fn get(&self) -> SEXP;
133
134 /// # Safety
135 ///
136 /// Access to a raw SEXP pointer can cause undefined behaviour and is not thread safe.
137 unsafe fn get_mut(&mut self) -> SEXP;
138
139 /// Get a reference to a Robj for this type.
140 fn as_robj(&self) -> &Robj;
141
142 /// Get a mutable reference to a Robj for this type.
143 fn as_robj_mut(&mut self) -> &mut Robj;
144}
145
146impl GetSexp for Robj {
147 unsafe fn get(&self) -> SEXP {
148 self.inner
149 }
150
151 unsafe fn get_mut(&mut self) -> SEXP {
152 self.inner
153 }
154
155 fn as_robj(&self) -> &Robj {
156 unsafe { std::mem::transmute(&self.inner) }
157 }
158
159 fn as_robj_mut(&mut self) -> &mut Robj {
160 unsafe { std::mem::transmute(&mut self.inner) }
161 }
162}
163
164pub trait Slices: GetSexp {
165 /// Get an immutable slice to this object's data.
166 ///
167 /// # Safety
168 ///
169 /// Unless the type is correct, this will cause undefined behaviour.
170 /// Creating this slice will also instantiate an Altrep objects.
171 unsafe fn as_typed_slice_raw<T>(&self) -> &[T] {
172 let len = XLENGTH(self.get()) as usize;
173 let data = dataptr(self.get()) as *const T;
174 std::slice::from_raw_parts(data, len)
175 }
176
177 /// Get a mutable slice to this object's data.
178 ///
179 /// # Safety
180 ///
181 /// Unless the type is correct, this will cause undefined behaviour.
182 /// Creating this slice will also instantiate Altrep objects.
183 /// Not all objects (especially not list and strings) support this.
184 unsafe fn as_typed_slice_raw_mut<T>(&mut self) -> &mut [T] {
185 let len = XLENGTH(self.get()) as usize;
186 let data = dataptr(self.get_mut()) as *mut T;
187 std::slice::from_raw_parts_mut(data, len)
188 }
189}
190
191impl Slices for Robj {}
192
193pub trait Length: GetSexp {
194 /// Get the extended length of the object.
195 /// ```
196 /// use extendr_api::prelude::*;
197 /// test! {
198 ///
199 /// let a : Robj = r!(vec![1., 2., 3., 4.]);
200 /// assert_eq!(a.len(), 4);
201 /// }
202 /// ```
203 fn len(&self) -> usize {
204 unsafe { Rf_xlength(self.get()) as usize }
205 }
206
207 /// Returns `true` if the `Robj` contains no elements.
208 /// ```
209 /// use extendr_api::prelude::*;
210 /// test! {
211 ///
212 /// let a : Robj = r!(vec![0.; 0]); // length zero of numeric vector
213 /// assert_eq!(a.is_empty(), true);
214 /// }
215 /// ```
216 fn is_empty(&self) -> bool {
217 self.len() == 0
218 }
219}
220
221impl Length for Robj {}
222
223impl Robj {
224 /// # Safety
225 ///
226 /// This function dereferences a raw SEXP pointer.
227 /// The caller must ensure that `sexp` is a valid SEXP pointer.
228 pub unsafe fn from_sexp(sexp: SEXP) -> Self {
229 single_threaded(|| {
230 unsafe { ownership::protect(sexp) };
231 Robj { inner: sexp }
232 })
233 }
234}
235
236pub trait Types: GetSexp {
237 #[doc(hidden)]
238 /// Get the XXXSXP type of the object.
239 fn sexptype(&self) -> SEXPTYPE {
240 unsafe { TYPEOF(self.get()) }
241 }
242
243 /// Get the type of an R object.
244 /// ```
245 /// use extendr_api::prelude::*;
246 /// test! {
247 /// assert_eq!(Robj::null().rtype(), Rtype::Null);
248 /// assert_eq!(sym!(xyz).rtype(), Rtype::Symbol);
249 /// assert_eq!(r!(Pairlist::from_pairs(vec![("a", r!(1))])).rtype(), Rtype::Pairlist);
250 /// assert_eq!(R!("function() {}")?.rtype(), Rtype::Function);
251 /// assert_eq!(Environment::new_with_parent(Environment::global()).rtype(), Rtype::Environment);
252 /// assert_eq!(lang!("+", 1, 2).rtype(), Rtype::Language);
253 /// assert_eq!(Rstr::from_string("hello").rtype(), Rtype::Rstr);
254 /// assert_eq!(r!(TRUE).rtype(), Rtype::Logicals);
255 /// assert_eq!(r!(1).rtype(), Rtype::Integers);
256 /// assert_eq!(r!(1.0).rtype(), Rtype::Doubles);
257 /// assert_eq!(r!("1").rtype(), Rtype::Strings);
258 /// assert_eq!(r!(List::from_values(&[1, 2])).rtype(), Rtype::List);
259 /// assert_eq!(Expressions::from_str("x + y")?.rtype(), Rtype::Expressions);
260 /// assert_eq!(r!(Raw::from_bytes(&[1_u8, 2, 3])).rtype(), Rtype::Raw);
261 /// }
262 /// ```
263 fn rtype(&self) -> Rtype {
264 use SEXPTYPE::*;
265 match self.sexptype() {
266 NILSXP => Rtype::Null,
267 SYMSXP => Rtype::Symbol,
268 LISTSXP => Rtype::Pairlist,
269 CLOSXP => Rtype::Function,
270 ENVSXP => Rtype::Environment,
271 PROMSXP => Rtype::Promise,
272 LANGSXP => Rtype::Language,
273 SPECIALSXP => Rtype::Special,
274 BUILTINSXP => Rtype::Builtin,
275 CHARSXP => Rtype::Rstr,
276 LGLSXP => Rtype::Logicals,
277 INTSXP => Rtype::Integers,
278 REALSXP => Rtype::Doubles,
279 CPLXSXP => Rtype::Complexes,
280 STRSXP => Rtype::Strings,
281 DOTSXP => Rtype::Dot,
282 ANYSXP => Rtype::Any,
283 VECSXP => Rtype::List,
284 EXPRSXP => Rtype::Expressions,
285 BCODESXP => Rtype::Bytecode,
286 EXTPTRSXP => Rtype::ExternalPtr,
287 WEAKREFSXP => Rtype::WeakRef,
288 RAWSXP => Rtype::Raw,
289 #[cfg(not(use_objsxp))]
290 S4SXP => Rtype::S4,
291 #[cfg(use_objsxp)]
292 OBJSXP => Rtype::S4,
293 _ => Rtype::Unknown,
294 }
295 }
296
297 fn as_any(&self) -> Rany<'_> {
298 use SEXPTYPE::*;
299 unsafe {
300 match self.sexptype() {
301 NILSXP => Rany::Null(self.as_robj()),
302 SYMSXP => Rany::Symbol(std::mem::transmute::<&Robj, &Symbol>(self.as_robj())),
303 LISTSXP => Rany::Pairlist(std::mem::transmute::<&Robj, &Pairlist>(self.as_robj())),
304 CLOSXP => Rany::Function(std::mem::transmute::<&Robj, &Function>(self.as_robj())),
305 ENVSXP => {
306 Rany::Environment(std::mem::transmute::<&Robj, &Environment>(self.as_robj()))
307 }
308 PROMSXP => Rany::Promise(std::mem::transmute::<&Robj, &Promise>(self.as_robj())),
309 LANGSXP => Rany::Language(std::mem::transmute::<&Robj, &Language>(self.as_robj())),
310 SPECIALSXP => {
311 Rany::Special(std::mem::transmute::<&Robj, &Primitive>(self.as_robj()))
312 }
313 BUILTINSXP => {
314 Rany::Builtin(std::mem::transmute::<&Robj, &Primitive>(self.as_robj()))
315 }
316 CHARSXP => Rany::Rstr(std::mem::transmute::<&Robj, &Rstr>(self.as_robj())),
317 LGLSXP => Rany::Logicals(std::mem::transmute::<&Robj, &Logicals>(self.as_robj())),
318 INTSXP => Rany::Integers(std::mem::transmute::<&Robj, &Integers>(self.as_robj())),
319 REALSXP => Rany::Doubles(std::mem::transmute::<&Robj, &Doubles>(self.as_robj())),
320 CPLXSXP => {
321 Rany::Complexes(std::mem::transmute::<&Robj, &Complexes>(self.as_robj()))
322 }
323 STRSXP => Rany::Strings(std::mem::transmute::<&Robj, &Strings>(self.as_robj())),
324 DOTSXP => Rany::Dot(std::mem::transmute::<&Robj, &Robj>(self.as_robj())),
325 ANYSXP => Rany::Any(std::mem::transmute::<&Robj, &Robj>(self.as_robj())),
326 VECSXP => Rany::List(std::mem::transmute::<&Robj, &List>(self.as_robj())),
327 EXPRSXP => {
328 Rany::Expressions(std::mem::transmute::<&Robj, &Expressions>(self.as_robj()))
329 }
330 BCODESXP => Rany::Bytecode(std::mem::transmute::<&Robj, &Robj>(self.as_robj())),
331 EXTPTRSXP => Rany::ExternalPtr(std::mem::transmute::<&Robj, &Robj>(self.as_robj())),
332 WEAKREFSXP => Rany::WeakRef(std::mem::transmute::<&Robj, &Robj>(self.as_robj())),
333 RAWSXP => Rany::Raw(std::mem::transmute::<&Robj, &Raw>(self.as_robj())),
334 #[cfg(not(use_objsxp))]
335 S4SXP => Rany::S4(std::mem::transmute(self.as_robj())),
336 #[cfg(use_objsxp)]
337 OBJSXP => Rany::S4(std::mem::transmute::<&Robj, &S4>(self.as_robj())),
338 _ => Rany::Unknown(std::mem::transmute::<&Robj, &Robj>(self.as_robj())),
339 }
340 }
341 }
342}
343
344impl Types for Robj {}
345
346impl Robj {
347 /// Construct an R `NULL` value.
348 ///
349 /// This is equivalent to `Robj::from(())`, `().into_robj()`, `r!(())`, and `r!(NULL)`.
350 ///
351 /// ```
352 /// use extendr_api::prelude::*;
353 /// test! {
354 /// let null = Robj::null();
355 /// assert_eq!(null, Robj::from(()));
356 /// assert_eq!(null, ().into_robj());
357 /// assert_eq!(null, r!(()));
358 /// assert_eq!(null, r!(NULL));
359 /// }
360 /// ```
361 pub fn null() -> Self {
362 Robj::from(())
363 }
364
365 /// Is this object is an `NA` scalar?
366 /// Works for character, integer and numeric types.
367 ///
368 /// ```
369 /// use extendr_api::prelude::*;
370 /// test! {
371 ///
372 /// assert_eq!(r!(NA_INTEGER).is_na(), true);
373 /// assert_eq!(r!(NA_REAL).is_na(), true);
374 /// assert_eq!(r!(NA_STRING).is_na(), true);
375 /// }
376 /// ```
377 pub fn is_na(&self) -> bool {
378 if self.len() != 1 {
379 false
380 } else {
381 unsafe {
382 let sexp = self.get();
383 use SEXPTYPE::*;
384 match self.sexptype() {
385 STRSXP => STRING_ELT(sexp, 0) == extendr_ffi::R_NaString,
386 INTSXP => *(INTEGER(sexp)) == extendr_ffi::R_NaInt,
387 LGLSXP => *(LOGICAL(sexp)) == extendr_ffi::R_NaInt,
388 REALSXP => R_IsNA(*(REAL(sexp))) != 0,
389 CPLXSXP => R_IsNA((*COMPLEX(sexp)).r) != 0,
390 // a character vector contains `CHARSXP`, and thus you
391 // seldom have `Robj`'s that are `CHARSXP` themselves
392 CHARSXP => sexp == extendr_ffi::R_NaString,
393 _ => false,
394 }
395 }
396 }
397 }
398
399 /// Get a read-only reference to the content of an integer vector.
400 /// ```
401 /// use extendr_api::prelude::*;
402 /// test! {
403 ///
404 /// let robj = r!([1, 2, 3]);
405 /// assert_eq!(robj.as_integer_slice().unwrap(), [1, 2, 3]);
406 /// }
407 /// ```
408 pub fn as_integer_slice<'a>(&self) -> Option<&'a [i32]> {
409 self.as_typed_slice()
410 }
411
412 /// Convert an [`Robj`] into [`Integers`].
413 pub fn as_integers(&self) -> Option<Integers> {
414 self.clone().try_into().ok()
415 }
416
417 /// Get a `Vec<i32>` copied from the object.
418 ///
419 /// ```
420 /// use extendr_api::prelude::*;
421 /// test! {
422 ///
423 /// let robj = r!([1, 2, 3]);
424 /// assert_eq!(robj.as_integer_slice().unwrap(), vec![1, 2, 3]);
425 /// }
426 /// ```
427 pub fn as_integer_vector(&self) -> Option<Vec<i32>> {
428 self.as_integer_slice().map(|value| value.to_vec())
429 }
430
431 /// Get a read-only reference to the content of a logical vector
432 /// using the tri-state [Rbool]. Returns None if not a logical vector.
433 /// ```
434 /// use extendr_api::prelude::*;
435 /// test! {
436 /// let robj = r!([TRUE, FALSE]);
437 /// assert_eq!(robj.as_logical_slice().unwrap(), [TRUE, FALSE]);
438 /// }
439 /// ```
440 pub fn as_logical_slice(&self) -> Option<&[Rbool]> {
441 self.as_typed_slice()
442 }
443
444 /// Get a `Vec<Rbool>` copied from the object
445 /// using the tri-state [`Rbool`].
446 /// Returns `None` if not a logical vector.
447 ///
448 /// ```
449 /// use extendr_api::prelude::*;
450 /// test! {
451 /// let robj = r!([TRUE, FALSE]);
452 /// assert_eq!(robj.as_logical_vector().unwrap(), vec![TRUE, FALSE]);
453 /// }
454 /// ```
455 pub fn as_logical_vector(&self) -> Option<Vec<Rbool>> {
456 self.as_logical_slice().map(|value| value.to_vec())
457 }
458
459 /// Get an iterator over logical elements of this slice.
460 /// ```
461 /// use extendr_api::prelude::*;
462 /// test! {
463 /// let robj = r!([TRUE, FALSE, NA_LOGICAL]);
464 /// let mut num_na = 0;
465 /// for val in robj.as_logical_iter().unwrap() {
466 /// if val.is_na() {
467 /// num_na += 1;
468 /// }
469 /// }
470 /// assert_eq!(num_na, 1);
471 /// }
472 /// ```
473 pub fn as_logical_iter(&self) -> Option<impl Iterator<Item = &Rbool>> {
474 self.as_logical_slice().map(|slice| slice.iter())
475 }
476
477 /// Get a read-only reference to the content of a double vector.
478 /// Note: the slice may contain NaN or NA values.
479 /// We may introduce a "Real" type to handle this like the Rbool type.
480 /// ```
481 /// use extendr_api::prelude::*;
482 /// test! {
483 /// let robj = r!([Some(1.), None, Some(3.)]);
484 /// let mut tot = 0.;
485 /// for val in robj.as_real_slice().unwrap() {
486 /// if !val.is_na() {
487 /// tot += val;
488 /// }
489 /// }
490 /// assert_eq!(tot, 4.);
491 /// }
492 /// ```
493 pub fn as_real_slice(&self) -> Option<&[f64]> {
494 self.as_typed_slice()
495 }
496
497 /// Get an iterator over real elements of this slice.
498 ///
499 /// ```
500 /// use extendr_api::prelude::*;
501 /// test! {
502 /// let robj = r!([1., 2., 3.]);
503 /// let mut tot = 0.;
504 /// for val in robj.as_real_iter().unwrap() {
505 /// if !val.is_na() {
506 /// tot += val;
507 /// }
508 /// }
509 /// assert_eq!(tot, 6.);
510 /// }
511 /// ```
512 pub fn as_real_iter(&self) -> Option<impl Iterator<Item = &f64>> {
513 self.as_real_slice().map(|slice| slice.iter())
514 }
515
516 /// Get a `Vec<f64>` copied from the object.
517 ///
518 /// ```
519 /// use extendr_api::prelude::*;
520 /// test! {
521 /// let robj = r!([1., 2., 3.]);
522 /// assert_eq!(robj.as_real_vector().unwrap(), vec![1., 2., 3.]);
523 /// }
524 /// ```
525 pub fn as_real_vector(&self) -> Option<Vec<f64>> {
526 self.as_real_slice().map(|value| value.to_vec())
527 }
528
529 /// Get a read-only reference to the content of an integer or logical vector.
530 /// ```
531 /// use extendr_api::prelude::*;
532 /// test! {
533 /// let robj = r!(Raw::from_bytes(&[1, 2, 3]));
534 /// assert_eq!(robj.as_raw_slice().unwrap(), &[1, 2, 3]);
535 /// }
536 /// ```
537 pub fn as_raw_slice(&self) -> Option<&[u8]> {
538 self.as_typed_slice()
539 }
540
541 /// Get a read-write reference to the content of an integer or logical vector.
542 /// Note that rust slices are 0-based so `slice[1]` is the middle value.
543 /// ```
544 /// use extendr_api::prelude::*;
545 /// test! {
546 /// let mut robj = r!([1, 2, 3]);
547 /// let slice : & mut [i32] = robj.as_integer_slice_mut().unwrap();
548 /// slice[1] = 100;
549 /// assert_eq!(robj, r!([1, 100, 3]));
550 /// }
551 /// ```
552 pub fn as_integer_slice_mut(&mut self) -> Option<&mut [i32]> {
553 self.as_typed_slice_mut()
554 }
555
556 /// Get a read-write reference to the content of a double vector.
557 /// Note that rust slices are 0-based so `slice[1]` is the middle value.
558 /// ```
559 /// use extendr_api::prelude::*;
560 /// test! {
561 /// let mut robj = r!([1.0, 2.0, 3.0]);
562 /// let slice = robj.as_real_slice_mut().unwrap();
563 /// slice[1] = 100.0;
564 /// assert_eq!(robj, r!([1.0, 100.0, 3.0]));
565 /// }
566 /// ```
567 pub fn as_real_slice_mut(&mut self) -> Option<&mut [f64]> {
568 self.as_typed_slice_mut()
569 }
570
571 /// Get a read-write reference to the content of a raw vector.
572 /// ```
573 /// use extendr_api::prelude::*;
574 /// test! {
575 /// let mut robj = r!(Raw::from_bytes(&[1, 2, 3]));
576 /// let slice = robj.as_raw_slice_mut().unwrap();
577 /// slice[1] = 100;
578 /// assert_eq!(robj, r!(Raw::from_bytes(&[1, 100, 3])));
579 /// }
580 /// ```
581 pub fn as_raw_slice_mut(&mut self) -> Option<&mut [u8]> {
582 self.as_typed_slice_mut()
583 }
584
585 /// Get a vector of owned strings.
586 /// Owned strings have long lifetimes, but are much slower than references.
587 /// ```
588 /// use extendr_api::prelude::*;
589 /// test! {
590 /// let robj1 = Robj::from("xyz");
591 /// assert_eq!(robj1.as_string_vector(), Some(vec!["xyz".to_string()]));
592 /// let robj2 = Robj::from(1);
593 /// assert_eq!(robj2.as_string_vector(), None);
594 /// }
595 /// ```
596 pub fn as_string_vector(&self) -> Option<Vec<String>> {
597 self.as_str_iter()
598 .map(|iter| iter.map(str::to_string).collect())
599 }
600
601 /// Get a vector of string references.
602 /// String references (&str) are faster, but have short lifetimes.
603 /// ```
604 /// use extendr_api::prelude::*;
605 /// test! {
606 /// let robj1 = Robj::from("xyz");
607 /// assert_eq!(robj1.as_str_vector(), Some(vec!["xyz"]));
608 /// let robj2 = Robj::from(1);
609 /// assert_eq!(robj2.as_str_vector(), None);
610 /// }
611 /// ```
612 pub fn as_str_vector(&self) -> Option<Vec<&str>> {
613 self.as_str_iter().map(|iter| iter.collect())
614 }
615
616 /// Get a read-only reference to a scalar string type.
617 /// ```
618 /// use extendr_api::prelude::*;
619 /// test! {
620 /// let robj1 = Robj::from("xyz");
621 /// let robj2 = Robj::from(1);
622 /// assert_eq!(robj1.as_str(), Some("xyz"));
623 /// assert_eq!(robj2.as_str(), None);
624 /// }
625 /// ```
626 pub fn as_str<'a>(&self) -> Option<&'a str> {
627 unsafe {
628 let charsxp = match self.sexptype() {
629 STRSXP => {
630 // only allows scalar strings
631 if self.len() != 1 {
632 return None;
633 }
634 STRING_ELT(self.get(), 0)
635 }
636 CHARSXP => self.get(),
637 SYMSXP => PRINTNAME(self.get()),
638 _ => return None,
639 };
640 rstr::charsxp_to_str(charsxp)
641 }
642 }
643
644 /// Get a scalar integer.
645 /// ```
646 /// use extendr_api::prelude::*;
647 /// test! {
648 /// let robj1 = Robj::from("xyz");
649 /// let robj2 = Robj::from(1);
650 /// let robj3 = Robj::from(NA_INTEGER);
651 /// assert_eq!(robj1.as_integer(), None);
652 /// assert_eq!(robj2.as_integer(), Some(1));
653 /// assert_eq!(robj3.as_integer(), None);
654 /// }
655 /// ```
656 pub fn as_integer(&self) -> Option<i32> {
657 match self.as_integer_slice() {
658 Some(slice) if slice.len() == 1 && !slice[0].is_na() => Some(slice[0]),
659 _ => None,
660 }
661 }
662
663 /// Get a scalar real.
664 /// ```
665 /// use extendr_api::prelude::*;
666 /// test! {
667 /// let robj1 = Robj::from(1);
668 /// let robj2 = Robj::from(1.);
669 /// let robj3 = Robj::from(NA_REAL);
670 /// assert_eq!(robj1.as_real(), None);
671 /// assert_eq!(robj2.as_real(), Some(1.));
672 /// assert_eq!(robj3.as_real(), None);
673 /// }
674 /// ```
675 pub fn as_real(&self) -> Option<f64> {
676 match self.as_real_slice() {
677 Some(slice) if slice.len() == 1 && !slice[0].is_na() => Some(slice[0]),
678 _ => None,
679 }
680 }
681
682 /// Get a scalar rust boolean.
683 /// ```
684 /// use extendr_api::prelude::*;
685 /// test! {
686 /// let robj1 = Robj::from(TRUE);
687 /// let robj2 = Robj::from(1.);
688 /// let robj3 = Robj::from(NA_LOGICAL);
689 /// assert_eq!(robj1.as_bool(), Some(true));
690 /// assert_eq!(robj2.as_bool(), None);
691 /// assert_eq!(robj3.as_bool(), None);
692 /// }
693 /// ```
694 pub fn as_bool(&self) -> Option<bool> {
695 match self.as_logical_slice() {
696 Some(slice) if slice.len() == 1 && !slice[0].is_na() => Some(slice[0].is_true()),
697 _ => None,
698 }
699 }
700
701 /// Get a scalar boolean as a tri-boolean [Rbool] value.
702 /// ```
703 /// use extendr_api::prelude::*;
704 /// test! {
705 /// let robj1 = Robj::from(TRUE);
706 /// let robj2 = Robj::from([TRUE, FALSE]);
707 /// let robj3 = Robj::from(NA_LOGICAL);
708 /// assert_eq!(robj1.as_logical(), Some(TRUE));
709 /// assert_eq!(robj2.as_logical(), None);
710 /// assert_eq!(robj3.as_logical().unwrap().is_na(), true);
711 /// }
712 /// ```
713 pub fn as_logical(&self) -> Option<Rbool> {
714 match self.as_logical_slice() {
715 Some(slice) if slice.len() == 1 => Some(slice[0]),
716 _ => None,
717 }
718 }
719}
720
721pub trait Eval: GetSexp {
722 /// Evaluate the expression in R and return an error or an R object.
723 /// ```
724 /// use extendr_api::prelude::*;
725 /// test! {
726 ///
727 /// let add = lang!("+", 1, 2);
728 /// assert_eq!(add.eval().unwrap(), r!(3));
729 /// }
730 /// ```
731 fn eval(&self) -> Result<Robj> {
732 self.eval_with_env(&Environment::global())
733 }
734
735 /// Evaluate the expression in R and return an error or an R object.
736 /// ```
737 /// use extendr_api::prelude::*;
738 /// test! {
739 ///
740 /// let add = lang!("+", 1, 2);
741 /// assert_eq!(add.eval_with_env(&Environment::global()).unwrap(), r!(3));
742 /// }
743 /// ```
744 fn eval_with_env(&self, env: &Environment) -> Result<Robj> {
745 single_threaded(|| unsafe {
746 let mut error: raw::c_int = 0;
747 let res = R_tryEval(self.get(), env.get(), &mut error as *mut raw::c_int);
748 if error != 0 {
749 Err(Error::EvalError(Robj::from_sexp(self.get())))
750 } else {
751 Ok(Robj::from_sexp(res))
752 }
753 })
754 }
755
756 /// Evaluate the expression and return NULL or an R object.
757 /// ```
758 /// use extendr_api::prelude::*;
759 /// test! {
760 /// let bad = lang!("imnotavalidfunctioninR", 1, 2);
761 /// assert_eq!(bad.eval_blind(), Robj::null());
762 /// }
763 /// ```
764 fn eval_blind(&self) -> Robj {
765 let res = self.eval();
766 if let Ok(robj) = res {
767 robj
768 } else {
769 Robj::null()
770 }
771 }
772}
773
774impl Eval for Robj {}
775
776/// Generic access to typed slices in an Robj.
777pub trait AsTypedSlice<'a, T>
778where
779 Self: 'a,
780{
781 fn as_typed_slice(&self) -> Option<&'a [T]>
782 where
783 Self: 'a,
784 {
785 None
786 }
787
788 fn as_typed_slice_mut(&mut self) -> Option<&'a mut [T]>
789 where
790 Self: 'a,
791 {
792 None
793 }
794}
795
796macro_rules! make_typed_slice {
797 ($type: ty, $fn: tt, $($sexp: tt),* ) => {
798 impl<'a> AsTypedSlice<'a, $type> for Robj
799 where
800 Self : 'a,
801 {
802 fn as_typed_slice(&self) -> Option<&'a [$type]> {
803 match self.sexptype() {
804 $( $sexp )|* => {
805 unsafe {
806 // if the vector is empty return an empty slice
807 if self.is_empty() {
808 return Some(&[])
809 }
810 // otherwise get the slice
811 let ptr = $fn(self.get()) as *const $type;
812 Some(std::slice::from_raw_parts(ptr, self.len()))
813 }
814 }
815 _ => None
816 }
817 }
818
819 fn as_typed_slice_mut(&mut self) -> Option<&'a mut [$type]> {
820 match self.sexptype() {
821 $( $sexp )|* => {
822 unsafe {
823 if self.is_empty() {
824 return Some(&mut []);
825 }
826 let ptr = $fn(self.get_mut()) as *mut $type;
827
828 Some(std::slice::from_raw_parts_mut(ptr, self.len()))
829
830 }
831 }
832 _ => None
833 }
834 }
835 }
836 }
837}
838
839make_typed_slice!(Rbool, INTEGER, LGLSXP);
840make_typed_slice!(i32, INTEGER, INTSXP);
841make_typed_slice!(Rint, INTEGER, INTSXP);
842make_typed_slice!(f64, REAL, REALSXP);
843make_typed_slice!(Rfloat, REAL, REALSXP);
844make_typed_slice!(u8, RAW, RAWSXP);
845make_typed_slice!(Rstr, STRING_PTR_RO, STRSXP);
846make_typed_slice!(c64, COMPLEX, CPLXSXP);
847make_typed_slice!(Rcplx, COMPLEX, CPLXSXP);
848make_typed_slice!(Rcomplex, COMPLEX, CPLXSXP);
849
850/// Provides access to the attributes of an R object.
851///
852/// The `Attribute` trait provides a consistent interface to getting, setting, and checking for the presence of attributes in an R object.
853///
854#[allow(non_snake_case)]
855pub trait Attributes: Types + Length {
856 /// Get a specific attribute as a borrowed `Robj` if it exists.
857 /// ```
858 /// use extendr_api::prelude::*;
859 /// test! {
860 /// let mut robj = r!("hello");
861 /// robj.set_attrib(sym!(xyz), 1);
862 /// assert_eq!(robj.get_attrib(sym!(xyz)), Some(r!(1)));
863 /// }
864 /// ```
865 fn get_attrib<'a, N>(&self, name: N) -> Option<Robj>
866 where
867 Self: 'a,
868 Robj: From<N> + 'a,
869 {
870 let name = Robj::from(name);
871 if self.sexptype() == SEXPTYPE::CHARSXP {
872 None
873 } else {
874 // FIXME: this attribute does not need protection
875 let res = unsafe { Robj::from_sexp(Rf_getAttrib(self.get(), name.get())) };
876 if res.is_null() {
877 None
878 } else {
879 Some(res)
880 }
881 }
882 }
883
884 /// Return true if an attribute exists.
885 fn has_attrib<'a, N>(&self, name: N) -> bool
886 where
887 Self: 'a,
888 Robj: From<N> + 'a,
889 {
890 let name = Robj::from(name);
891 if self.sexptype() == SEXPTYPE::CHARSXP {
892 false
893 } else {
894 unsafe { Rf_getAttrib(self.get(), name.get()) != R_NilValue }
895 }
896 }
897
898 /// Set a specific attribute in-place and return the object.
899 ///
900 /// Note that some combinations of attributes are illegal and this will
901 /// return an error.
902 /// ```
903 /// use extendr_api::prelude::*;
904 /// test! {
905 /// let mut robj = r!("hello");
906 /// robj.set_attrib(sym!(xyz), 1)?;
907 /// assert_eq!(robj.get_attrib(sym!(xyz)), Some(r!(1)));
908 /// }
909 /// ```
910 fn set_attrib<N, V>(&mut self, name: N, value: V) -> Result<&mut Self>
911 where
912 N: Into<Robj>,
913 V: Into<Robj>,
914 {
915 let name = name.into();
916 let value = value.into();
917 unsafe {
918 let sexp = self.get_mut();
919 let result =
920 single_threaded(|| catch_r_error(|| Rf_setAttrib(sexp, name.get(), value.get())));
921 result.map(|_| self)
922 }
923 }
924
925 /// Get the `names` attribute as a string iterator if one exists.
926 /// ```
927 /// use extendr_api::prelude::*;
928 /// test! {
929 /// let list = list!(a = 1, b = 2, c = 3);
930 /// let names : Vec<_> = list.names().unwrap().collect();
931 /// assert_eq!(names, vec!["a", "b", "c"]);
932 /// }
933 /// ```
934 fn names(&self) -> Option<StrIter> {
935 if let Some(names) = self.get_attrib(wrapper::symbol::names_symbol()) {
936 names.as_str_iter()
937 } else {
938 None
939 }
940 }
941
942 /// Return true if this object has an attribute called `names`.
943 fn has_names(&self) -> bool {
944 self.has_attrib(wrapper::symbol::names_symbol())
945 }
946
947 /// Set the `names` attribute from a string iterator.
948 ///
949 /// Returns `Error::NamesLengthMismatch` if the length of the names does
950 /// not match the length of the object.
951 ///
952 /// ```
953 /// use extendr_api::prelude::*;
954 /// test! {
955 /// let mut obj = r!([1, 2, 3]);
956 /// obj.set_names(&["a", "b", "c"]).unwrap();
957 /// assert_eq!(obj.names().unwrap().collect::<Vec<_>>(), vec!["a", "b", "c"]);
958 /// assert_eq!(r!([1, 2, 3]).set_names(&["a", "b"]), Err(Error::NamesLengthMismatch(r!(["a", "b"]))));
959 /// }
960 /// ```
961 fn set_names<T>(&mut self, names: T) -> Result<&mut Self>
962 where
963 T: IntoIterator,
964 T::IntoIter: ExactSizeIterator,
965 T::Item: ToVectorValue + AsRef<str>,
966 {
967 let iter = names.into_iter();
968 let robj = iter.collect_robj();
969 if !robj.is_vector() && !robj.is_pairlist() {
970 Err(Error::ExpectedVector(robj))
971 } else if robj.len() != self.len() {
972 Err(Error::NamesLengthMismatch(robj))
973 } else {
974 self.set_attrib(wrapper::symbol::names_symbol(), robj)
975 }
976 }
977
978 /// Get the `dim` attribute as an integer iterator if one exists.
979 /// ```
980 /// use extendr_api::prelude::*;
981 /// test! {
982 ///
983 /// let array = R!(r#"array(data = c(1, 2, 3, 4), dim = c(2, 2), dimnames = list(c("x", "y"), c("a","b")))"#).unwrap();
984 /// let dim : Vec<_> = array.dim().unwrap().iter().collect();
985 /// assert_eq!(dim, vec![2, 2]);
986 /// }
987 /// ```
988 fn dim(&self) -> Option<Integers> {
989 if let Some(dim) = self.get_attrib(wrapper::symbol::dim_symbol()) {
990 dim.as_integers()
991 } else {
992 None
993 }
994 }
995
996 /// Get the `dimnames` attribute as a list iterator if one exists.
997 /// ```
998 /// use extendr_api::prelude::*;
999 /// test! {
1000 /// let array = R!(r#"array(data = c(1, 2, 3, 4), dim = c(2, 2), dimnames = list(c("x", "y"), c("a","b")))"#).unwrap();
1001 /// let names : Vec<_> = array.dimnames().unwrap().collect();
1002 /// assert_eq!(names, vec![r!(["x", "y"]), r!(["a", "b"])]);
1003 /// }
1004 /// ```
1005 fn dimnames(&self) -> Option<ListIter> {
1006 if let Some(names) = self.get_attrib(wrapper::symbol::dimnames_symbol()) {
1007 names.as_list().map(|v| v.values())
1008 } else {
1009 None
1010 }
1011 }
1012
1013 /// Get the `class` attribute as a string iterator if one exists.
1014 /// ```
1015 /// use extendr_api::prelude::*;
1016 /// test! {
1017 /// let formula = R!("y ~ A * x + b").unwrap();
1018 /// let class : Vec<_> = formula.class().unwrap().collect();
1019 /// assert_eq!(class, ["formula"]);
1020 /// }
1021 /// ```
1022 fn class(&self) -> Option<StrIter> {
1023 if let Some(class) = self.get_attrib(wrapper::symbol::class_symbol()) {
1024 class.as_str_iter()
1025 } else {
1026 None
1027 }
1028 }
1029
1030 /// Set the `class` attribute from a string iterator, and return the same
1031 /// object.
1032 ///
1033 /// May return an error for some class names.
1034 /// ```
1035 /// use extendr_api::prelude::*;
1036 /// test! {
1037 /// let mut obj = r!([1, 2, 3]);
1038 /// obj.set_class(&["a", "b", "c"])?;
1039 /// assert_eq!(obj.class().unwrap().collect::<Vec<_>>(), vec!["a", "b", "c"]);
1040 /// assert_eq!(obj.inherits("a"), true);
1041 /// }
1042 /// ```
1043 fn set_class<T>(&mut self, class: T) -> Result<&mut Self>
1044 where
1045 T: IntoIterator,
1046 T::IntoIter: ExactSizeIterator,
1047 T::Item: ToVectorValue + AsRef<str>,
1048 {
1049 let iter = class.into_iter();
1050 self.set_attrib(wrapper::symbol::class_symbol(), iter.collect_robj())
1051 }
1052
1053 /// Return true if this object has this class attribute.
1054 /// Implicit classes are not supported.
1055 /// ```
1056 /// use extendr_api::prelude::*;
1057 /// test! {
1058 /// let formula = R!("y ~ A * x + b").unwrap();
1059 /// assert_eq!(formula.inherits("formula"), true);
1060 /// }
1061 /// ```
1062 fn inherits(&self, classname: &str) -> bool {
1063 if let Some(mut iter) = self.class() {
1064 iter.any(|n| n == classname)
1065 } else {
1066 false
1067 }
1068 }
1069
1070 /// Get the `levels` attribute as a string iterator if one exists.
1071 /// ```
1072 /// use extendr_api::prelude::*;
1073 /// test! {
1074 /// let factor = factor!(vec!["abcd", "def", "fg", "fg"]);
1075 /// let levels : Vec<_> = factor.levels().unwrap().collect();
1076 /// assert_eq!(levels, vec!["abcd", "def", "fg"]);
1077 /// }
1078 /// ```
1079 fn levels(&self) -> Option<StrIter> {
1080 if let Some(levels) = self.get_attrib(wrapper::symbol::levels_symbol()) {
1081 levels.as_str_iter()
1082 } else {
1083 None
1084 }
1085 }
1086}
1087
1088impl Attributes for Robj {}
1089
1090/// Compare equality with integer slices.
1091impl PartialEq<[i32]> for Robj {
1092 fn eq(&self, rhs: &[i32]) -> bool {
1093 self.as_integer_slice() == Some(rhs)
1094 }
1095}
1096
1097/// Compare equality with slices of double.
1098impl PartialEq<[f64]> for Robj {
1099 fn eq(&self, rhs: &[f64]) -> bool {
1100 self.as_real_slice() == Some(rhs)
1101 }
1102}
1103
1104/// Compare equality with strings.
1105impl PartialEq<str> for Robj {
1106 fn eq(&self, rhs: &str) -> bool {
1107 self.as_str() == Some(rhs)
1108 }
1109}
1110
1111/// Compare equality with two Robjs.
1112impl PartialEq<Robj> for Robj {
1113 fn eq(&self, rhs: &Robj) -> bool {
1114 unsafe {
1115 if self.get() == rhs.get() {
1116 return true;
1117 }
1118
1119 // see https://github.com/hadley/r-internals/blob/master/misc.md
1120 R_compute_identical(self.get(), rhs.get(), 16) != Rboolean::FALSE
1121 }
1122 }
1123}
1124
1125/// Release any owned objects.
1126impl Drop for Robj {
1127 fn drop(&mut self) {
1128 unsafe {
1129 ownership::unprotect(self.inner);
1130 }
1131 }
1132}