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 98 99 100 101 102 103 104 105 106 107 108 109 110
//! A low-level libR binding library which is kept deliberately //! minimal. //! //! In particular, it has no external dependencies other that libR //! installed on the target. //! //! ## Synopsis //! //! The `libR-sys` crate is a low level bindgen wrapper for the R //! programming language. The intention is to allow one or more extension //! mechanisms to be implemented for rust. //! //! Effort to make the extension libraries platform-independent can be //! concentrated here. //! //! # Examples //! //! ```no_run //! use libR_sys::{Rf_initialize_R, R_CStackLimit, setup_Rmainloop}; //! use std::os::raw; //! //! unsafe { //! std::env::set_var("R_HOME", "/usr/lib/R"); //! let arg0 = "R\0".as_ptr() as *mut raw::c_char; //! Rf_initialize_R(1, [arg0].as_mut_ptr()); //! R_CStackLimit = usize::max_value(); //! setup_Rmainloop(); //! } //! ``` #![allow(non_upper_case_globals)] #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(improper_ctypes)] include!(concat!(env!("OUT_DIR"), "/bindings.rs")); #[cfg(test)] mod tests { use super::*; use std::os::raw; // Generate constant static strings. // Much more efficient than CString. // Generates asciiz. macro_rules! cstr { ($s: expr) => { concat!($s, "\0").as_ptr() as *const raw::c_char }; } // 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 }; } // Thanks to @qinwf and @scottmmjackson for showing the way here. fn start_R() { unsafe { // TODO: This has only been tested on the debian package // r-base-dev. if cfg!(unix) { if std::env::var("R_HOME").is_err() { // env! gets the build-time R_HOME made in build.rs 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()) }; Rf_initialize_R(1, [cstr_mut!("R")].as_mut_ptr()); // In case you are curious. // Maybe 8MB is a bit small. // eprintln!("R_CStackLimit={:016x}", R_CStackLimit); R_CStackLimit = usize::max_value(); setup_Rmainloop(); } } // Run some R code. Check the result. #[test] fn test_eval() { start_R(); unsafe { // In an ideal world, we would do the following. // let res = R_ParseEvalString(cstr!("1"), R_NilValue); // But R_ParseEvalString is only in recent packages. let s = Rf_protect(Rf_mkString(cstr!("1"))); let mut status: ParseStatus = 0; let status_ptr = &mut status as *mut ParseStatus; let ps = Rf_protect(R_ParseVector(s, -1, status_ptr, R_NilValue)); let val = Rf_eval(VECTOR_ELT(ps, 0), R_GlobalEnv); Rf_PrintValue(val); assert_eq!(TYPEOF(val) as u32, REALSXP); assert_eq!(*REAL(val), 1.); Rf_unprotect(2); } } }