Skip to main content

aorist_extendr_api/wrapper/
mod.rs

1//! Wrappers are lightweight proxies for references to R datatypes.
2//! They do not contain an Robj (see array.rs for an example of this).
3
4use crate::*;
5use libR_sys::*;
6
7pub mod character;
8pub mod environment;
9pub mod expr;
10pub mod function;
11pub mod lang;
12pub mod list;
13pub mod matrix;
14pub mod nullable;
15pub mod pairlist;
16pub mod primitive;
17pub mod promise;
18pub mod raw;
19pub mod symbol;
20
21pub use character::Character;
22pub use environment::{EnvIter, Environment};
23pub use expr::Expression;
24pub use function::Function;
25pub use lang::Language;
26pub use list::{FromList, List, ListIter};
27pub use matrix::{RArray, RColumn, RMatrix, RMatrix3D};
28pub use nullable::Nullable;
29pub use pairlist::{Pairlist, PairlistIter};
30pub use primitive::Primitive;
31pub use promise::Promise;
32pub use raw::Raw;
33pub use symbol::Symbol;
34
35pub(crate) fn make_symbol(name: &str) -> SEXP {
36    let mut bytes = Vec::with_capacity(name.len() + 1);
37    bytes.extend(name.bytes());
38    bytes.push(0);
39    unsafe { Rf_install(bytes.as_ptr() as *const ::std::os::raw::c_char) }
40}
41
42pub(crate) fn make_vector<T>(sexptype: u32, values: T) -> Robj
43where
44    T: IntoIterator,
45    T::IntoIter: ExactSizeIterator,
46    T::Item: Into<Robj>,
47{
48    single_threaded(|| unsafe {
49        let values = values.into_iter();
50        let sexp = Rf_allocVector(sexptype, values.len() as R_xlen_t);
51        ownership::protect(sexp);
52        for (i, val) in values.enumerate() {
53            SET_VECTOR_ELT(sexp, i as R_xlen_t, val.into().get());
54        }
55        Robj::Owned(sexp)
56    })
57}
58
59macro_rules! make_conversions {
60    ($typename: ident, $errname: ident, $isfunc: ident, $errstr: expr) => {
61        impl<'a> FromRobj<'a> for $typename {
62            fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
63                if let Ok(f) = $typename::try_from(robj.clone()) {
64                    Ok(f)
65                } else {
66                    Err($errstr)
67                }
68            }
69        }
70
71        impl From<$typename> for Robj {
72            /// Make an robj from a wrapper.
73            fn from(val: $typename) -> Self {
74                val.robj
75            }
76        }
77
78        impl TryFrom<Robj> for $typename {
79            type Error = crate::Error;
80
81            /// Make a wrapper from a robj if it matches.
82            fn try_from(robj: Robj) -> Result<Self> {
83                if robj.$isfunc() {
84                    Ok($typename { robj })
85                } else {
86                    Err(Error::$errname(robj))
87                }
88            }
89        }
90
91        impl Deref for $typename {
92            type Target = Robj;
93
94            /// Make a wrapper behave like an Robj.
95            fn deref(&self) -> &Self::Target {
96                &self.robj
97            }
98        }
99    };
100}
101
102make_conversions!(Pairlist, ExpectedPairlist, is_pairlist, "Not a pairlist");
103make_conversions!(Function, ExpectedFunction, is_function, "Not a function");
104make_conversions!(Raw, ExpectedRaw, is_raw, "Not a raw object");
105
106make_conversions!(
107    Character,
108    ExpectedCharacter,
109    is_character,
110    "Not a character object"
111);
112
113make_conversions!(
114    Environment,
115    ExpectedEnvironment,
116    is_environment,
117    "Not an Environment"
118);
119
120make_conversions!(List, ExpectedList, is_list, "Not a List");
121
122make_conversions!(
123    Expression,
124    ExpectedExpression,
125    is_expression,
126    "Not an Expression"
127);
128
129make_conversions!(
130    Language,
131    ExpectedLanguage,
132    is_language,
133    "Not a Language object"
134);
135
136make_conversions!(Symbol, ExpectedSymbol, is_symbol, "Not a Symbol object");
137
138make_conversions!(
139    Primitive,
140    ExpectedPrimitive,
141    is_primitive,
142    "Not a Primitive object"
143);
144
145make_conversions!(Promise, ExpectedPromise, is_promise, "Not a Promise object");
146
147impl Robj {
148    /// Convert a symbol object to a Symbol wrapper.
149    /// ```
150    /// use extendr_api::prelude::*;
151    /// test! {
152    ///     let fred = sym!(fred);
153    ///     assert_eq!(fred.as_symbol(), Some(Symbol::from_string("fred")));
154    /// }
155    /// ```
156    pub fn as_symbol(&self) -> Option<Symbol> {
157        Symbol::try_from(self.clone()).ok()
158    }
159
160    /// Convert a character object to a Character wrapper.
161    /// ```
162    /// use extendr_api::prelude::*;
163    /// test! {
164    ///     let fred = r!(Character::from_string("fred"));
165    ///     assert_eq!(fred.as_character(), Some(Character::from_string("fred")));
166    /// }
167    /// ```
168    pub fn as_character(&self) -> Option<Character> {
169        Character::try_from(self.clone()).ok()
170    }
171
172    /// Convert a raw object to a Character wrapper.
173    /// ```
174    /// use extendr_api::prelude::*;
175    /// test! {
176    ///     let bytes = r!(Raw::from_bytes(&[1, 2, 3]));
177    ///     assert_eq!(bytes.len(), 3);
178    ///     assert_eq!(bytes.as_raw(), Some(Raw::from_bytes(&[1, 2, 3])));
179    /// }
180    /// ```
181    pub fn as_raw(&self) -> Option<Raw> {
182        Raw::try_from(self.clone()).ok()
183    }
184
185    /// Convert a language object to a Language wrapper.
186    /// ```
187    /// use extendr_api::prelude::*;
188    /// test! {
189    ///     let call_to_xyz = r!(Language::from_values(&[r!(Symbol::from_string("xyz")), r!(1), r!(2)]));
190    ///     assert_eq!(call_to_xyz.is_language(), true);
191    ///     assert_eq!(call_to_xyz.len(), 3);
192    ///     assert_eq!(format!("{:?}", call_to_xyz), r#"r!(Language::from_values([sym!(xyz), r!(1), r!(2)]))"#);
193    /// }
194    /// ```
195    pub fn as_language(&self) -> Option<Language> {
196        Language::try_from(self.clone()).ok()
197    }
198
199    /// Convert a pair list object (LISTSXP) to a Pairlist wrapper.
200    /// ```
201    /// use extendr_api::prelude::*;
202    /// test! {
203    ///     let names_and_values = vec![("a", r!(1)), ("b", r!(2)), ("", r!(3))];
204    ///     let pairlist = Pairlist::from_pairs(names_and_values);
205    ///     let robj = r!(pairlist.clone());
206    ///     assert_eq!(robj.as_pairlist().unwrap(), pairlist);
207    /// }
208    /// ```
209    pub fn as_pairlist(&self) -> Option<Pairlist> {
210        Pairlist::try_from(self.clone()).ok()
211    }
212
213    /// Convert a list object (VECSXP) to a List wrapper.
214    /// ```
215    /// use extendr_api::prelude::*;
216    /// test! {
217    ///     let list = r!(List::from_values(&[r!(0), r!(1), r!(2)]));
218    ///     assert_eq!(list.is_list(), true);
219    ///     assert_eq!(format!("{:?}", list), r#"r!(List::from_values([r!(0), r!(1), r!(2)]))"#);
220    /// }
221    /// ```
222    pub fn as_list(&self) -> Option<List> {
223        List::try_from(self.clone()).ok()
224    }
225
226    /// Convert an expression object (EXPRSXP) to a Expr wrapper.
227    /// ```
228    /// use extendr_api::prelude::*;
229    /// test! {
230    ///     let expr = r!(Expression::from_values(&[r!(0), r!(1), r!(2)]));
231    ///     assert_eq!(expr.is_expression(), true);
232    ///     assert_eq!(expr.as_expression(), Some(Expression::from_values(vec![r!(0), r!(1), r!(2)])));
233    ///     assert_eq!(format!("{:?}", expr), r#"r!(Expression::from_values([r!(0), r!(1), r!(2)]))"#);
234    /// }
235    /// ```
236    pub fn as_expression(&self) -> Option<Expression> {
237        Expression::try_from(self.clone()).ok()
238    }
239
240    /// Convert an environment object (ENVSXP) to a Env wrapper.
241    /// ```
242    /// use extendr_api::prelude::*;
243    /// test! {
244    ///     let names_and_values = (0..100).map(|i| (format!("n{}", i), i));
245    ///     let env = Environment::from_pairs(global_env(), names_and_values);
246    ///     let expr = env.clone();
247    ///     assert_eq!(expr.len(), 100);
248    ///     let env2 = expr.as_environment().unwrap();
249    ///     assert_eq!(env2.len(), 100);
250    /// }
251    /// ```
252    pub fn as_environment(&self) -> Option<Environment> {
253        Environment::try_from(self.clone()).ok()
254    }
255
256    /// Convert a function object (CLOSXP) to a Function wrapper.
257    /// ```
258    /// use extendr_api::prelude::*;
259    /// test! {
260    ///     let func = R!("function(a,b) a + b").unwrap();
261    ///     println!("{:?}", func.as_function());
262    /// }
263    /// ```
264    pub fn as_function(&self) -> Option<Function> {
265        Function::try_from(self.clone()).ok()
266    }
267
268    /// Get a wrapper for a promise.
269    pub fn as_promise(&self) -> Option<Promise> {
270        Promise::try_from(self.clone()).ok()
271    }
272}
273
274pub trait SymPair {
275    fn sym_pair(self) -> (Option<Robj>, Robj);
276}
277
278impl<S, R> SymPair for (S, R)
279where
280    S: AsRef<str>,
281    R: Into<Robj>,
282{
283    fn sym_pair(self) -> (Option<Robj>, Robj) {
284        let val = self.0.as_ref();
285        // "" represents the absense of the name
286        let nm = if val.is_empty() {
287            None
288        } else {
289            Some(r!(Symbol::from_string(val)))
290        };
291        (nm, self.1.into())
292    }
293}
294
295impl<S, R> SymPair for &(S, R)
296where
297    S: AsRef<str>,
298    R: Into<Robj>,
299    R: Clone,
300{
301    fn sym_pair(self) -> (Option<Robj>, Robj) {
302        let val = self.0.as_ref();
303        let nm = if val.is_empty() {
304            None
305        } else {
306            Some(r!(Symbol::from_string(val)))
307        };
308        (nm, self.1.clone().into())
309    }
310}