Send array from Julia to Rust (using "ccall")

Viewed 232

Can someone explain? How to send any array from julia to rust using "ccall" function. There is no problem with sending usial variables or constants.

I have Julia code:

A = Array{Float64,1}(undef, 2)
print("A is ",A, "\n")
ccall((:recvstruct, "target/debug/liblib"),Float64, (Ref{Array{Float64,1}}, Int32,), A, sizeof(A))

And Rustcode

#[no_mangle]
pub extern fn recvstruct(vec: &mut Vec<f64> , len: usize){
    println!("reiceved?: {:?}", len);
    println!("reiceved?: {:?}", vec);
}

Output is:

A is [0.0, 0.0]
Hello from cargo

reiceved?: 16

and weird endless array:

, 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000069329110091509, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000693291559949425, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000693291100915405, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000693291559949425, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000693291100915405, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000693291559949425, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000693291100915563, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000693291559949425, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000693291100915563, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000693291559949425, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000693291100915563, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000693291559949425, 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000069329110091572, 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Julia installed: Version 1.5.2 Rust (cargo): cargo 1.49.0 (d00d64df9 2020-12-05)

1 Answers

Julia side

In (argtype1, ...) of ccall declare the type of first argument of recvstruct as a pointer to a memory address with Ptr{T}.

direclty from ccall docs:

Each argvalue to the ccall will be converted to the corresponding argtype, by automatic insertion of calls to unsafe_convert(argtype, cconvert(argtype, argvalue))

Pass the number of array elements and not the size in bytes of the array:

a = [2.0, 3.0]
result = ccall((:recvstruct, "target/debug/liblib"), Float64, (Ptr{Float64}, UInt,), a, length(a))
println("got: $result")

Rust side

Declare the first argument of recvstruct as a memory pointer to an array of float64.

Moreover use slice::from_raw_parts for getting the slice of values.

For example:

#[no_mangle]
pub extern "C" fn recvstruct(array_ptr: *const f64, len: usize) -> f64 {
    _recvstruct(unsafe {
        std::slice::from_raw_parts(array_ptr as *const f64, len)
    }, len)
}

fn _recvstruct(vec: &[f64] , len: usize) -> f64 {
    match len {
        2 => vec[0] * vec[1],
        _ => 0.0
    }
}

Note that from_raw_parts is marked as unsafe. The Safety section of the manual page contains all the details to be considered.

Related