Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interaction between Julia and Rust

Tags:

rust

julia

Is there any way to interact between Julia and Rust, a way that allow:

  1. Calling/Executing Rust function from Julia
  2. Calling/Executing Julia from Rust

Thanks

like image 904
Hasan A Yousef Avatar asked Aug 19 '18 10:08

Hasan A Yousef


2 Answers

Calling Rust function from Julia, like ccall

There's an example for this in alexcrichton/rust-ffi-examples repo:

Cargo.toml:

[package]
name = "julia-to-rust"
version = "0.1.0"
authors = ["timmonfette1 <[email protected]>"]

[lib]
name = "double_input"
crate-type = ["dylib"]

src/lib.rs:

#[no_mangle]
pub extern fn double_input(input: i32) -> i32 {
    input * 2
}

src/main.jl:

input = Int32(10)
output =  ccall((:double_input, "target/debug/libdouble_input"),
                        Int32, (Int32,), input)

print(input)
print(" * 2 = ")
println(output)

Makefile:

ifeq ($(shell uname),Darwin)
    EXT := dylib
else
    EXT := so
endif

all: target/debug/libdouble_input.$(EXT)
    julia src/main.jl

target/debug/libdouble_input.$(EXT): src/lib.rs Cargo.toml
    cargo build

clean:
    rm -rf target

The idea is that you export a non-mangled function and compile your rust library to a normal native shared library. Then you just use standard C FFI of Julia.

Calling Julia from Rust

I guess it's better to use julia crate for this - it provides a safe wrapper over a raw C API. Example from the repo:

fn main() {
    use julia::api::{Julia, Value};

    let mut jl = Julia::new().unwrap();
    jl.eval_string("println(\"Hello, Julia!\")").unwrap();
    // Hello, Julia!

    let sqrt = jl.base().function("sqrt").unwrap();

    let boxed_x = Value::from(1337.0);
    let boxed_sqrt_x = sqrt.call1(&boxed_x).unwrap();

    let sqrt_x = f64::try_from(boxed_sqrt_x).unwrap();
    println!("{}", sqrt_x);
    // 36.565010597564445
}
like image 197
ozkriff Avatar answered Oct 18 '22 05:10

ozkriff


Executing Julia from Rust

Use Rust's Command.

Create a main.jl file that contains:

# __precompile__()   # If required to be kept precompiled for faster execution
# name = isempty(ARGS) ? "name" : ARGS[1] # To check input arguments
println("hello from Julia function")

Create a main.rs file that contains:

use std::process::Command;

fn main() {
    println!("Hello from Rust");
    let mut cmd = Command::new("Julia");
    cmd.arg("main.jl");
    // cmd.args(&["main.jl", "arg1", "arg2"]);
    match cmd.output() {
        Ok(o) => unsafe {
            println!("Output: {}", String::from_utf8_unchecked(o.stdout));
        },
        Err(e) => {
            println!("There was an error {}", e);
        }
    }
}

Then, by running cargo run you'll get the required output below:

enter image description here

Executing Rust from Julia

Use the calling-c-and-fortran-code by ccall

Create a Rust shared library using a lib.rs file that contains:

#[no_mangle]
pub extern fn double_input(input: i32) -> i32 {
    println!("Hello from Rust");
    input * 2
}

The Cargo.toml for building the library:

[package]
name = "julia_call_rust"
version = "1.0.0"
authors = ["hasan yousef]

[lib]
name = "my_rust_lib"
crate-type = ["dylib"]

Create a main.jl file, that contains:

println("Hello from Julia")
input = 10 #Int32(10)
output =  ccall(   #(:function or "function", "library"), Return type, (Input types,), arguments if any)
                (:double_input,
                "target/debug/libmy_rust_lib"),
                Int32,          # Return type
                (Int32,),       # (Input types,)
                input)          # Arguments if any
println("As result of $input * 2 is: $output")

Run cargo build to get the Rust library built, and run julia main.jl to get the required output below:

enter image description here

like image 23
Hasan A Yousef Avatar answered Oct 18 '22 06:10

Hasan A Yousef