Skip to main content

aorist_extendr_api/
functions.rs

1use crate::*;
2
3/// Get a global variable from global_env() and ancestors.
4/// If the result is a promise, evaulate the promise.
5///
6/// See also [global_var()].
7/// ```
8/// use extendr_api::prelude::*;
9/// test! {
10///    let iris = global_var(sym!(iris))?;
11///    assert_eq!(iris.len(), 5);
12/// }
13/// ```
14pub fn global_var<K: Into<Robj>>(key: K) -> Result<Robj> {
15    let key = key.into();
16    global_env().find_var(key)?.eval_promise()
17}
18
19/// Get a local variable from current_env() and ancestors.
20///
21/// If the result is a promise, evaulate the promise.
22/// The result will come from the calling environment
23/// of an R function which will enable you to use variables
24/// from the caller.
25///
26/// See also [var!].
27///
28/// Note that outside of R, current_env() will be base_env()
29/// and cannot be modified.
30///
31/// ```no_run
32/// use extendr_api::prelude::*;
33/// test! {
34///    current_env().set_local(sym!(my_var), 1);
35///    assert_eq!(local_var(sym!(my_var))?, r!(1));
36/// }
37/// ```
38pub fn local_var<K: Into<Robj>>(key: K) -> Result<Robj> {
39    let key = key.into();
40    current_env().find_var(key)?.eval_promise()
41}
42
43/// Get a global function from global_env() and ancestors.
44/// ```
45/// use extendr_api::prelude::*;
46/// test! {
47///     let ls = global_function(sym!(ls))?;
48///     assert_eq!(ls.is_function(), true);
49/// }
50/// ```
51pub fn global_function<K: Into<Robj>>(key: K) -> Result<Robj> {
52    let key = key.into();
53    global_env().find_function(key)
54}
55
56/// Find a namespace by name.
57///
58/// See also [Robj::double_colon].
59/// ```
60/// use extendr_api::prelude::*;
61/// test! {
62///    assert_eq!(find_namespace("base").is_ok(), true);
63///    assert_eq!(find_namespace("stats").is_ok(), true);
64/// }
65/// ```
66pub fn find_namespace<K: Into<Robj>>(key: K) -> Result<Environment> {
67    let key = key.into();
68    let res = single_threaded(|| call!(".getNamespace", key.clone()));
69    if let Ok(res) = res {
70        Ok(res.try_into()?)
71    } else {
72        Err(Error::NamespaceNotFound(key))
73    }
74}
75
76/// The current interpreter environment.
77///
78/// ```
79/// use extendr_api::prelude::*;
80/// test! {
81///    assert_eq!(current_env(), base_env());
82/// }
83/// ```
84pub fn current_env() -> Environment {
85    unsafe { new_owned(R_GetCurrentEnv()).try_into().unwrap() }
86}
87
88/// The "global" environment
89///
90/// ```
91/// use extendr_api::prelude::*;
92/// test! {
93///     global_env().set_local(sym!(x), "hello");
94///     assert_eq!(global_env().local(sym!(x)), Ok(r!("hello")));
95/// }
96/// ```
97pub fn global_env() -> Environment {
98    unsafe { new_sys(R_GlobalEnv).try_into().unwrap() }
99}
100
101/// An empty environment at the root of the environment tree
102pub fn empty_env() -> Environment {
103    unsafe { new_sys(R_EmptyEnv).try_into().unwrap() }
104}
105
106/// The base environment; formerly R_NilValue
107///
108/// ```
109/// use extendr_api::prelude::*;
110/// test! {
111///     global_env().set_local(sym!(x), "hello");
112///     assert_eq!(base_env().local(sym!(+)), Ok(r!(Primitive::from_string("+"))));
113/// }
114/// ```
115pub fn base_env() -> Environment {
116    unsafe { new_sys(R_BaseEnv).try_into().unwrap() }
117}
118
119/// The namespace for base.
120///
121/// ```
122/// use extendr_api::prelude::*;
123/// test! {
124///    assert_eq!(base_namespace().parent().ok_or("no parent")?, global_env());
125/// }
126/// ```
127pub fn base_namespace() -> Environment {
128    unsafe { new_sys(R_BaseNamespace).try_into().unwrap() }
129}
130
131/// For registered namespaces.
132///
133/// ```
134/// use extendr_api::prelude::*;
135/// test! {
136///    assert_eq!(namespace_registry().is_environment(), true);
137/// }
138/// ```
139pub fn namespace_registry() -> Environment {
140    unsafe { new_sys(R_NamespaceRegistry).try_into().unwrap() }
141}
142
143/// Current srcref, for debuggers
144pub fn srcref() -> Robj {
145    unsafe { new_sys(R_Srcref) }
146}
147
148/// The nil object
149pub fn nil_value() -> Robj {
150    unsafe { new_sys(R_NilValue) }
151}
152
153/* fix version issues.
154/// ".Generic"
155pub fn dot_Generic() -> Robj { unsafe { new_sys(R_dot_Generic) }}
156*/
157
158/// NA_STRING as a CHARSXP
159pub fn na_string() -> Robj {
160    unsafe { new_sys(R_NaString) }
161}
162
163/// "" as a CHARSXP
164pub fn blank_string() -> Robj {
165    unsafe { new_sys(R_BlankString) }
166}
167
168/// "" as a STRSXP
169pub fn blank_scalar_string() -> Robj {
170    unsafe { new_sys(R_BlankScalarString) }
171}
172
173/// Special "NA" string that represents null strings.
174/// ```
175/// use extendr_api::prelude::*;
176/// test! {
177///     assert!(na_str().as_ptr() != "NA".as_ptr());
178///     assert_eq!(na_str(), "NA");
179///     assert_eq!("NA".is_na(), false);
180///     assert_eq!(na_str().is_na(), true);
181/// }
182/// ```
183pub fn na_str() -> &'static str {
184    unsafe { std::str::from_utf8_unchecked(&[b'N', b'A']) }
185}
186
187/// Parse a string into an R executable object
188/// ```
189/// use extendr_api::prelude::*;
190/// test! {
191///    let expr = parse("1 + 2").unwrap();
192///    assert!(expr.is_expression());
193/// }
194/// ```
195pub fn parse(code: &str) -> Result<Robj> {
196    single_threaded(|| unsafe {
197        use libR_sys::*;
198        let mut status = 0_u32;
199        let status_ptr = &mut status as *mut u32;
200        let codeobj: Robj = code.into();
201        let parsed = new_owned(R_ParseVector(codeobj.get(), -1, status_ptr, R_NilValue));
202        match status {
203            1 => Ok(parsed),
204            _ => Err(Error::ParseError(code.into())),
205        }
206    })
207}
208
209/// Parse a string into an R executable object and run it.
210/// Used by the R! macro.
211/// ```
212/// use extendr_api::prelude::*;
213/// test! {
214///    let res = eval_string("1 + 2").unwrap();
215///    assert_eq!(res, r!(3.));
216/// }
217/// ```
218pub fn eval_string(code: &str) -> Result<Robj> {
219    single_threaded(|| {
220        let expr = parse(code)?;
221        let mut res = Robj::from(());
222        if let Some(expr) = expr.as_expression() {
223            for lang in expr.values() {
224                res = lang.eval()?
225            }
226        }
227        Ok(res)
228    })
229}
230
231/// Parse a string into an R executable object and run it using
232///   parameters param.0, param.1, ...
233///
234/// Used by the R! macro.
235/// ```
236/// use extendr_api::prelude::*;
237/// test! {
238///    let res = eval_string_with_params("param.0", &[&r!(3.)]).unwrap();
239///    assert_eq!(res, r!(3.));
240/// }
241/// ```
242pub fn eval_string_with_params(code: &str, values: &[&Robj]) -> Result<Robj> {
243    single_threaded(|| {
244        let env = Environment::new_with_parent(global_env());
245        for (i, &v) in values.iter().enumerate() {
246            let key = Symbol::from_string(format!("param.{}", i));
247            env.set_local(key, v);
248        }
249
250        let expr = parse(code)?;
251        let mut res = Robj::from(());
252        if let Some(expr) = expr.as_expression() {
253            for lang in expr.values() {
254                res = lang.eval_with_env(&env)?
255            }
256        }
257
258        Ok(res)
259    })
260}
261
262/// Find a function or primitive that may be in a namespace.
263/// ```
264/// use extendr_api::prelude::*;
265/// test! {
266///    assert!(find_namespaced_function("+").is_ok());
267///    assert!(find_namespaced_function("ls").is_ok());
268///    assert!(find_namespaced_function("base::ls").is_ok());
269///    assert!(find_namespaced_function("ls")?.is_language());
270///    assert!(!find_namespaced_function("basex::ls").is_ok());
271/// }
272/// ```
273pub fn find_namespaced_function(name: &str) -> Result<Language> {
274    let mut iter = name.split("::");
275    match (iter.next(), iter.next(), iter.next()) {
276        (Some(key), None, None) => {
277            let gf = global_function(Symbol::from_string(key))?;
278            Ok(Language::from_values(&[gf]))
279        }
280        (Some(ns), Some(key), None) => {
281            let namespace = find_namespace(ns)?;
282            Ok(Language::from_values(&[
283                namespace.local(Symbol::from_string(key))?
284            ]))
285        }
286        _ => Err(Error::NotFound(r!(name))),
287    }
288}