# Native Fusion Example

**Native Fusion** lets you write performance-critical functions and stateful
objects in Rust and use them directly from BoxLang. Everything is statically
linked into a single native binary — no external libraries, no FFI boilerplate
at call sites.

This example demonstrates both interop styles:

| Style | Rust side | BoxLang side |
|---|---|---|
| **Standalone BIF** | `#[matchbox_fn]` on a plain function | `result = fast_fib(10)` |
| **Native object** | `#[matchbox_class]` + `#[matchbox_methods]` on a struct | `s = new rust:stats.RunningStats()` |

## Project Layout

```
native_fusion/
├── app.bxs        ← BoxLang entry point
└── native/
    └── stats.rs   ← Rust source: BIFs + RunningStats native object
```

MatchBox automatically detects any `.rs` files inside a `native/` directory
that lives alongside your entry script and compiles them together with the VM.

## Building

You need a Rust toolchain (`cargo`, `rustc`) in addition to the `matchbox` binary.

```bash
cd docs/examples/native_fusion
matchbox --target native app.bxs
```

MatchBox will:
1. Compile `native/stats.rs` together with the MatchBox VM.
2. Register the exported BIFs (`fast_fib`, `fast_factorial`) and the `RunningStats` class.
3. Compile `app.bxs` to bytecode and embed it.
4. Produce a single `app` binary.

## Running

```bash
./app
```

Expected output:

```
=== Native Fusion Demo ===

--- Fibonacci (BIF) ---
  fib(0) = 0
  fib(1) = 1
  fib(2) = 1
  ...
  fib(10) = 55

--- Factorials (BIF) ---
  1! = 1
  2! = 2
  ...
  10! = 3628800

--- RunningStats (native object) ---
  count : 6
  sum   : 108
  mean  : 18
  min   : 4
  max   : 42

All results computed in Rust — zero JVM, zero overhead.
```

## Writing a Native BIF with `#[matchbox_fn]`

Using the `#[matchbox_fn]` macro is the recommended way to write BIFs. You write
a plain typed Rust function — the macro generates the `{name}_wrapper` with the
correct BIF signature, argument-count validation, and type coercions for you.

```rust
use matchbox_vm::{matchbox_fn};

// Write a normal Rust function with typed parameters.
// Supported types: f64, i32, bool, String, BxValue (pass-through)
#[matchbox_fn]
pub fn my_bif(n: f64) -> f64 {
    n * 2.0
}
```

The macro expands this into two things:
1. Your original `my_bif(n: f64) -> f64` function, unchanged.
2. A generated `my_bif_wrapper(vm, args) -> Result<BxValue, String>` that the
   VM actually calls.

Each `.rs` file inside `native/` must export a `register_bifs()` function.
Register the `_wrapper` variant (not the original function):

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

#[matchbox_fn]
pub fn my_bif(n: f64) -> f64 {
    n * 2.0
}

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

The string key (`"my_bif"`) is the name BoxLang uses to call the function:

```boxlang
result = my_bif(21)
println(result)   // 42
```

### Supported Parameter Types

| Rust type | Macro conversion |
|---|---|
| `f64` | `args[i].as_number()` |
| `i32` | `args[i].as_int()` |
| `bool` | `args[i].as_bool()` |
| `String` | `vm.to_string(args[i])` |
| `BxValue` | passed through as-is |

---

## Native Objects with `#[matchbox_class]` and `#[matchbox_methods]`

For stateful interop, expose a Rust struct as a BoxLang native object.

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

// #[matchbox_class] auto-implements the BxNativeObject trait,
// wiring get_property / set_property / call_method to the
// dispatcher generated by #[matchbox_methods].
#[matchbox_class]
#[derive(Debug)]
pub struct Counter {
    pub value: f64,
}

// #[matchbox_methods] generates a dispatch_method() router that maps
// BoxLang method names (case-insensitive) to the Rust methods below.
#[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 — called when BoxLang evaluates `new rust:mymodule.Counter(0)`.
// vm.native_object_new() stores the object on the VM heap and returns an id
// wrapped in a BxValue pointer.
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))
}

// register_classes() maps "<module>.<ClassName>" to the constructor.
// The module name is the filename of this .rs file without the extension.
// BoxLang resolves `new rust:mymodule.Counter()` using this key.
pub fn register_classes() -> HashMap<String, BxNativeFunction> {
    let mut map = HashMap::new();
    map.insert("mymodule.Counter".to_string(), create_counter as BxNativeFunction);
    map
}
```

BoxLang:

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

## When to Use Native Fusion

- You need maximum throughput on a hot path (parsing, compression, crypto, ML).
- You want to use a Rust crate (`serde`, `image`, `reqwest`, etc.) from BoxLang.
- You need direct OS or hardware access.

For most application logic, plain BoxLang is sufficient. Reserve Native Fusion
for the innermost loops where performance is measured and critical.

## Limitations

| Feature | Status |
|---|---|
| Available in native builds | ✅ |
| Available in WASM builds | ❌ Not supported |
| Multiple `.rs` files in `native/` | ✅ Each may export `register_bifs()` and/or `register_classes()` |
| Using external Rust crates | ✅ Add a `Cargo.toml` to `native/` |
| Mutable `self` in `#[matchbox_methods]` | ✅ Dispatcher takes `&mut self` |
| Property access on native objects | ⚠️ Override `get_property` in `BxNativeObject` manually |

For the full macro API reference see [native-fusion.md](../../building-and-deploying/native-fusion.md).
