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