Skip to main content

extendr_api/wrapper/
wrapper_macros.rs

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