├── GNUmakefile ├── README ├── README.md ├── RustInRPkg ├── DESCRIPTION ├── NAMESPACE ├── src │ ├── Makevars │ ├── lib.rs │ └── wrapper.c └── tests │ └── call.R ├── call.R ├── callDotc.R ├── lib.rs ├── regular.R ├── rustRoutines.rs └── wrapper.c /GNUmakefile: -------------------------------------------------------------------------------- 1 | RUSTC=rustc 2 | 3 | librustRoutines.dylib: rustRoutines.rs 4 | $(RUSTC) $^ 5 | 6 | %.o: %.rust 7 | $(RUSTC) --emit obj $< -o $@ 8 | 9 | %.o: %.rs 10 | $(RUSTC) --emit obj $< -o $@ 11 | 12 | RcallRust.so: wrapper.o rustRoutines.o 13 | (export PKG_LIBS="-lrustc_driver-4e7c5e5c -lrustc-4e7c5e5c /usr/local/lib/rustlib/i686-apple-darwin/lib/libcore-4e7c5e5c.rlib"; R CMD SHLIB -o $@ $^) 14 | 15 | # $(RUSTC) -o $@ $^ 16 | 17 | clean: 18 | rm librustRoutines.dylib 19 | 20 | 21 | wrapper.o: wrapper.c 22 | (export PKG_CPPFLAGS=-I$(R_HOME)/include ; R CMD COMPILE wrapper.c) 23 | 24 | libfoo.a: lib.rs 25 | $(RUSTC) --crate-type staticlib --crate-name foo lib.rs 26 | 27 | wrapper.so: wrapper.o libfoo.a 28 | (export PKG_LIBS="-L. -lfoo" ; R CMD SHLIB -o $@ wrapper.o) 29 | 30 | 31 | threads.dylib: 32 | $(RUSTC) --crate-type dylib --crate-name threads threads.rs -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | See RustInRPkg for an example of arranging things as a C routine calling Rust routines 2 | in a library. 3 | 4 | This is a very simple example of calling Rust routines from R. 5 | This uses the Rffi package to call the routines directly without 6 | the need for a wrapper routine. We could use Dan Adler's rdyncall package 7 | also. 8 | 9 | I've also added an example of using .C() and .Call(). 10 | 11 | This approach doesn't really allow us to use Rust's run-time facilities, 12 | just to compile routines that we can call. 13 | 14 | For using Rust's run-time, it may be "necessary" to embed R within R, 15 | start rust as the primary application, and then pass control back to 16 | R's REPL. This is complicated with different R front-ends, e.g., 17 | R.app, Rgui.exe, RStudio, etc. 18 | 19 | Hopefully, Rust's run-time will become embeddable. It was mentioned in 2013. 20 | http://brson.github.io/2013/03/10/embedding-rust-in-ruby/ 21 | 22 | 23 | ``` shell 24 | make 25 | ``` 26 | 27 | In R 28 | ``` R 29 | source("call.R", verbose = TRUE) 30 | ``` 31 | 32 | Currently, this doesn't show how to active the Rust run-time system. 33 | 34 | 35 | A different approach that we implement is to 36 | write the wrappers in C 37 | compile the rust code as a library 38 | link the compiled C code and rust static library 39 | invoke as usual. 40 | 41 | 42 | There is a related SO thread: 43 | http://stackoverflow.com/questions/28901036/what-are-the-steps-necessary-to-pass-r-objects-to-a-rust-program -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | This is a very simple example of calling Rust routines from R. 3 | This uses the Rffi package to call the routines directly without 4 | the need for a wrapper routine. We could use Dan Adler's rdyncall package 5 | also. 6 | 7 | ``` shell 8 | make 9 | ``` 10 | 11 | In R 12 | ``` R 13 | source("call.R", verbose = TRUE) 14 | ``` -------------------------------------------------------------------------------- /RustInRPkg/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: RustInRPkg 2 | Version: 0.1-0 3 | Author: Duncan Temple Lang 4 | Maintainer: DTL 5 | Title: Illustrating calling Rust routines from R. 6 | Description: This does not (yet) handle Rust run-time facilities. 7 | So we can only use Rust as an alternative to C for compiling routines. 8 | Perhaps more on this soon. 9 | License: BSD_3_clause 10 | -------------------------------------------------------------------------------- /RustInRPkg/NAMESPACE: -------------------------------------------------------------------------------- 1 | useDynLib(RustInRPkg) 2 | 3 | -------------------------------------------------------------------------------- /RustInRPkg/src/Makevars: -------------------------------------------------------------------------------- 1 | 2 | include $(R_HOME)/etc/Makeconf 3 | 4 | RustInRPkg$(SHLIB_EXT) : librustRoutines.a wrapper.o 5 | $(R_HOME)/bin/R CMD SHLIB -o $@ wrapper.o 6 | 7 | PKG_LIBS=-L. -lrustRoutines 8 | RUSTC=rustc 9 | 10 | librustRoutines.a: lib.rs 11 | $(RUSTC) --crate-type staticlib --crate-name rustRoutines threads.rs 12 | # lib.rs 13 | -------------------------------------------------------------------------------- /RustInRPkg/src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | #[no_mangle] 3 | pub extern fn bob(val: f64) -> f64 { 4 | return val* 100.0 5 | } 6 | 7 | #[no_mangle] 8 | pub extern fn jane(val: i32) -> i32 { 9 | return val* 10 10 | } 11 | 12 | 13 | -------------------------------------------------------------------------------- /RustInRPkg/src/wrapper.c: -------------------------------------------------------------------------------- 1 | #if 0 2 | int jane(int); 3 | 4 | void 5 | R_jane(int *val) 6 | { 7 | val[0] = jane(val[0]); 8 | } 9 | 10 | 11 | #include 12 | 13 | double bob(double); 14 | 15 | SEXP 16 | Rf_bob(SEXP r_val) 17 | { 18 | double val; 19 | val = bob(REAL(r_val)[0]); 20 | return(ScalarReal(val)); 21 | } 22 | 23 | #endif 24 | 25 | extern void process(); 26 | 27 | void 28 | R_process() 29 | { 30 | process(); 31 | } 32 | -------------------------------------------------------------------------------- /RustInRPkg/tests/call.R: -------------------------------------------------------------------------------- 1 | 2 | library(RustInRPkg) 3 | 4 | .C("R_jane", 3L) 5 | 6 | .Call("Rf_bob", 3.12) 7 | 8 | -------------------------------------------------------------------------------- /call.R: -------------------------------------------------------------------------------- 1 | dyn.load("librustRoutines.dylib") 2 | 3 | library(Rffi) 4 | f = prepCIF(sint32Type, list(sint32Type)) 5 | callCIF(f, "jane", 4L) 6 | 7 | 8 | # Not behaving itself 9 | f = prepCIF(doubleType, list(doubleType)) 10 | callCIF(f, "bob", 4.12) 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /callDotc.R: -------------------------------------------------------------------------------- 1 | dyn.load("librustRoutines.dylib") 2 | 3 | .C("rf_jane", 32L) 4 | 5 | .C("rf_bob", 32) 6 | -------------------------------------------------------------------------------- /lib.rs: -------------------------------------------------------------------------------- 1 | 2 | #[no_mangle] 3 | pub extern fn bob(val: f64) -> f64 { 4 | return val* 100.0 5 | } 6 | 7 | #[no_mangle] 8 | pub extern fn jane(val: i32) -> i32 { 9 | return val* 10 10 | } 11 | 12 | 13 | -------------------------------------------------------------------------------- /regular.R: -------------------------------------------------------------------------------- 1 | dyn.load("wrapper.so") 2 | .C("R_jane", 3L) 3 | 4 | .Call("Rf_bob", 3.12) 5 | 6 | -------------------------------------------------------------------------------- /rustRoutines.rs: -------------------------------------------------------------------------------- 1 | // use core::libc::c_uint; 2 | 3 | 4 | #![crate_type = "dylib"] 5 | 6 | 7 | #[no_mangle] 8 | pub extern fn bob(val: f64) -> f64 { 9 | return val* 100.0 10 | } 11 | 12 | #[no_mangle] 13 | pub extern fn jane(val: i32) -> i32 { 14 | return val* 10 15 | } 16 | 17 | 18 | // Could use #[allow(non_snake_case)] to allow Rf_jane 19 | 20 | #[no_mangle] 21 | pub unsafe extern fn rf_jane(val: *mut i32) { 22 | *val = jane(*val); 23 | } 24 | 25 | #[no_mangle] 26 | pub unsafe extern fn rf_bob(val: *mut f64) { 27 | *val = bob(*val); 28 | } -------------------------------------------------------------------------------- /wrapper.c: -------------------------------------------------------------------------------- 1 | 2 | int jane(int); 3 | 4 | void 5 | R_jane(int *val) 6 | { 7 | val[0] = jane(val[0]); 8 | } 9 | 10 | 11 | #include 12 | 13 | double bob(double); 14 | 15 | SEXP 16 | Rf_bob(SEXP r_val) 17 | { 18 | double val; 19 | val = bob(REAL(r_val)[0]); 20 | return(ScalarReal(val)); 21 | } 22 | --------------------------------------------------------------------------------