aorist_extendr_engine/
lib.rs

1//! A sigleton instance of the R interpreter.
2//!
3//! Only call this from main() if you want to run stand-alone.
4//!
5//! Its principal use is for testing.
6//!
7//! See <https://github.com/wch/r-source/blob/trunk/src/unix/Rembedded.c>
8
9use libR_sys::*;
10use std::os::raw;
11use std::sync::Once;
12
13// Generate mutable static strings.
14// Much more efficient than CString.
15// Generates asciiz.
16macro_rules! cstr_mut {
17    ($s: expr) => {
18        concat!($s, "\0").as_ptr() as *mut raw::c_char
19    };
20}
21
22static START_R: Once = Once::new();
23
24pub fn start_r() {
25    START_R.call_once(|| {
26        unsafe {
27            if std::env::var("R_HOME").is_err() {
28                // env! gets the build-time R_HOME stored by libR-sys
29                std::env::set_var("R_HOME", env!("R_HOME"));
30            }
31
32            // Due to Rf_initEmbeddedR using __libc_stack_end
33            // We can't call Rf_initEmbeddedR.
34            // Instead we must follow rustr's example and call the parts.
35
36            //let res = unsafe { Rf_initEmbeddedR(1, args.as_mut_ptr()) };
37            // NOTE: R will crash if this is called twice in the same process.
38            Rf_initialize_R(
39                3,
40                [cstr_mut!("R"), cstr_mut!("--slave"), cstr_mut!("--no-save")].as_mut_ptr(),
41            );
42
43            // In case you are curious.
44            // Maybe 8MB is a bit small.
45            // eprintln!("R_CStackLimit={:016x}", R_CStackLimit);
46            R_CStackLimit = usize::max_value();
47
48            setup_Rmainloop();
49        }
50    });
51}
52
53/// Close down the R interpreter. Note you won't be able to
54/// Restart it, so use with care or not at all.
55pub fn end_r() {
56    unsafe {
57        //Rf_endEmbeddedR(0);
58        R_RunExitFinalizers();
59        //CleanEd();
60        R_CleanTempDir();
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn test_engine() {
70        // If this is the first call, it should wake up the interpreter.
71        start_r();
72
73        // This should do nothing.
74        start_r();
75
76        // Ending the interpreter is bad if we are running multiple threads.
77        // So avoid doing this in tests.
78        //end_r();
79    }
80}