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}