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!(Rstr, ExpectedRstr, is_char, "Not a character object");
124
125make_conversions!(
126    Environment,
127    ExpectedEnvironment,
128    is_environment,
129    "Not an Environment"
130);
131
132make_conversions!(List, ExpectedList, is_list, "Not a List");
133
134make_conversions!(
135    Expressions,
136    ExpectedExpression,
137    is_expressions,
138    "Not an Expression"
139);
140
141make_conversions!(
142    Language,
143    ExpectedLanguage,
144    is_language,
145    "Not a Language object"
146);
147
148make_conversions!(Symbol, ExpectedSymbol, is_symbol, "Not a Symbol object");
149
150make_conversions!(
151    Primitive,
152    ExpectedPrimitive,
153    is_primitive,
154    "Not a Primitive object"
155);
156
157make_conversions!(Promise, ExpectedPromise, is_promise, "Not a Promise object");
158
159make_conversions!(Altrep, ExpectedAltrep, is_altrep, "Not an Altrep type");
160
161make_conversions!(S4, ExpectedS4, is_s4, "Not a S4 type");
162
163make_conversions!(Integers, ExpectedInteger, is_integer, "Not an integer type");
164make_conversions!(Logicals, ExpectedLogical, is_logical, "Not a logical type");
165make_conversions!(Doubles, ExpectedReal, is_real, "Not a floating point type");
166make_conversions!(
167    Complexes,
168    ExpectedComplex,
169    is_complex,
170    "Not a complex number or vector"
171);
172// make_conversions!(Function, ExpectedFunction, is_function, "Not a function");
173
174make_conversions!(Strings, ExpectedString, is_string, "Not a string vector");
175
176make_getsexp!(Dataframe<T>, impl<T>);
177
178// impl Deref for Integers {
179//     type Target = [Rint];
180
181//     fn deref(&self) -> &Self::Target {
182//         unsafe { self.as_typed_slice_raw() }
183//     }
184// }
185
186pub trait Conversions: GetSexp {
187    /// Convert a symbol object to a Symbol wrapper.
188    /// ```
189    /// use extendr_api::prelude::*;
190    /// test! {
191    ///     let fred = sym!(fred);
192    ///     assert_eq!(fred.as_symbol(), Some(Symbol::from_string("fred")));
193    /// }
194    /// ```
195    fn as_symbol(&self) -> Option<Symbol> {
196        Symbol::try_from(self.as_robj()).ok()
197    }
198
199    /// Convert a `CHARSXP` object to a `Rstr` wrapper.
200    /// ```
201    /// use extendr_api::prelude::*;
202    /// test! {
203    ///     let fred = Rstr::from_string("fred");
204    ///     assert_eq!(fred.as_char(), Some(Rstr::from_string("fred")));
205    /// }
206    /// ```
207    fn as_char(&self) -> Option<Rstr> {
208        Rstr::try_from(self.as_robj()).ok()
209    }
210
211    /// Convert a raw object to a Rstr wrapper.
212    /// ```
213    /// use extendr_api::prelude::*;
214    /// test! {
215    ///     let bytes = r!(Raw::from_bytes(&[1, 2, 3]));
216    ///     assert_eq!(bytes.len(), 3);
217    ///     assert_eq!(bytes.as_raw(), Some(Raw::from_bytes(&[1, 2, 3])));
218    /// }
219    /// ```
220    fn as_raw(&self) -> Option<Raw> {
221        Raw::try_from(self.as_robj()).ok()
222    }
223
224    /// Convert a language object to a Language wrapper.
225    /// ```
226    /// use extendr_api::prelude::*;
227    /// test! {
228    ///     let call_to_xyz = r!(Language::from_values(&[r!(Symbol::from_string("xyz")), r!(1), r!(2)]));
229    ///     assert_eq!(call_to_xyz.is_language(), true);
230    ///     assert_eq!(call_to_xyz.len(), 3);
231    /// }
232    /// ```
233    fn as_language(&self) -> Option<Language> {
234        Language::try_from(self.as_robj()).ok()
235    }
236
237    /// Convert a pair list object (LISTSXP) to a Pairlist wrapper.
238    /// ```
239    /// use extendr_api::prelude::*;
240    /// test! {
241    ///     let names_and_values = vec![("a", r!(1)), ("b", r!(2)), ("", r!(3))];
242    ///     let pairlist = Pairlist::from_pairs(names_and_values);
243    ///     let robj = r!(pairlist.clone());
244    ///     assert_eq!(robj.as_pairlist().unwrap(), pairlist);
245    /// }
246    /// ```
247    fn as_pairlist(&self) -> Option<Pairlist> {
248        Pairlist::try_from(self.as_robj()).ok()
249    }
250
251    /// Convert a list object (VECSXP) to a List wrapper.
252    /// ```
253    /// use extendr_api::prelude::*;
254    /// test! {
255    ///     let list = r!(List::from_values(&[r!(0), r!(1), r!(2)]));
256    ///     assert_eq!(list.is_list(), true);
257    /// }
258    /// ```
259    fn as_list(&self) -> Option<List> {
260        List::try_from(self.as_robj()).ok()
261    }
262
263    /// Convert an expression object (EXPRSXP) to a Expr wrapper.
264    /// ```
265    /// use extendr_api::prelude::*;
266    /// test! {
267    ///     let expr = r!(Expressions::from_values(&[r!(0), r!(1), r!(2)]));
268    ///     assert_eq!(expr.is_expressions(), true);
269    ///     assert_eq!(expr.as_expressions(), Some(Expressions::from_values(vec![r!(0), r!(1), r!(2)])));
270    /// }
271    /// ```
272    fn as_expressions(&self) -> Option<Expressions> {
273        Expressions::try_from(self.as_robj()).ok()
274    }
275
276    /// Convert an environment object (ENVSXP) to a Env wrapper.
277    /// ```
278    /// use extendr_api::prelude::*;
279    /// test! {
280    ///     let names_and_values = (0..100).map(|i| (format!("n{}", i), i));
281    ///     let env = Environment::from_pairs(global_env(), names_and_values);
282    ///     let expr = env.clone();
283    ///     assert_eq!(expr.len(), 100);
284    ///     let env2 = expr.as_environment().unwrap();
285    ///     assert_eq!(env2.len(), 100);
286    /// }
287    /// ```
288    fn as_environment(&self) -> Option<Environment> {
289        Environment::try_from(self.as_robj()).ok()
290    }
291
292    /// Convert a function object (CLOSXP) to a Function wrapper.
293    /// ```
294    /// use extendr_api::prelude::*;
295    /// test! {
296    ///     let func = R!("function(a,b) a + b").unwrap();
297    ///     println!("{:?}", func.as_function());
298    /// }
299    /// ```
300    fn as_function(&self) -> Option<Function> {
301        Function::try_from(self.as_robj()).ok()
302    }
303
304    /// Get a wrapper for a promise.
305    fn as_promise(&self) -> Option<Promise> {
306        Promise::try_from(self.as_robj()).ok()
307    }
308}
309
310impl Conversions for Robj {}
311
312pub trait SymPair {
313    fn sym_pair(self) -> (Option<Robj>, Robj);
314}
315
316impl<S, R> SymPair for (S, R)
317where
318    S: AsRef<str>,
319    R: Into<Robj>,
320{
321    fn sym_pair(self) -> (Option<Robj>, Robj) {
322        let val = self.0.as_ref();
323        // "" represents the absense of the name
324        let nm = if val.is_empty() {
325            None
326        } else {
327            Some(r!(Symbol::from_string(val)))
328        };
329        (nm, self.1.into())
330    }
331}
332
333impl<S, R> SymPair for &(S, R)
334where
335    S: AsRef<str>,
336    R: Into<Robj>,
337    R: Clone,
338{
339    fn sym_pair(self) -> (Option<Robj>, Robj) {
340        use crate as extendr_api;
341        let val = self.0.as_ref();
342        let nm = if val.is_empty() {
343            None
344        } else {
345            Some(r!(Symbol::from_string(val)))
346        };
347        (nm, self.1.clone().into())
348    }
349}