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