# Native Fusion Builds

## Native Fusion — Rust Interop Reference

**Native Fusion** is the mechanism that lets you write Rust functions and classes and expose them as first-class BoxLang Built-In Functions (BIFs) and native objects. Everything is statically linked into your final binary — no shared libraries, no FFI boilerplate at the BoxLang call site.

> Native Fusion is available in **native builds only** (`--target native`).\
> It is not available in WASM targets.

***

### How It Works

1. Create a `native/` directory alongside your `.bxs` entry script.
2. Write one or more `.rs` files inside `native/`.
3. Each `.rs` file exports a `register_bifs()` and/or `register_classes()` function.
4. Run `matchbox --target native app.bxs`.

MatchBox detects `native/`, compiles the Rust files together with the VM, merges all BIF and class registrations, and produces a single binary.

***

### Macros

All interop macros are re-exported from the `matchbox_vm` crate — no separate `matchbox_macros` import is needed:

```rust
use matchbox_vm::{matchbox_fn, matchbox_class, matchbox_methods};
```

***

#### `#[matchbox_fn]` — Expose a Rust function as a BoxLang BIF

Annotate a plain Rust function with typed parameters. The macro generates a corresponding `{name}_wrapper` function that carries the low-level BIF signature expected by the VM (`fn(&mut dyn BxVM, &[BxValue]) -> Result<BxValue, String>`).

The wrapper handles argument-count validation and type coercion automatically.

**Usage**

```rust
use matchbox_vm::{matchbox_fn, types::{BxNativeFunction}};
use std::collections::HashMap;

#[matchbox_fn]
pub fn add(a: f64, b: f64) -> f64 {
    a + b
}

pub fn register_bifs() -> HashMap<String, BxNativeFunction> {
    let mut map = HashMap::new();
    // Register the generated wrapper, not the original function.
    map.insert("add".to_string(), add_wrapper as BxNativeFunction);
    map
}
```

BoxLang:

```boxlang
result = add(10, 20)
println(result)   // 30
```

**Supported Parameter Types**

| Rust parameter type | VM conversion applied by the macro |
| ------------------- | ---------------------------------- |
| `f64`               | `args[i].as_number()`              |
| `i32`               | `args[i].as_int()`                 |
| `bool`              | `args[i].as_bool()`                |
| `String`            | `vm.to_string(args[i])`            |
| `BxValue`           | passed through unchanged           |

The return value is always wrapped as `BxValue::new_number(result as f64)`. For BIFs that need to return other types (strings, null, objects), write a manual BIF instead (see Manual BIF Signature).

**What the Macro Generates**

```rust
// Your function — unchanged:
pub fn add(a: f64, b: f64) -> f64 { a + b }

// Generated wrapper:
pub fn add_wrapper(
    vm: &mut dyn matchbox_vm::types::BxVM,
    args: &[matchbox_vm::types::BxValue],
) -> Result<matchbox_vm::types::BxValue, String> {
    if args.len() != 2 {
        return Err(format!("add requires 2 arguments, got {}", args.len()));
    }
    let a = args[0].as_number();
    let b = args[1].as_number();
    let result = add(a, b);
    Ok(matchbox_vm::types::BxValue::new_number(result as f64))
}
```

***

#### `#[matchbox_class]` — Expose a Rust struct as a BoxLang native object

Annotate a struct to auto-implement the `BxNativeObject` trait. The generated implementation delegates `get_property`, `set_property`, and `call_method` to a `dispatch_method` function that is generated by `#[matchbox_methods]`.

Always pair `#[matchbox_class]` with a `#[matchbox_methods]` impl block.

**Usage**

```rust
use matchbox_vm::{matchbox_class, matchbox_methods, types::{BxValue, BxVM, BxNativeFunction, BxNativeObject}};
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;

#[matchbox_class]
#[derive(Debug)]
pub struct Counter {
    pub value: f64,
}

#[matchbox_methods]
impl Counter {
    pub fn increment(&mut self) -> f64 {
        self.value += 1.0;
        self.value
    }

    pub fn add(&mut self, n: f64) -> f64 {
        self.value += n;
        self.value
    }

    pub fn get(&self) -> f64 {
        self.value
    }
}

// Constructor — registered separately, not via #[matchbox_fn].
pub fn create_counter(vm: &mut dyn BxVM, args: &[BxValue]) -> Result<BxValue, String> {
    let initial = args.first().map(|v| v.as_number()).unwrap_or(0.0);
    let obj = Counter { value: initial };
    let id = vm.native_object_new(Rc::new(RefCell::new(obj)));
    Ok(BxValue::new_ptr(id))
}

pub fn register_classes() -> HashMap<String, BxNativeFunction> {
    let mut map = HashMap::new();
    // Key format: "<module_filename>.<ClassName>"
    // This file is native/counter.rs → module name is "counter"
    map.insert("counter.Counter".to_string(), create_counter as BxNativeFunction);
    map
}
```

