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