2

I am trying to pass a matrix from R to Rust by way of C. I can pass a two-dimensional array if I hard-code the array-dimensions in the rust function signature. Is there a way to do this dynamically by passing a pointer to the array along with the number of rows and columns?

My C code:

#include "Rinternals.h"
#include "R.h"
#include <stdint.h>

void test1(double* matrix);

void test2(double* matrix, int32_t nrow, int32_t ncol);

SEXP pass_matrix_to_rust(SEXP mat, SEXP nrow, SEXP ncol) {

    // store nrows and ncols into integers
    int32_t rows = *INTEGER(nrow);
    int32_t cols = *INTEGER(ncol);

    // store pointer to matrix of doubles
    double *matrix = REAL(mat);

    test1(matrix); // hard coded version
    test2(matrix, rows, cols);

    return R_NilValue;
}

My Rust code:

// This function works but I have to specify the size at compile time
#[no_mangle]
pub extern fn test1(value: *const [[f64; 10]; 10]) {
  let matrix = unsafe{*value};

  println!("{:?}", matrix);
}

// this function doesn't compile
#[no_mangle]
pub extern fn test2(value: *const f64, nrow: i32, ncol: i32) {
  let matrix: [[f64; nrow]; ncol] = unsafe{*value};

  println!("{:?}", matrix);
}

// rustc output:
 rustc glue.rs
glue.rs:30:29: 30:33 error: no type for local variable 161
glue.rs:30   let matrix: [[f64; nrow]; ncol] = unsafe{*value};
                                       ^~~~
glue.rs:30:22: 30:26 error: no type for local variable 158
glue.rs:30   let matrix: [[f64; nrow]; ncol] = unsafe{*value};
                                ^~~~
Zelazny7
  • 39,946
  • 18
  • 70
  • 84
  • Rust doesn't have strided slices in std. You'll need to wrap it manually or get a library. – Veedrac Jun 20 '15 at 23:20
  • 1
    Arrays have *compile time length*, that's one of the core parts of them. Your question has nothing to do with FFI or C; you simply cannot create arrays with dynamic length. This should be a duplicate of http://stackoverflow.com/q/27859822/155423, or of http://stackoverflow.com/q/30312885/155423. – Shepmaster Jun 21 '15 at 00:03
  • 1
    http://nalgebra.org/doc/nalgebra/struct.DMat.html - "*Matrix with dimensions unknown at compile-time*". – ArtemGr Jun 21 '15 at 00:12
  • @ArtemGr I have a feeling that a `DMat` is going to be *much* harder to cross the FFI boundary :-) Really anything with a generic type. – Shepmaster Jun 21 '15 at 13:36
  • @Shepmaster, riiight. Pointer arithmetics should be used to read the matrix from the C memory. – ArtemGr Jun 21 '15 at 13:43
  • 1
    you should probably look at https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html that allows one to create a slice using a pointer of type T and the number of elements. – Christophe Augier Jun 24 '15 at 16:01

1 Answers1

1

Here's what I'd suggest, assuming this is in row-major order.

C code:

void test2(double* matrix, int32_t nrow, int32_t ncol);

Rust code:

use std::slice;

#[no_mangle]
pub extern fn test2(pointer: *const f64, nrow: i32, ncol: i32) {
    let mut rows: Vec<&[f64]> = Vec::new();
    for i in 0..nrow as usize {
        rows.push(unsafe {
            slice::from_raw_parts(
                pointer.offset(i as isize * ncol as isize), 
                ncol as usize
            )
        });
    }
    let matrix: &[&[f64]] = &rows[..];

    println!("{:#?}", matrix);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Phoenix
  • 1,553
  • 2
  • 13
  • 29