#[export]Expand description
Export a function as a Wolfram LibraryLink function. See
export for the four wire-format modes (native, margs,
wstp, wxf) and the Cargo features each one needs.
Export a function as a Wolfram LibraryLink function, in one of four wire
formats picked by a keyword argument. All four need
LibraryFunctionLoad on the Wolfram side and none of them need the
automate-function-loading-boilerplate feature to work — that feature
only affects whether cargo wl build can discover the load call for you
(#[export(margs)] needs an args =/ret = annotation for that
discovered call to be correct — see below).
| Attribute | Wire format | Cargo feature (on wolfram-export) |
|---|---|---|
#[export] | native MArgument ABI | native (in the default feature set) |
#[export(margs)] | raw MArgument ABI | native |
#[export(wstp)] | WSTP LinkObject | wstp |
#[export(wxf)] | typed WXF ByteArray | wxf |
# Cargo.toml
wolfram-export = { version = "0.6", features = ["wstp", "wxf"] } # native is on by default§#[export] — native mode (default)
Parameters and the return type must implement FromArg/IntoArg:
bool, i64, f64, String, NumericArray, and references thereof.
This is the fastest mode — arguments cross the LibraryLink ABI with no
intermediate encoding.
use wolfram_export::export;
#[export]
fn add(a: i64, b: i64) -> i64 { a + b }
#[export]
fn greet(name: String) -> String { format!("Hello, {name}!") }§#[export(margs)] — raw native mode
Same C ABI as plain #[export], but the function receives the raw
&[MArgument] arguments and MArgument return slot directly, with no
FromArg/IntoArg marshaling performed for you. Use this when you need
full manual control over argument/return conversion.
Since the parameter/return types aren’t visible to the macro from the
function signature alone, declare them by hand with args = (..)/
ret = .. — each fragment is spliced verbatim into a wolfram_expr::expr!
call, so wolfram-expr must be a direct dependency of your crate to use
them:
use wolfram_export::{export, sys::MArgument};
#[export(margs, args = (::Real, ::Real), ret = ::Real)]
fn raw_add(args: &[MArgument], ret: MArgument) {
unsafe { *ret.real = *args[0].real + *args[1].real; }
}This makes raw_add show up in cargo wl build’s generated
Functions.wl with a real, correct LibraryFunctionLoad call — same as
if you’d written LibraryFunctionLoad["...", "raw_add", {Real, Real}, Real]
by hand. Omitting args/ret still compiles, but defaults the generated
entry’s type spec to the same fixed LinkObject/LinkObject placeholder
#[export(wstp)] uses — which a raw MArgument function does not actually
accept, so calling it would misbehave — and emits a compile-time warning
telling you to annotate it.
§#[export(wstp)] — WSTP mode
The function receives a Vec<Expr> (all arguments as a list) and returns
an Expr, or takes a &mut Link for low-level control over the wire.
Use this mode when the function’s arguments or return value don’t fit a
fixed native/WXF shape — e.g. variadic arguments, or streaming a result
incrementally.
use wolfram_export::export;
use wolfram_expr::{expr, Expr, ExprKind};
// High-level: Vec<Expr> in, Expr out.
#[export(wstp)]
fn reverse(args: Vec<Expr>) -> Expr {
let list = args.into_iter().next().expect("expected 1 arg");
if let ExprKind::Normal(n) = list.kind() {
let head = n.head().clone();
expr!(head[..n.elements().iter().rev().cloned()])
} else {
list
}
}§#[export(wxf)] — typed WXF mode
The generated wrapper reads a WXF-encoded ByteArray MArgument,
deserializes all arguments via FromWXF, calls your function, and
serializes the return value via ToWXF back into a ByteArray. Panics
are caught and returned as structured Failure["RustPanic", …]
expressions. Use this mode for structured arguments/return values
(structs, enums, Option/Result) without hand-writing WSTP plumbing.
use wolfram_export::export;
use wolfram_expr::{expr, Expr};
use wolfram_serialize::{ToWXF, FromWXF};
// Primitives and Vec<T> work out of the box.
#[export(wxf)]
fn scale(values: Vec<f64>, factor: f64) -> Vec<f64> {
values.into_iter().map(|v| v * factor).collect()
}
// `Expr` implements `ToWXF`/`FromWXF` directly (in `wolfram-expr`), so a
// function can take and return untyped Wolfram Language expressions —
// useful when the shape isn't known ahead of time, or a derive isn't worth
// it. Build the result with the `expr!` macro.
#[export(wxf)]
fn add_hold(e: Expr) -> Expr {
expr!(System::Hold[e])
}
// Structs need #[derive(ToWXF, FromWXF)].
#[derive(ToWXF, FromWXF)]
struct Point { x: f64, y: f64 }
#[export(wxf)]
fn midpoint(a: Point, b: Point) -> Point {
Point { x: (a.x + b.x) / 2.0, y: (a.y + b.y) / 2.0 }
}
// Option<T> and Result<T,E> are supported too.
#[export(wxf)]
fn safe_div(a: f64, b: f64) -> Option<f64> {
if b == 0.0 { None } else { Some(a / b) }
}On the Wolfram side a struct maps to an Association:
midpoint[<|"x" -> 0.0, "y" -> 0.0|>, <|"x" -> 2.0, "y" -> 4.0|>]
(* Returns <|"x" -> 1.0, "y" -> 2.0|> *)