extendr_api/robj/
mod.rs

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