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