296 words, 2 min read

When using Rust NIFs in Elixir via the Rustler crate, it's often useful to pass structured data, not just integers and strings. This post shows how to pass an Elixir struct to Rust, manipulate it, and return a new struct to Elixir.

Define a struct in Elixir

Start by creating a simple struct, such as User:

defmodule MyNif.User do
  defstruct [:name, :age]
end

Define the same struct in Rust

In your NIF crate (native/my_nif/src/lib.rs), define a matching Rust struct using Rustler's NifStruct derive macro:

use rustler::NifStruct;

#[derive(NifStruct)]
#[module = "MyNif.User"]
struct User {
    name: String,
    age: u32,
}

The #[module = "MyNif.User"] attribute tells Rustler how to map the Elixir struct to the Rust struct.

Write a NIF function that uses the struct

Here's a Rust NIF that increases a user's age:

#[rustler::nif]
fn birthday(user: User) -> User {
    User {
        age: user.age + 1,
        ..user
    }
}

Register the function:

rustler::init!("Elixir.MyNif");

Wire it up in Elixir

In your wrapper module:

defmodule MyNif do
  use Rustler, otp_app: :my_nif_app, crate: "my_nif"

  def birthday(_user), do: :erlang.nif_error(:nif_not_loaded)
end

Call it from IEx

$ iex -S mix
iex> user = %MyNif.User{name: "Alice", age: 29}
iex> MyNif.birthday(user)
%MyNif.User{name: "Alice", age: 30}

Notes

  • Fields must match exactly between Elixir and Rust.
  • Rustler will raise a badarg error if field names or types don't match.
  • NifStruct automatically handles encoding and decoding using serde.