Supported Native Constructs
pub structdeclarationsimplblocks and methods- Module-level
pub fnfunctions - All standard primitive types (
u8,i32,f64,String, etc.) Option<T>andResult<T, E>types- Rust Generics (e.g.,
<T>)
In addition to external crates, you can write custom native Rust code inside your project and call it directly from Flame with zero runtime overhead.
The easiest way to initialize a native plugin in your Flame project is via the Flame CLI:
fmp new --plugin <plugin_name># or shorthand:fmp new -p <plugin_name>This command will automatically scaffold a Rust library in your ./native folder and register it in your flame.toml. If you omit the plugin name, the CLI defaults to naming the plugin bridge.
If you have an existing plugin or modular Rust crate, register it into your project with:
fmp add --plugin ./native# or shorthand:fmp add -p ./nativeFlame automatically extracts the plugin name directly from the plugin’s Cargo.toml ([package] name = "..."), so passing a separate --name flag is not required.
Flame’s FFI boundary natively supports a vast majority of standard Rust elements simply by marking them pub. There are no boilerplate binding requirements—just write normal Rust code and use it directly via import native.<plugin_name>.
Supported Native Constructs
pub struct declarationsimpl blocks and methodspub fn functionsu8, i32, f64, String, etc.)Option<T> and Result<T, E> types<T>)Currently Unsupported
Mutex<T>, Box<T>, Arc<T>)Create a native folder containing native/Cargo.toml and native/src/lib.rs:
[package]name = "server"version = "0.1.0"edition = "2021"
[dependencies]axum = "0.7"tokio = { version = "1.0", features = ["full"] }flame-macro = "0.1.0"lib.rs)use axum::{ routing::{get, post}, Router,};use flame_macro::flame;use std::mem;use std::net::SocketAddr;
pub struct FlameServer { router: Router,}
#[derive(Debug, Clone)]pub struct Request { pub body: String,}
#[derive(Debug, Clone)]pub struct Response { pub body: String,}
// Module-level function/// Initialize a new FlameServer instance.pub fn init() -> FlameServer { FlameServer { router: Router::new(), }}
impl FlameServer { pub fn get<H, T>(&mut self, path: &'static str, handler: H) where H: axum::handler::Handler<T, ()> + Clone + Send + Sync + 'static, T: 'static, { let router = mem::take(&mut self.router); self.router = router.route(path, get(handler)); }
pub fn post<H, T>(&mut self, path: &'static str, handler: H) where H: axum::handler::Handler<T, ()> + Clone + Send + Sync + 'static, T: 'static, { let router = mem::take(&mut self.router); self.router = router.route(path, post(handler)); }
pub fn router(&mut self) -> Router { mem::take(&mut self.router) }
#[flame(daemon)] pub async fn listen(self, port: u16) -> std::io::Result<()> { let addr = SocketAddr::from(([127, 0, 0, 1], port));
let listener = tokio::net::TcpListener::bind(addr).await?;
axum::serve(listener, self.router) .await .map_err(std::io::Error::other) }}flame.toml[plugins]server = "./native"import native.server
let app = server.init()fn main() -> String { "hello"}
app.get("/", main)print("Server started!")
app.listen(3000)Native Rust implementations are incorporated into the executable only when required by the application’s dependency graph:
Application │ ├── Flame source ├── flame.toml └── package .fm + .fmi ↓ Dependency Analysis ↓ Required native plugins ↓ Application Runtime ↓ Cargo + LLVM ↓ Native Binary.fmi): The application relies on the Flame-side package source (.fm) and the .fmi interface metadata.flame.toml but not actually imported in the code, Flame’s dependency analysis excludes it from the application’s specialized runtime.flame build --release contains all native plugin code, production runner containers or servers do not need Rust, Cargo, or any .rs files.