Zelazny7 Zelazny7 - 3 months ago 13
R Question

What are the steps necessary to pass R objects to a Rust program?

Both R and Rust can interface with C code, so I think it is very possible. I am a bit unclear about how to proceed, however.

I have read these sections looking for answers:


  1. R-extensions System-and-foreign-language-interfaces

  2. The Rust foreign function interface guide



But while I am well-versed in
R
I am not a systems programmer and confused by what the build-chain looks like for such an endeavor.

Using
Rinternals.h
would be ideal, but I would settle for the simpler
.C
interface as well.

Answer

If R can interface with C code, so it is no problem at all to compile shared library from Rust code which exposes C-style functions.

Then you can easily use your library as it was written in C or C++. Of course, you will not able to use Rust object and libraries directly from R, you will have to make appropriate C interface for converting their functions.

Here is how can I do that for SBCL, and I suppose it would be very similar for R:

On Rust side

Some code:

% cat experiment.rs

extern crate libc;

use libc::{c_int, c_char};
use std::{ffi, str};

#[no_mangle]
pub extern fn rust_code_string_to_int(s: *const c_char, r: *mut c_int) -> c_int { 
    let string = String::from_utf8_lossy(unsafe { ffi::CStr::from_ptr(s).to_bytes() });
    match <isize as str::FromStr>::from_str(&*string) {
        Ok(value) => { unsafe { *r = value as c_int }; 0 },
        Err(_) => -1,
    }
}

Then I'm making shared lib:

% rustc --crate-type dylib experiment.rs
% nm -a libexperiment.dylib | grep rust_code_string_to_int
0000000000001630 t __ZN23rust_code_string_to_int10__rust_abiE
00000000000015e0 T _rust_code_string_to_int

Next, on SBCL side

Now I'm just loading my shared lib and then I have access to my rust_code_string_to_int function:

RUST> (sb-alien:load-shared-object "libexperiment.dylib")
#P"libexperiment.dylib"
RUST> (sb-alien:with-alien ((result sb-alien:int 0))  
          (values (sb-alien:alien-funcall (sb-alien:extern-alien "rust_code_string_to_int" 
                                                                 (sb-alien:function sb-alien:int 
                                                                                    (sb-alien:c-string :external-format :utf-8)
                                                                                    (sb-alien:* sb-alien:int)))
                                          (sb-alien:make-alien-string "42")
                                          (sb-alien:addr result))
                  result))
0
42