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