use super::*;
use extendr_ffi::{get_closure_body, get_closure_env, get_closure_formals, Rf_lcons};
#[derive(PartialEq, Clone)]
pub struct Function {
pub(crate) robj: Robj,
}
impl Function {
#[cfg(feature = "non-api")]
pub fn from_parts(formals: Pairlist, body: Language, env: Environment) -> Result<Self> {
single_threaded(|| unsafe {
let sexp = extendr_ffi::Rf_allocSExp(SEXPTYPE::CLOSXP);
let robj = Robj::from_sexp(sexp);
extendr_ffi::SET_FORMALS(sexp, formals.get());
extendr_ffi::SET_BODY(sexp, body.get());
extendr_ffi::SET_CLOENV(sexp, env.get());
Ok(Function { robj })
})
}
pub fn call(&self, args: Pairlist) -> Result<Robj> {
single_threaded(|| unsafe {
let call = Robj::from_sexp(Rf_lcons(self.get(), args.get()));
call.eval()
})
}
pub fn formals(&self) -> Option<Pairlist> {
unsafe {
if self.rtype() == Rtype::Function {
let sexp = self.robj.get();
Some(
Robj::from_sexp(get_closure_formals(sexp))
.try_into()
.unwrap(),
)
} else {
None
}
}
}
pub fn body(&self) -> Option<Robj> {
unsafe {
if self.rtype() == Rtype::Function {
let sexp = self.robj.get();
Some(Robj::from_sexp(get_closure_body(sexp)))
} else {
None
}
}
}
pub fn environment(&self) -> Option<Environment> {
unsafe {
if self.rtype() == Rtype::Function {
let sexp = self.robj.get();
Some(
Robj::from_sexp(get_closure_env(sexp))
.try_into()
.expect("Should be an environment"),
)
} else {
None
}
}
}
}
impl std::fmt::Debug for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.deparse().unwrap())
}
}