2 unstable releases
0.2.0 | Nov 19, 2024 |
---|---|
0.1.0 | Nov 18, 2024 |
#596 in Web programming
323 downloads per month
21KB
389 lines
Elm Rust Binding
This crate offers a way to conveniently call an Elm function from Rust. The main motivation here is for testing purposes:
- You have some logic in your Elm frontend that cannot be moved to the backend (because e.g. it is called in a hot loop)
- You have related logic in your Rust backend
Then you can call your Elm code in a Rust test with this crate to verify the two implementations are in sync. The performance this crate offers is NOT optimal - do not use this for Interop in production code.
Example
Rust side
use elm_rust_binding::{ElmRoot, Result};
#[test]
fn call_elm() -> Result<()> {
let mut elm_root = ElmRoot::new("../frontend/src")?;
let mut square_fn = elm_root.prepare("Math.square")?;
let squared = square_fn.call(4)?;
assert_eq!(squared, 16);
Ok(())
}
Elm side
-- In /frontend/src/Math.elm
module Math exposing (square)
square : Int -> Int
square n = n * n
Note that you can call the function multiple times, which will improve performance over creating a new ElmRoot
and ElmFunctionHandle
.
This is especially useful for fuzz/property-based testing
Implementation Details
How does this work under the hood? It essentially boils down to 6 steps:
- Infer the Elm input and output types based on the Rust type annotations (i32 -> Int, bool -> Bool, etc.).
- Generate an .elm file with a
Platform.worker
main function. It will accept the input type over its flags and return the output type via a port. Internally it will call the specified function by importing it. - Invoke the Elm compiler on the generated file, producing a .js file.
- Make the produced .js file ESM-compatible.
- Load the module into a Deno runtime.
- Initialize the Elm application every time
.call
is invoked by passing the input argument as flags and getting the output via.subscribe
.
The generated files are removed automatically and are postfixed with a UUID to prevent different invocations messing with each other.
If you call .debug()
on the ElmRoot
, the files are not removed to help debugging issues.
Dependencies
~95MB
~2M SLoC