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