aorist_extendr_api/wrapper/function.rs
1use super::*;
2
3/// Wrapper for creating functions (CLOSSXP).
4/// ```
5/// use extendr_api::prelude::*;
6/// test! {
7/// let expr = R!("function(a = 1, b) {c <- a + b}").unwrap();
8/// let func = expr.as_function().unwrap();
9///
10/// let expected_formals = Pairlist::from_pairs(vec![("a", r!(1.0)), ("b", missing_arg().into())]);
11/// let expected_body = lang!(
12/// "{", lang!("<-", sym!(c), lang!("+", sym!(a), sym!(b))));
13/// assert_eq!(func.formals().as_pairlist().unwrap(), expected_formals);
14/// assert_eq!(func.body(), expected_body);
15/// assert_eq!(func.environment(), global_env());
16/// }
17/// ```
18#[derive(Debug, PartialEq, Clone)]
19pub struct Function {
20 pub(crate) robj: Robj,
21}
22
23impl Function {
24 /// Make a function from parts.
25 /// ```
26 /// use extendr_api::prelude::*;
27 /// test! {
28 /// let formals = pairlist!(a=NULL);
29 /// let body = lang!("+", sym!(a), r!(1)).try_into()?;
30 /// let env = global_env();
31 /// let f = r!(Function::from_parts(formals, body, env )?);
32 /// assert_eq!(f.call(pairlist!(a=1))?, r!(2));
33 /// }
34 /// ```
35 pub fn from_parts(formals: Pairlist, body: Language, env: Environment) -> Result<Self> {
36 unsafe {
37 let sexp = Rf_allocSExp(CLOSXP);
38 let robj = new_owned(sexp);
39 SET_FORMALS(sexp, formals.get());
40 SET_BODY(sexp, body.get());
41 SET_CLOENV(sexp, env.get());
42 Ok(Function { robj })
43 }
44 }
45
46 /// Do the equivalent of x(a, b, c)
47 /// ```
48 /// use extendr_api::prelude::*;
49 /// test! {
50 /// let function = R!(function(a, b) a + b).unwrap().as_function().unwrap();
51 /// assert_eq!(function.call(pairlist!(a=1, b=2)).unwrap(), r!(3));
52 /// }
53 /// ```
54 pub fn call(&self, args: Pairlist) -> Result<Robj> {
55 self.robj.call(args)
56 }
57
58 /// Get the formal arguments of the function.
59 pub fn formals(&self) -> Pairlist {
60 unsafe {
61 let sexp = self.robj.get();
62 new_owned(FORMALS(sexp)).try_into().unwrap()
63 }
64 }
65
66 /// Get the body of the function.
67 pub fn body(&self) -> Robj {
68 unsafe {
69 let sexp = self.robj.get();
70 new_owned(BODY(sexp))
71 }
72 }
73
74 /// Get the environment of the function.
75 pub fn environment(&self) -> Environment {
76 unsafe {
77 let sexp = self.robj.get();
78 new_owned(CLOENV(sexp))
79 .try_into()
80 .expect("Should be an environment")
81 }
82 }
83}