BaseRT Rust Bindings
Rust bindings for the BaseRT LLM inference engine (Apple Silicon / Metal).
Two crates are provided:
baseRT-sys-- raw#[repr(C)]FFI bindings (unsafe).baseRT-- safe, idiomatic Rust wrapper with RAII,Resulterror handling, and closures for streaming.
Prerequisites
Build the single shared engine so that libbaseRT.dylib exists:
By default the crates dynamically link the one libbaseRT.dylib, which
already carries the Metal kernels (embedded metallib) and its own framework /
C++ dependencies — one redistributable artifact, matching the Python / Node /
Swift bindings. Point the build at the directory containing it with
BASERT_LIB_DIR. When it is unset, the build uses the first of these that
holds the library: ../../../build relative to the sys crate, a prebuilt
engine from install.sh ($BASERT_INSTALL_DIR, default ~/.basert), or
Homebrew ($(brew --prefix)/opt/basert/libexec). So after
brew install basecompute/tap/basert, cargo add baseRT builds with no extra setup.
The baseRT crate embeds an rpath to that directory, so its own examples and
tests run without DYLD_LIBRARY_PATH. A downstream binary that depends on
baseRT must make the dylib discoverable at runtime — either add an rpath in
its own build.rs (cargo:rustc-link-arg=-Wl,-rpath,<dir>), install the dylib
to a standard location, or set DYLD_LIBRARY_PATH=$BASERT_LIB_DIR.
To link the static engine archive instead (fully static, pulls in the
frameworks manually), enable the static feature:
= { = "...", = ["static"] }
A crate that loads libbaseRT itself at run time can depend on baseRT-sys
with the no-link feature: the build then looks for no library and links
nothing. The types stay usable; the extern functions must not be called.
Either way, baseRT-sys tells dependents' build scripts where the engine's C
headers are: DEP_BASERT_INCLUDE holds baseRT/baseRT.h.
Usage
Add the dependency from crates.io (install the engine first, e.g.
brew install basecompute/tap/basert):
[]
= "0.4"
or from a checkout:
[]
= { = "path/to/baseRT/bindings/rust/baseRT" }
Run the bundled example end-to-end:
BASERT_LIB_DIR=/path/to/baseRT/build \
Text generation
use ;
Non-streaming generation
let = model.generate_text?;
println!;
Multi-turn chat (continue from KV cache)
let turn1 = model.encode?;
model.generate?;
let turn2 = model.encode?;
model.generate_continue?;
Whisper transcription
let model = load?;
assert!;
let = model.transcribe?;
println!;
println!;
Model inspection
println!;
for in model.tensors
Sampling configuration
// Greedy (default)
let cfg = greedy;
// Temperature sampling
let cfg = with_temperature;
// Full control
let cfg = SamplingConfig ;
Low-level API
let first_token = model.prefill;
let next = model.decode_step;
// Or batch decode
let batch = model.chain_decode?;
Error handling
All fallible operations return baseRT::Result<T>. Errors come from:
Error::Api(msg)-- the C API returned NULL or an error (message frombaseRT_get_error()).Error::InvalidString(e)-- a Rust string contained an interior NUL byte.