extendr_api/robj/
mod.rs

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