Skip to content

Custom Rust Extensions

An extern declaration gives a Rust implementation a Magscript signature. Use magnet new --rust gain to scaffold the package, then add it as a dependency.

The header gain/src/gain.mag declares fields and ports:

model Gain {
k: f64,
}
params Gain(k: f64 = 1.0) {
Self { k }
}
extern step Gain(u: f64) -> (y: f64);

A consumer:

  1. imports it with use gain::gain::Gain;
  2. constructs it with Gain(2.0) in its params body
  3. steps the instance with self.gain(u)

The dependency directory must contain the implementing Cargo.toml. The DSL package name identifies the Rust crate; the .mag module path identifies the Rust module. That module exports Gain and GainParameters.

Declaration Rust requirement
model Gain { k: f64 } GainParameters with public field k: f64
extern step Gain(...) -> (...) Gain implements magnetite::Model
Parameters Model::Parameters = GainParameters
Ports Model::Inputs and Model::Outputs match the declared types and order
Initialization fn init(params: &Self::Parameters) -> Self
One tick fn step(&mut self, ctx: &Ctx, params: &Self::Parameters, inputs: Self::Inputs) -> Self::Outputs

Zero ports map to (), one port to its type, and multiple ports to a tuple. The crate must support no_std and use the same magnetite runtime as the generated crate.

An external model’s explicit constructor must pass each argument directly to the same-named field, as above. It may supply defaults, but cannot derive fields through calculations or local bindings. Without params, fields are constructor arguments under the implicit constructor rules.

External pure functions use a signature followed by a semicolon:

extern fn response(x: f64) -> f64;

The Rust module must export the corresponding function. Calls follow the pure function rules.

  • External declarations belong in dependency packages. Checking a standalone Rust block package treats it as a dependency of a synthetic host.
  • External models cannot be inline; feedback around them needs an explicit delay.
  • @probe can observe external inputs and outputs, but not Rust internals.
  • Generic external models require a Rust implementation for each used type instantiation.
  • magnet check validates the DSL interface. magnet build compiles against Rust and reports implementation mismatches through Cargo.