Skip to content

Repository files navigation

RustCall.jl

CI

RustCall.jl is a Julia package for calling Rust code directly. It covers the common paths from this repository: inline Rust via rust"""...""", explicit FFI calls with @rust, lightweight inline expressions with @irust, #[julia]-based wrapper generation, and external crate loading with @rust_crate.

It is inspired by Cxx.jl, but targets Rust.

Installation

Requirements:

  • Julia 1.12 or later
  • Rust toolchain (rustc and cargo) available in PATH
using Pkg
Pkg.add("RustCall")

RustCall.jl is registered in Julia's General registry. Pkg.add("RustCall") installs the package and builds the helper library used by ownership-related features such as RustBox, RustRc, RustArc, RustVec, and RustSlice.

If the helper library needs to be rebuilt, run:

using Pkg
Pkg.build("RustCall")

Quick Start

The simplest path is to annotate Rust functions with #[julia] and call the generated Julia wrapper directly.

using RustCall

rust"""
#[julia]
fn add(a: i32, b: i32) -> i32 {
    a + b
}
"""

add(10, 20) # 30

If you want explicit C-ABI style calls, use @rust.

using RustCall

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

@rust multiply(Int32(6), Int32(7))::Int32 # 42

For small expressions inside Julia functions, @irust captures Julia variables with $var.

using RustCall

function affine(a, x, b)
    @irust("\$a * \$x + \$b")
end

affine(Int32(2), Int32(10), Int32(3)) # 23

The snippet is the body of the generated function — a trailing expression is its value, return works, and statements and multi-line snippets are fine — and its return type is taken from rustc rather than guessed from the text. $$ is a literal $ (for a macro_rules! metavariable), and a Rust panic inside a snippet is a catchable RustCall.RustPanicError.

When not to use @irust

@irust is for exploration at the REPL or in a notebook. It is deliberately small:

  • scalars only — arguments and results must be Int8Int64, UInt8UInt64, Float32, Float64 or Bool; no String, arrays, structs or 128-bit integers;
  • $name substitution is textual, so it happens inside Rust string literals too, and $obj.field interpolates obj only;
  • not type-stable — the return type is decided at run time from the snippet;
  • compiler invocations per new snippet (on first use: the type probe, a confirmation of its answer, and the build), memoized for the rest of the session.

Anything beyond a small scalar expression belongs in rust"""...""" with @rust: it takes its types from the Rust side, generates the wrapper once, is type-stable, and handles String, Result/Option and #[julia] structs. The same computation both ways:

# @irust — a one-off scalar expression
hypot_irust(a, b) = @irust("(\$a * \$a + \$b * \$b).sqrt()")
hypot_irust(3.0, 4.0)   # 5.0

# rust""" — what a package should ship
rust"""
#[julia]
fn hypot_rs(a: f64, b: f64) -> f64 {
    (a * a + b * b).sqrt()
}
"""
hypot_rs(3.0, 4.0)      # 5.0

Main APIs

  • rust"""...""" / @rust_str: compile Rust code, cache the build artifact, and make it available in the current Julia module
  • #[julia]: generate Julia-callable wrappers for Rust functions and structs
  • @rust: call exported functions through a C-compatible ABI
  • @irust: compile a small Rust expression with Julia variable capture
  • @rust_crate: build and load an external crate annotated with #[julia]

Rust dependencies can be declared inline with // cargo-deps: or fenced cargo blocks. The first build may need network access.

External Crates

@rust_crate loads a Rust crate and returns a Julia module-like binding object.

using RustCall

const MyCrate = @rust_crate "/path/to/my_crate"
MyCrate.add(Int32(1), Int32(2)) # 3

For crate-side bindings, use the companion juliacall_macros crate and mark exported items with #[julia].

Documentation And Examples

Development

For a local checkout:

julia --project -e 'using Pkg; Pkg.instantiate()'
julia --project -e 'using Pkg; Pkg.build("RustCall")'
julia --project -e 'using Pkg; Pkg.test()'
julia --project=docs docs/make.jl

The main package entry point is src/RustCall.jl. Runnable examples live in examples/.

Acknowledgments

RustCall.jl has been implemented with support from AI coding tools and agents including Codex, Claude Code, and Cursor.

About

It's the last call for headache.

Topics

Resources

Stars

30 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages