extendr_api/wrapper/
wrapper_macros.rs

1use super::*;
2use crate as extendr_api;
3use extendr_ffi::{R_xlen_t, SET_VECTOR_ELT};
4
5pub(crate) fn make_symbol(name: &str) -> SEXP {
6    let name = CString::new(name).unwrap();
7    unsafe { extendr_ffi::Rf_install(name.as_ptr()) }
8}
9
10pub(crate) fn make_vector<T>(sexptype: SEXPTYPE, values: T) -> Robj
11where
12    T: IntoIterator,
13    T::IntoIter: ExactSizeIterator,
14    T::Item: Into<Robj>,
15{
16    single_threaded(|| unsafe {
17        let values = values.into_iter();
18        let mut res = Robj::alloc_vector(sexptype, values.len());
19        let sexp = res.get_mut();
20        for (i, val) in values.enumerate() {
21            SET_VECTOR_ELT(sexp, i as R_xlen_t, val.into().get());
22        }
23        res
24    })
25}
26
27macro_rules! make_conversions {
28    ($typename: ident, $errname: ident, $isfunc: ident, $errstr: expr) => {
29        impl From<$typename> for Robj {
30            /// Make an robj from a wrapper.
31            fn from(val: $typename) -> Self {
32                val.robj
33            }
34        }
35
36        // We can convert a reference to any wrapper to a Robj by cloning the robj pointer
37        impl From<&$typename> for Robj {
38            /// Make an robj from a wrapper.
39            fn from(val: &$typename) -> Self {
40                val.robj.to_owned()
41            }
42        }
43
44        impl TryFrom<&Robj> for $typename {
45            type Error = crate::Error;
46
47            /// Make a wrapper from a robj if it matches.
48            fn try_from(robj: &Robj) -> Result<Self> {
49                if robj.$isfunc() {
50                    Ok($typename { robj: robj.clone() })
51                } else {
52                    Err(Error::$errname(robj.clone()))
53                }
54            }
55        }
56
57        impl TryFrom<Robj> for $typename {
58            type Error = crate::Error;
59
60            /// Make a wrapper from a robj if it matches.
61            fn try_from(robj: Robj) -> Result<Self> {
62                <$typename>::try_from(&robj)
63            }
64        }
65
66        make_getsexp!($typename, impl);
67    };
68}
69
70macro_rules! make_getsexp {
71    ($typename: ty, $($impl : tt)*) => {
72        $($impl)* GetSexp for $typename {
73            unsafe fn get(&self) -> SEXP {
74                self.robj.get()
75            }
76
77            unsafe fn get_mut(&mut self) -> SEXP {
78                self.robj.get_mut()
79            }
80
81            fn as_robj(&self) -> &Robj {
82                &self.robj
83            }
84
85            fn as_robj_mut(&mut self) -> &mut Robj {
86                &mut self.robj
87            }
88        }
89
90        // These traits all derive from GetSexp
91
92        /// len() and is_empty()
93        $($impl)* Length for $typename {}
94
95        /// rtype() and rany()
96        $($impl)* Types for $typename {}
97
98        /// as_*()
99        $($impl)* Conversions for $typename {}
100
101        /// find_var() etc.
102        $($impl)* Rinternals for $typename {}
103
104        /// as_typed_slice_raw() etc.
105        $($impl)* Slices for $typename {}
106
107        /// dollar() etc.
108        $($impl)* Operators for $typename {}
109    };
110}
111
112make_conversions!(Pairlist, ExpectedPairlist, is_pairlist, "Not a pairlist");
113
114make_conversions!(
115    Function,
116    ExpectedFunction,
117    is_function,
118    "Not a function or primitive."
119);
120
121make_conversions!(Raw, ExpectedRaw, is_raw, "Not a raw object");
122
123make_conversions!(
124    Environment,
125    ExpectedEnvironment,
126    is_environment,
127    "Not an Environment"
128);
129
130make_conversions!(List, ExpectedList, is_list, "Not a List");
131
132make_conversions!(
133    Expressions,
134    ExpectedExpression,
135    is_expressions,
136    "Not an Expression"
137);
138
139make_conversions!(
140    Language,
141    ExpectedLanguage,
142    is_language,
143    "Not a Language object"
144);
145
146make_conversions!(Symbol, ExpectedSymbol, is_symbol, "Not a Symbol object");
147
148make_conversions!(
149    Primitive,
150    ExpectedPrimitive,
151    is_primitive,
152    "Not a Primitive object"
153);
154
155make_conversions!(Promise, ExpectedPromise, is_promise, "Not a Promise object");
156
157make_conversions!(Altrep, ExpectedAltrep, is_altrep, "Not an Altrep type");
158
159make_conversions!(S4, ExpectedS4, is_s4, "Not a S4 type");
160
161make_conversions!(Integers, ExpectedInteger, is_integer, "Not an integer type");
162make_conversions!(Logicals, ExpectedLogical, is_logical, "Not a logical type");
163make_conversions!(Doubles, ExpectedReal, is_real, "Not a floating point type");
164make_conversions!(
165    Complexes,
166    ExpectedComplex,
167    is_complex,
168    "Not a complex number or vector"
169);
170// make_conversions!(Function, ExpectedFunction, is_function, "Not a function");
171
172make_conversions!(Strings, ExpectedString, is_string, "Not a string vector");
173
174make_getsexp!(Dataframe<T>, impl<T>);
175
176// impl Deref for Integers {
177//     type Target = [Rint];
178
179//     fn deref(&self) -> &Self::Target {
180//         unsafe { self.as_typed_slice_raw() }
181//     }
182// }
183
184pub trait Conversions: GetSexp {
185    /// Convert a symbol object to a Symbol wrapper.
186    /// ```
187    /// use extendr_api::prelude::*;
188    /// test! {
189    ///     let fred = sym!(fred);
190    ///     assert_eq!(fred.as_symbol(), Some(Symbol::from_string("fred")));
191    /// }
192    /// ```
193    fn as_symbol(&self) -> Option<Symbol> {
194        Symbol::try_from(self.as_robj()).ok()
195    }
196
197    /// Convert a `CHARSXP` object to a `Rstr` wrapper.
198    /// ```
199    /// use extendr_api::prelude::*;
200    /// test! {
201    ///     let fred = Rstr::from_string("fred");
202    ///     assert_eq!(fred.as_char(), Some(Rstr::from_string("fred")));
203    /// }
204    /// ```
205    fn as_char(&self) -> Option<Rstr> {
206        Rstr::try_from(self.as_robj()).ok()
207    }
208
209    /// Convert a raw object to a Rstr wrapper.
210    /// ```
211    /// use extendr_api::prelude::*;
212    /// test! {
213    ///     let bytes = r!(Raw::from_bytes(&[1, 2, 3]));
214    ///     assert_eq!(bytes.len(), 3);
215    ///     assert_eq!(bytes.as_raw(), Some(Raw::from_bytes(&[1, 2, 3])));
216    /// }
217    /// ```
218    fn as_raw(&self) -> Option<Raw> {
219        Raw::try_from(self.as_robj()).ok()
220    }
221
222    /// Convert a language object to a Language wrapper.
223    /// ```
224    /// use extendr_api::prelude::*;
225    /// test! {
226    ///     let call_to_xyz = r!(Language::from_values(&[r!(Symbol::from_string("xyz")), r!(1), r!(2)]));
227    ///     assert_eq!(call_to_xyz.is_language(), true);
228    ///     assert_eq!(call_to_xyz.len(), 3);
229    /// }
230    /// ```
231    fn as_language(&self) -> Option<Language> {
232        Language::try_from(self.as_robj()).ok()
233    }
234
235    /// Convert a pair list object (LISTSXP) to a Pairlist wrapper.
236    /// ```
237    /// use extendr_api::prelude::*;
238    /// test! {
239    ///     let names_and_values = vec![("a", r!(1)), ("b", r!(2)), ("", r!(3))];
240    ///     let pairlist = Pairlist::from_pairs(names_and_values);
241    ///     let robj = r!(pairlist.clone());
242    ///     assert_eq!(robj.as_pairlist().unwrap(), pairlist);
243    /// }
244    /// ```
245    fn as_pairlist(&self) -> Option<Pairlist> {
246        Pairlist::try_from(self.as_robj()).ok()
247    }
248
249    /// Convert a list object (VECSXP) to a List wrapper.
250    /// ```
251    /// use extendr_api::prelude::*;
252    /// test! {
253    ///     let list = r!(List::from_values(&[r!(0), r!(1), r!(2)]));
254    ///     assert_eq!(list.is_list(), true);
255    /// }
256    /// ```
257    fn as_list(&self) -> Option<List> {
258        List::try_from(self.as_robj()).ok()
259    }
260
261    /// Convert an expression object (EXPRSXP) to a Expr wrapper.
262    /// ```
263    /// use extendr_api::prelude::*;
264    /// test! {
265    ///     let expr = r!(Expressions::from_values(&[r!(0), r!(1), r!(2)]));
266    ///     assert_eq!(expr.is_expressions(), true);
267    ///     assert_eq!(expr.as_expressions(), Some(Expressions::from_values(vec![r!(0), r!(1), r!(2)])));
268    /// }
269    /// ```
270    fn as_expressions(&self) -> Option<Expressions> {
271        Expressions::try_from(self.as_robj()).ok()
272    }
273
274    /// Convert an environment object (ENVSXP) to a Env wrapper.
275    /// ```
276    /// use extendr_api::prelude::*;
277    /// test! {
278    ///     let names_and_values = (0..100).map(|i| (format!("n{}", i), i));
279    ///     let env = Environment::from_pairs(global_env(), names_and_values);
280    ///     let expr = env.clone();
281    ///     assert_eq!(expr.len(), 100);
282    ///     let env2 = expr.as_environment().unwrap();
283    ///     assert_eq!(env2.len(), 100);
284    /// }
285    /// ```
286    fn as_environment(&self) -> Option<Environment> {
287        Environment::try_from(self.as_robj()).ok()
288    }
289
290    /// Convert a function object (CLOSXP) to a Function wrapper.
291    /// ```
292    /// use extendr_api::prelude::*;
293    /// test! {
294    ///     let func = R!("function(a,b) a + b").unwrap();
295    ///     println!("{:?}", func.as_function());
296    /// }
297    /// ```
298    fn as_function(&self) -> Option<Function> {
299        Function::try_from(self.as_robj()).ok()
300    }
301
302    /// Get a wrapper for a promise.
303    fn as_promise(&self) -> Option<Promise> {
304        Promise::try_from(self.as_robj()).ok()
305    }
306}
307
308impl Conversions for Robj {}
309
310pub trait SymPair {
311    fn sym_pair(self) -> (Option<Robj>, Robj);
312}
313
314impl<S, R> SymPair for (S, R)
315where
316    S: AsRef<str>,
317    R: Into<Robj>,
318{
319    fn sym_pair(self) -> (Option<Robj>, Robj) {
320        let val = self.0.as_ref();
321        // "" represents the absense of the name
322        let nm = if val.is_empty() {
323            None
324        } else {
325            Some(r!(Symbol::from_string(val)))
326        };
327        (nm, self.1.into())
328    }
329}
330
331impl<S, R> SymPair for &(S, R)
332where
333    S: AsRef<str>,
334    R: Into<Robj>,
335    R: Clone,
336{
337    fn sym_pair(self) -> (Option<Robj>, Robj) {
338        use crate as extendr_api;
339        let val = self.0.as_ref();
340        let nm = if val.is_empty() {
341            None
342        } else {
343            Some(r!(Symbol::from_string(val)))
344        };
345        (nm, self.1.clone().into())
346    }
347}