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}