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