Skip to main content

extendr_api/robj/
mod.rs

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