I'm looking at using Roc as a kind of replacement for Lua. However I see its a compiled language rather than scripting language, so I guess I could compile it to wasm and run it from Rust.
If I assumed things correctly, I have a few questions:
It's not super easy right now, but doable. There's a few things in development which make platform development more difficult than it will be in future.
I have a template https://github.com/lukewilliamboswell/roc-platform-template-wasi which does what you are looking for. It currently uses a build script using build.sh
which you can see the steps manually. We have some WIP PR's which should unlock more WASI/WASM type workflows but that hasn't landed yet.
Would I just use Wasmtime to execute the Roc script? Or is there a better way to do so without even compiling Roc to wasm?
You can make a custom roc platform that compiles your roc app/script/plugin to WASM/WASI, and then load that an run it using something like wasmtime.
If it is compiled to wasm, how would I share data between Roc and my host Rust app? I could use Json or something of course, but is there any other approaches similar to wasm bindgen?
The example template I shared above is using zig for the (roc platform) host language. If you use rust then you can use wasm bindgen to simplify data across the WASM boundary
It can be difficult to talk about this idea specifically because there are multiple layers and terms that are overloaded, like the roc platform has a host and the wasm runtime is also a host... so it can get confusing.
Would I just use Wasmtime to execute the Roc script? Or is there a better way to do so without even compiling Roc to wasm?
The other option which is much simpler is to use roc in what I think of as a plugin. Have your rust app compile the roc source to a dynamic library (using roc as a library "libroc" by pointing cargo at the compiler repository, or even just shelling out using std::process::Command) and then load the library at runtime to run the roc app.
This is what roc does internally with the roc glue
subcommand, where the end user provides a glue script and the roc cli compiles and then runs that to generate the glue files.
I had a crack at doing this to make an example and see what is involved.
https://github.com/lukewilliamboswell/roc-plugin-experiment-rust
I got pretty far, it builds and runs fine... but there is something not quite right as it doesn't look like roc is running when I call it, or at least it doesn't appear to be modifying the input at all.
I'm hoping @Brendan Hansknecht or @Folkert de Vries or someone can see my problem as it's probably something simple I'm missing I think.
One hunch I have is that I'm providing an implementation of roc_alloc
and friends to satisfy roc_std
which is linked in at build time and then the host also provides an implementation of roc_alloc
for linking with the script... and maybe these two need to be the same implementation. :man_shrugging:
This is awesome, thank you for the detailed response Luke!
Since what I'm building is a little more than just a side project, I'll probably have to stick with a simpler approach for now until Roc has some more stability and documentation for this kind of thing. But I'll still check out the GH repos you linked thanks for taking the time for that
Ok, I got carried away (and Folkert helped to) and now it works :tada:
https://github.com/lukewilliamboswell/roc-plugin-experiment-rust
Definitely one of the coolest experiments I've put together in a little while.
I can see how this could be easily expanded to more complicated platforms with a Task based API etc.
I haven't tested this on linux, but tried to use some cfg
flags so hopefully it should just work.
In the end I had everything setup correctly but we have a bug where the codegen isn't correct for
mainForHost : U64 -> Str
mainForHost = main
But is for
mainForHost : U64 -> Str
mainForHost = \x -> main x
:smiley:
Last updated: Jul 06 2025 at 12:14 UTC