The Crystal Programming Language Forum

Crystal integration with Rust

Hi, I had the bright idea to integrate Crystal with Rust, which is more less worked out, but there is one thing which does not seem to work, Arrays.

Since Rust can compile to C compatible code, like this

#[no_mangle]
pub extern "C" fn rust_function() {
    println!("Hello from Rust");
}

#[no_mangle]
pub extern "C" fn rust_add(a: i32, b: i32) -> i32 {
    a + b
}

#[no_mangle]
pub extern "C" fn rust_sum(a: Vec<i32>) -> i32 {
    let mut sum = 0;
    for item in a {
        sum += item;
    }
    sum
}

and Crystal can load C libs like this

module Rshost
  VERSION = "0.1.0"

  @[Link(ldflags: "#{__DIR__}/../../embed/target/release/libembed.so")]
  lib MyDylib
    fun rust_function : Void
    fun rust_add(a: Int32, b: Int32) : Int32
    fun rust_sum(a: Pointer(Int32)) : Int32
  end

  MyDylib.rust_function
  puts MyDylib.rust_add(2, 3)
  puts MyDylib.rust_sum([1,2])
end

the only problem is with the last function the rust_sum is not working as expected, if I mean expected to work at all :D The error what I’m getting is the following

imre@DESKTOP-1JK127M:/mnt/d/Documents/Git/rs-cr-magic/rshost$ crystal run src/rshost.cr 
Hello from Rust
5
Invalid memory access (signal 11) at address 0x28d8bca3c
[0x7fe58d64d6c6] *CallStack::print_backtrace:Int32 +118
[0x7fe58d640f80] __crystal_sigfault_handler +192
[0x7fe58ca92890] ???
[0x7fe58cf5ddd0] rust_sum +176
[0x7fe58d633a2c] __crystal_main +1628
[0x7fe58d68e286] *Crystal::main_user_code<Int32, Pointer(Pointer(UInt8))>:Nil +6
[0x7fe58d68e1e9] *Crystal::main<Int32, Pointer(Pointer(UInt8))>:Int32 +41
[0x7fe58d63e466] main +6
[0x7fe58c011b97] __libc_start_main +231
[0x7fe58d6332ea] _start +42
[0x0] ???

It’s totally possible, that my Rust is in fault, but maybe someone could help me out.

It won’t work this way. Vector in Rust is a much more complex construct than just pointer. Code on a Rust side should take not a vector, but a raw pointer and number of elements, then (unsafely) construct a vector from them.

Well, I don’t know Rust. Maybe you should construct slice not vector, and maybe it’s not unsafe as long as calling contract holds.
But general idea is that you should pass pointer and size.

yes, after some digging around, you are probably right, I came to the same conclusion too. I will try it out, when I have some free time, and probably try to include in a Python code, I’m more proficient with that, thanks for the help

I successfully updated the Rust code, like this, now it works as expected. Thanks for the help. :slight_smile:

#[no_mangle]
    pub extern "C" fn rust_sum(ptr: *const i32, size: usize) -> i32 {
        assert!(!ptr.is_null());
        let arr = unsafe {
            slice::from_raw_parts(ptr, size)
        };
        let mut sum = 0;
        for item in arr {
            sum += item;
        }
        sum
    }
2 Likes