Hi everyone :wave:. I came here to share the Wasmtime Ruby gem I've been working on for a little while.
https://github.com/dtcristo/wasmtime-ruby
It's quite primitive at the moment, but I hope to wrap more of the Wasmtime API over time. I will aim to keep the Ruby API as close to the Wasmtime API as possible just like wasmtime-py
.
I'm using the Rust embedding API directly, rather than the C API. Not sure if this is the best approach, but I'm not super comfortable with C and would rather write Rust :). But it works and the Rust support for Ruby native extensions seems good enough. I've opted for shipping pre-compiled binaries (just Linux and macOS right now) in the gem so users don't need Rust to use it.
I'm pretty excited for Interface Types support to drop and I'm following the issue closely. Supporting this will be important.
I'm keen for any feedback.
Also, if you folks like it and once it gets more feature complete and has docs. I'd be happy to eventually migrate it to the bytecodealliance
org. I've chosen the Apache-2.0 WITH LLVM-exception
license for compatibility.
@David Cristofaro nice! At the very least we should definitely add to the wasmtime README once you feel the bindings are ready
Hey team! I have a small function that manipulates strings in AssemblyScript, successfully built into a .wasm release package that I'm trying to call with Ruby.
However, using wasmtime-rb has been a little problematic for me. I want to pass a Ruby string in, and get a Ruby string out.
For getting the Ruby string out, I understood I need to read the instance memory bytes in the UTF-16 encoding, and whatever I return from the function I can read fine. However, I'm struggling with setting up the input correctly.
I tried to allocate my string to the instance memory (successfully), and run the function with a number pointing to the memory location (successfully) - but inside of the function it reports the AssemblyScript string as empty.
Here's the AssemblyScript:
export function testString(inputString: string): string {
return `Str length: ${inputString.length}, string: >>${inputString}<<`;
}
And here's how I try to call it with Ruby:
require 'wasmtime'
# Helper function to read a null-terminated string from WASM memory
def read_string(memory, ptr)
bytes = []
loop do
byte1 = memory.read(ptr, 1)
byte2 = memory.read(ptr + 1, 1)
break if byte1.nil? || byte2.nil? || (byte1.bytes.first == 0 && byte2.bytes.first == 0)
bytes << byte1.bytes.first
bytes << byte2.bytes.first
ptr += 2
end
bytes.pack('C*').force_encoding('UTF-16LE').encode('UTF-8')
end
# Load the WebAssembly module bytes
wasm_bytes = File.read('build/release.wasm', mode: 'rb')
# Create an engine and store
engine = Wasmtime::Engine.new
store = Wasmtime::Store.new(engine)
# Compile the module
mod = Wasmtime::Module.new(engine, wasm_bytes)
# Instantiate the module with the imports
instance = Wasmtime::Instance.new(store, mod, [])
# Access the exported memory
instance_memory = instance.export('memory').to_memory
# Access the exported 'testString' function
# TODO: https://docs.wasmtime.dev/api/wasmtime/struct.ExternRef.html probably need to define the ExternRef to correctly work with host strings, which is what I want here?
test_string = instance.exports['testString'].to_func
input_string = "Hello, Wasm!"
# Write the string to WASM memory
# TODO: no idea which pointer is a good pointer; 0x00 didn't work, 0x1000 didn't work
string_ptr = 0x30
instance_memory.write(string_ptr, input_string)
p "Calling testString(#{string_ptr}, #{input_string.bytesize})"
result_ptr = test_string.call(string_ptr)
# Read the result string from WASM memory
p "Result pointer: #{result_ptr}, reading from memory"
p read_string(instance_memory, result_ptr)
I tried using custom memory instances too but that also didn't help. I read through the wasmtime-rb examples multiple times but still don't get how to pass in the string (or, probably any other more complex object) correctly.
Any tips appreciated! Thank you
Are you familiar with the memory layout used by classes in AssemblyScript? Also are you calling a function within the Wasm instance to allocate the memory? The code sample above looks to me like it's using an arbitrary index in linear memory.
Last updated: Dec 23 2024 at 14:03 UTC