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