BoxLang (instantiate with `new rust:<module>.<Class>(...)`):

```boxlang
c = new rust:counter.Counter(0)
c.increment()
c.add(9)
println(c.get())   // 10
```

***

#### `#[matchbox_methods]` — Generate a method dispatcher for a native class

Annotate an `impl` block to generate a `dispatch_method` function that routes BoxLang method calls to the correct Rust method by name (case-insensitive).

`#[matchbox_fn]` type-coercion rules apply to each method's parameters.

**Usage**

```rust
#[matchbox_methods]
impl MyStruct {
    pub fn process(&self, input: f64) -> f64 {
        input * self.factor
    }
}
```

BoxLang calls `obj.process(42)` and the dispatcher resolves it to `MyStruct::process(&self, 42.0)`.

**What the Macro Generates**

```rust
impl MyStruct {
    fn dispatch_method(
        &mut self,
        vm: &mut dyn BxVM,
        name: &str,
        args: &[BxValue],
    ) -> Result<BxValue, String> {
        match name.to_lowercase().as_str() {
            "process" => {
                if args.len() != 1 { return Err(...); }
                let input = args[0].as_number();
                let result = self.process(input);
                Ok(BxValue::new_number(result as f64))
            }
            _ => Err(format!("Method {} not found", name)),
        }
    }
}
```

***

#### `#[matchbox_module]` — Module marker (no-op)

A no-op attribute that serves as documentation: apply it to the top-level `mod` or `impl` to indicate the file is a Native Fusion module. Currently passes through unchanged.

```rust
#[matchbox_module]
mod my_native_module { ... }
```

***

### Registration Entry Points

Every `.rs` file in `native/` may export two entry-point functions. MatchBox calls them both at startup.

#### `register_bifs()` — standalone functions

```rust
pub fn register_bifs() -> HashMap<String, BxNativeFunction> {
    let mut map = HashMap::new();
    map.insert("my_bif".to_string(), my_bif_wrapper as BxNativeFunction);
    map
}
```

BIF names must be unique across all files in `native/`.

#### `register_classes()` — native object constructors

```rust
pub fn register_classes() -> HashMap<String, BxNativeFunction> {
    let mut map = HashMap::new();
    // Key: "<module>.<ClassName>" where <module> is the filename without .rs
    map.insert("mymodule.MyClass".to_string(), create_my_class as BxNativeFunction);
    map
}
```

BoxLang uses the key to resolve `new rust:mymodule.MyClass(...)`.

***

### Manual BIF Signature

When you need full control (e.g. returning a string, null, or an object pointer), skip `#[matchbox_fn]` and write the low-level signature directly:

```rust
use matchbox_vm::types::{BxNativeFunction, BxValue, BxVM};
use std::collections::HashMap;

pub fn greet(vm: &mut dyn BxVM, args: &[BxValue]) -> Result<BxValue, String> {
    if args.is_empty() {
        return Err("greet: expected one argument".to_string());
    }
    let name = vm.to_string(args[0]);
    Ok(BxValue::new_string(format!("Hello, {}!", name)))
}

pub fn register_bifs() -> HashMap<String, BxNativeFunction> {
    let mut map = HashMap::new();
    map.insert("greet".to_string(), greet as BxNativeFunction);
    map
}
```

***

### Project Layout

```
my_app/
├── app.bxs         ← BoxLang entry point
└── native/
    ├── math.rs     ← exports register_bifs()
    ├── counter.rs  ← exports register_bifs() + register_classes()
    └── crypto.rs   ← exports register_classes()
```

Multiple files are supported as long as BIF and class names are unique across all files.

***

### Using External Rust Crates

Add a `Cargo.toml` to the `native/` directory to pull in dependencies:

```toml
[package]
name    = "native"
version = "0.1.0"
edition = "2021"

[dependencies]
serde       = { version = "1", features = ["derive"] }
serde_json  = "1"
base64      = "0.22"
```

MatchBox compiles this as a standard Cargo project and links the output into the final binary.

***

### Limitations

| Feature                                             | Status                                         |
| --------------------------------------------------- | ---------------------------------------------- |
| Native builds (`--target native`)                   | ✅                                              |
| WASM builds (`--target js` / `--target wasm`)       | ❌ Not supported                                |
| Multiple `.rs` files in `native/`                   | ✅                                              |
| External Rust crates via `native/Cargo.toml`        | ✅                                              |
| Return types other than `f64` from `#[matchbox_fn]` | ⚠️ Use manual BIF signature                    |
| Mutable `self` in `#[matchbox_methods]`             | ✅ Works — dispatcher takes `&mut self`         |
| Property access on native objects (`obj.field`)     | ⚠️ Override `get_property` in `BxNativeObject` |

See native-builds.md for the complete native build reference and differences-from-boxlang.md for the full list of features not available in MatchBox.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://boxlang.ortusbooks.com/boxlang-framework/matchbox/native-fusion-builds.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
