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