aorist_extendr_api/robj/
into_robj.rs

1use super::*;
2use crate::single_threaded;
3use std::collections::HashMap;
4
5pub(crate) fn str_to_character(s: &str) -> SEXP {
6    unsafe {
7        if s.is_na() {
8            R_NaString
9        } else {
10            Rf_mkCharLen(s.as_ptr() as *const raw::c_char, s.len() as i32)
11        }
12    }
13}
14
15/// Convert a null to an Robj.
16impl From<()> for Robj {
17    fn from(_: ()) -> Self {
18        // Note: we do not need to protect this.
19        unsafe { Robj::Sys(R_NilValue) }
20    }
21}
22
23/// Convert a Result to an Robj. This is used to allow
24/// functions to use the ? operator and return [Result<T>].
25///
26/// Panics if there is an error.
27/// ```
28/// use extendr_api::prelude::*;
29/// fn my_func() -> Result<f64> {
30///     Ok(1.0)
31/// }
32///
33/// test! {
34///     assert_eq!(r!(my_func()), r!(1.0));
35/// }
36/// ```
37impl<T> From<Result<T>> for Robj
38where
39    T: Into<Robj>,
40{
41    fn from(res: Result<T>) -> Self {
42        // Force a panic on error.
43        res.unwrap().into()
44    }
45}
46
47/// Convert an Robj reference into a borrowed Robj.
48impl From<&Robj> for Robj {
49    // Note: we should probably have a much better reference
50    // mechanism as double-free or underprotection is a distinct possibility.
51    fn from(val: &Robj) -> Self {
52        unsafe { new_owned(val.get()) }
53    }
54}
55
56pub trait IntoRobj {
57    fn into_robj(self) -> Robj;
58}
59
60impl<T> IntoRobj for T
61where
62    Robj: From<T>,
63{
64    fn into_robj(self) -> Robj {
65        self.into()
66    }
67}
68
69/// `ToVectorValue` is a trait that allows many different types
70/// to be converted to vectors. It is used as a type parameter
71/// to `collect_robj()`.
72pub trait ToVectorValue {
73    fn sexptype() -> SEXPTYPE {
74        0
75    }
76
77    fn to_real(&self) -> f64
78    where
79        Self: Sized,
80    {
81        0.
82    }
83
84    fn to_integer(&self) -> i32
85    where
86        Self: Sized,
87    {
88        std::i32::MIN
89    }
90
91    fn to_logical(&self) -> i32
92    where
93        Self: Sized,
94    {
95        std::i32::MIN
96    }
97
98    fn to_raw(&self) -> u8
99    where
100        Self: Sized,
101    {
102        0
103    }
104
105    fn to_sexp(&self) -> SEXP
106    where
107        Self: Sized,
108    {
109        unsafe { R_NilValue }
110    }
111}
112
113macro_rules! impl_real_tvv {
114    ($t: ty) => {
115        impl ToVectorValue for $t {
116            fn sexptype() -> SEXPTYPE {
117                REALSXP
118            }
119
120            fn to_real(&self) -> f64 {
121                *self as f64
122            }
123        }
124
125        impl ToVectorValue for &$t {
126            fn sexptype() -> SEXPTYPE {
127                REALSXP
128            }
129
130            fn to_real(&self) -> f64 {
131                **self as f64
132            }
133        }
134
135        impl ToVectorValue for Option<$t> {
136            fn sexptype() -> SEXPTYPE {
137                REALSXP
138            }
139
140            fn to_real(&self) -> f64 {
141                if self.is_some() {
142                    self.unwrap() as f64
143                } else {
144                    unsafe { R_NaReal }
145                }
146            }
147        }
148    };
149}
150
151impl_real_tvv!(f64);
152impl_real_tvv!(f32);
153impl_real_tvv!(usize);
154
155macro_rules! impl_integer_tvv {
156    ($t: ty) => {
157        impl ToVectorValue for $t {
158            fn sexptype() -> SEXPTYPE {
159                INTSXP
160            }
161
162            fn to_integer(&self) -> i32 {
163                *self as i32
164            }
165        }
166
167        impl ToVectorValue for &$t {
168            fn sexptype() -> SEXPTYPE {
169                INTSXP
170            }
171
172            fn to_integer(&self) -> i32 {
173                **self as i32
174            }
175        }
176
177        impl ToVectorValue for Option<$t> {
178            fn sexptype() -> SEXPTYPE {
179                INTSXP
180            }
181
182            fn to_integer(&self) -> i32 {
183                if self.is_some() {
184                    self.unwrap() as i32
185                } else {
186                    unsafe { R_NaInt }
187                }
188            }
189        }
190    };
191}
192
193impl_integer_tvv!(i8);
194impl_integer_tvv!(i16);
195impl_integer_tvv!(i32);
196impl_integer_tvv!(i64);
197impl_integer_tvv!(u8);
198impl_integer_tvv!(u16);
199impl_integer_tvv!(u32);
200impl_integer_tvv!(u64);
201
202macro_rules! impl_str_tvv {
203    ($t: ty) => {
204        impl ToVectorValue for $t {
205            fn sexptype() -> SEXPTYPE {
206                STRSXP
207            }
208
209            fn to_sexp(&self) -> SEXP
210            where
211                Self: Sized,
212            {
213                str_to_character(self.as_ref())
214            }
215        }
216
217        impl ToVectorValue for &$t {
218            fn sexptype() -> SEXPTYPE {
219                STRSXP
220            }
221
222            fn to_sexp(&self) -> SEXP
223            where
224                Self: Sized,
225            {
226                str_to_character(self.as_ref())
227            }
228        }
229
230        impl ToVectorValue for Option<$t> {
231            fn sexptype() -> SEXPTYPE {
232                STRSXP
233            }
234
235            fn to_sexp(&self) -> SEXP
236            where
237                Self: Sized,
238            {
239                if let Some(s) = self {
240                    str_to_character(s.as_ref())
241                } else {
242                    unsafe { R_NaString }
243                }
244            }
245        }
246    };
247}
248
249impl_str_tvv! {&str}
250impl_str_tvv! {String}
251
252impl ToVectorValue for bool {
253    fn sexptype() -> SEXPTYPE {
254        LGLSXP
255    }
256
257    fn to_logical(&self) -> i32
258    where
259        Self: Sized,
260    {
261        *self as i32
262    }
263}
264
265impl ToVectorValue for &bool {
266    fn sexptype() -> SEXPTYPE {
267        LGLSXP
268    }
269
270    fn to_logical(&self) -> i32
271    where
272        Self: Sized,
273    {
274        **self as i32
275    }
276}
277
278impl ToVectorValue for Bool {
279    fn sexptype() -> SEXPTYPE {
280        LGLSXP
281    }
282
283    fn to_logical(&self) -> i32
284    where
285        Self: Sized,
286    {
287        self.0
288    }
289}
290
291impl ToVectorValue for &Bool {
292    fn sexptype() -> SEXPTYPE {
293        LGLSXP
294    }
295
296    fn to_logical(&self) -> i32
297    where
298        Self: Sized,
299    {
300        self.0
301    }
302}
303
304impl ToVectorValue for Option<bool> {
305    fn sexptype() -> SEXPTYPE {
306        LGLSXP
307    }
308
309    fn to_logical(&self) -> i32 {
310        if self.is_some() {
311            self.unwrap() as i32
312        } else {
313            unsafe { R_NaInt }
314        }
315    }
316}
317
318// Not thread safe.
319fn fixed_size_collect<I>(iter: I, len: usize) -> Robj
320where
321    I: Iterator,
322    I: Sized,
323    I::Item: ToVectorValue,
324{
325    single_threaded(|| unsafe {
326        // Length of the vector is known in advance.
327        let sexptype = I::Item::sexptype();
328        if sexptype != 0 {
329            let sexp = Rf_allocVector(sexptype, len as R_xlen_t);
330            ownership::protect(sexp);
331            match sexptype {
332                REALSXP => {
333                    let ptr = REAL(sexp);
334                    for (i, v) in iter.enumerate() {
335                        *ptr.add(i) = v.to_real();
336                    }
337                }
338                INTSXP => {
339                    let ptr = INTEGER(sexp);
340                    for (i, v) in iter.enumerate() {
341                        *ptr.add(i) = v.to_integer();
342                    }
343                }
344                LGLSXP => {
345                    let ptr = LOGICAL(sexp);
346                    for (i, v) in iter.enumerate() {
347                        *ptr.add(i) = v.to_logical();
348                    }
349                }
350                STRSXP => {
351                    for (i, v) in iter.enumerate() {
352                        SET_STRING_ELT(sexp, i as isize, v.to_sexp());
353                    }
354                }
355                _ => {
356                    panic!("unexpected SEXPTYPE in collect_robj");
357                }
358            }
359            Robj::Owned(sexp)
360        } else {
361            Robj::from(())
362        }
363    })
364}
365
366/// Extensions to iterators for R objects including [RobjItertools::collect_robj()].
367pub trait RobjItertools: Iterator {
368    /// Convert a wide range of iterators to Robj.
369    /// ```
370    /// use extendr_api::prelude::*;
371    ///
372    /// test! {
373    /// // Integer iterators.
374    /// let robj = (0..3).collect_robj();
375    /// assert_eq!(robj.as_integer_vector().unwrap(), vec![0, 1, 2]);
376    ///
377    /// // Logical iterators.
378    /// let robj = (0..3).map(|x| x % 2 == 0).collect_robj();
379    /// assert_eq!(robj.as_logical_vector().unwrap(), vec![TRUE, FALSE, TRUE]);
380    ///
381    /// // Numeric iterators.
382    /// let robj = (0..3).map(|x| x as f64).collect_robj();
383    /// assert_eq!(robj.as_real_vector().unwrap(), vec![0., 1., 2.]);
384    ///
385    /// // String iterators.
386    /// let robj = (0..3).map(|x| format!("{}", x)).collect_robj();
387    /// assert_eq!(robj.as_str_vector(), Some(vec!["0", "1", "2"]));
388    /// }
389    /// ```
390    fn collect_robj(self) -> Robj
391    where
392        Self: Iterator,
393        Self: Sized,
394        Self::Item: ToVectorValue,
395    {
396        if let (len, Some(max)) = self.size_hint() {
397            if len == max {
398                return fixed_size_collect(self, len);
399            }
400        }
401        // If the size is indeterminate, create a vector and call recursively.
402        let vec: Vec<_> = self.collect();
403        assert!(vec.iter().size_hint() == (vec.len(), Some(vec.len())));
404        vec.into_iter().collect_robj()
405    }
406}
407
408// Thanks to *pretzelhammer* on stackoverflow for this.
409impl<T> RobjItertools for T where T: Iterator {}
410
411// Scalars which are ToVectorValue
412impl<T> From<T> for Robj
413where
414    T: ToVectorValue,
415{
416    fn from(scalar: T) -> Self {
417        Some(scalar).into_iter().collect_robj()
418    }
419}
420
421// We would love to do a blanket IntoIterator impl.
422// But the matching rules would clash with the above.
423macro_rules! impl_from_iter {
424    ($t: ty) => {
425        impl<'a, T> From<$t> for Robj
426        where
427            Self: 'a,
428            T: Clone + 'a,
429            T: ToVectorValue,
430        {
431            fn from(val: $t) -> Self {
432                val.iter().cloned().collect_robj()
433            }
434        }
435    };
436}
437
438macro_rules! impl_from_into_iter {
439    ($t: ty) => {
440        impl<'a, T> From<$t> for Robj
441        where
442            Self: 'a,
443            T: 'a,
444            &'a T: ToVectorValue,
445        {
446            fn from(val: $t) -> Self {
447                val.into_iter().collect_robj()
448            }
449        }
450    };
451}
452
453macro_rules! impl_from_as_iterator {
454    ($t: ty) => {
455        impl<T> From<$t> for Robj
456        where
457            $t: RobjItertools,
458            <$t as Iterator>::Item: ToVectorValue,
459            T: ToVectorValue,
460        {
461            fn from(val: $t) -> Self {
462                val.collect_robj()
463            }
464        }
465    };
466}
467
468// impl<T> From<Range<T>> for Robj
469// where
470//     Range<T> : RobjItertools,
471//     <Range<T> as Iterator>::Item: ToVectorValue,
472//     T : ToVectorValue
473// {
474//     fn from(val: Range<T>) -> Self {
475//         val.collect_robj()
476//     }
477// }
478
479// Template constants are still unstable in rust.
480impl_from_iter! {[T; 1]}
481impl_from_iter! {[T; 2]}
482impl_from_iter! {[T; 3]}
483impl_from_iter! {[T; 4]}
484impl_from_iter! {[T; 5]}
485impl_from_iter! {[T; 6]}
486impl_from_iter! {[T; 7]}
487impl_from_iter! {[T; 8]}
488impl_from_iter! {[T; 9]}
489impl_from_iter! {[T; 10]}
490impl_from_iter! {[T; 11]}
491impl_from_iter! {[T; 12]}
492impl_from_iter! {[T; 13]}
493impl_from_iter! {[T; 14]}
494impl_from_iter! {[T; 15]}
495impl_from_iter! {[T; 16]}
496impl_from_iter! {[T; 17]}
497impl_from_iter! {[T; 18]}
498impl_from_iter! {[T; 19]}
499impl_from_iter! {Vec<T>}
500
501impl_from_into_iter! {&'a [T]}
502
503impl_from_as_iterator! {Range<T>}
504impl_from_as_iterator! {RangeInclusive<T>}
505
506impl From<Real> for Robj {
507    /// Convert a real iterator into a vector.
508    fn from(val: Real) -> Self {
509        val.collect_robj()
510    }
511}
512
513impl From<Int> for Robj {
514    /// Convert an integer iterator into a vector.
515    fn from(val: Int) -> Self {
516        val.collect_robj()
517    }
518}
519
520impl From<Logical> for Robj {
521    /// Convert a logical iterator into a vector.
522    fn from(val: Logical) -> Self {
523        val.collect_robj()
524    }
525}
526
527impl<'a> From<HashMap<&'a str, Robj>> for Robj {
528    /// Convert a hashmap into a list.
529    fn from(val: HashMap<&'a str, Robj>) -> Self {
530        let res: Robj = List::from_values(val.iter().map(|(_, v)| v)).into();
531        res.set_names(val.into_iter().map(|(k, _)| k)).unwrap()
532    }
533}
534
535impl<'a> From<Vec<Robj>> for Robj {
536    /// Convert a vector of Robj into a list.
537    fn from(val: Vec<Robj>) -> Self {
538        List::from_values(val.iter()).into()
539    }
540}