Skip to main content

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}