|
1 | 1 | use wasmtime::*;
|
2 | 2 | //use anyhow::Error as anyhowError;
|
3 | 3 | use rustler::{Atom, Env, Error, NifStruct, ResourceArc, Term};
|
| 4 | +use std::convert::TryInto; |
4 | 5 |
|
5 | 6 | #[rustler::nif]
|
6 | 7 | fn add(a: i64, b: i64) -> i64 {
|
@@ -121,6 +122,14 @@ fn wasm_buffer_2_i32(wat_source: String, f: String, a: i32, b: i32) -> Result<Ve
|
121 | 122 | }
|
122 | 123 | }
|
123 | 124 |
|
| 125 | +#[rustler::nif] |
| 126 | +fn wasm_string_2_i32(wat_source: String, f: String, a: i32, b: i32) -> Result<String, Error> { |
| 127 | + return match wasm_example_2_i32_string_internal(wat_source, f, a, b) { |
| 128 | + Ok(v) => Ok(v), |
| 129 | + Err(e) => Err(Error::Term(Box::new(e.to_string()))) |
| 130 | + } |
| 131 | +} |
| 132 | + |
124 | 133 | fn wasm_example_2_i32_internal(wat_source: String, buffer: bool, f: String, a: i32, b: i32) -> Result<i32, anyhow::Error> {
|
125 | 134 | let engine = Engine::default();
|
126 | 135 |
|
@@ -222,11 +231,62 @@ fn wasm_example_2_i32_n_internal(wat_source: String, buffer: bool, f: String, a:
|
222 | 231 | return Ok(result);
|
223 | 232 | }
|
224 | 233 |
|
| 234 | +fn wasm_example_2_i32_string_internal(wat_source: String, f: String, a: i32, b: i32) -> Result<String, anyhow::Error> { |
| 235 | + let engine = Engine::default(); |
| 236 | + |
| 237 | + // A `Store` is what will own instances, functions, globals, etc. All wasm |
| 238 | + // items are stored within a `Store`, and it's what we'll always be using to |
| 239 | + // interact with the wasm world. Custom data can be stored in stores but for |
| 240 | + // now we just use `()`. |
| 241 | + let mut store = Store::new(&engine, ()); |
| 242 | + let mut linker = Linker::new(&engine); |
| 243 | + |
| 244 | + let memory_ty = MemoryType::new(1, None); |
| 245 | + let memory = Memory::new(&mut store, memory_ty)?; |
| 246 | + linker.define(&store, "env", "buffer", memory)?; |
| 247 | + |
| 248 | + // We start off by creating a `Module` which represents a compiled form |
| 249 | + // of our input wasm module. In this case it'll be JIT-compiled after |
| 250 | + // we parse the text format. |
| 251 | + let module = Module::new(&engine, wat_source)?; |
| 252 | + |
| 253 | + // With a compiled `Module` we can then instantiate it, creating |
| 254 | + // an `Instance` which we can actually poke at functions on. |
| 255 | + // let instance = Instance::new(&mut store, &module, &[])?; |
| 256 | + let instance = linker.instantiate(&mut store, &module)?; |
| 257 | + |
| 258 | + // The `Instance` gives us access to various exported functions and items, |
| 259 | + // which we access here to pull out our `answer` exported function and |
| 260 | + // run it. |
| 261 | + let answer = instance |
| 262 | + .get_func(&mut store, &f) |
| 263 | + .expect(&format!("{} was not an exported function", f)); |
| 264 | + |
| 265 | + // There's a few ways we can call the `answer` `Func` value. The easiest |
| 266 | + // is to statically assert its signature with `typed` (in this case |
| 267 | + // asserting it takes no arguments and returns one i32) and then call it. |
| 268 | + let answer = answer.typed::<(i32, i32), (i32, i32)>(&store)?; |
| 269 | + |
| 270 | + // And finally we can call our function! Note that the error propagation |
| 271 | + // with `?` is done to handle the case where the wasm function traps. |
| 272 | + let (start, length) = answer.call(&mut store, (a, b))?; |
| 273 | + let start: usize = start.try_into().unwrap(); |
| 274 | + let length: usize = length.try_into().unwrap(); |
| 275 | + |
| 276 | + let mut string_buffer: Vec<u8> = Vec::with_capacity(length); |
| 277 | + string_buffer.resize(length, 0); |
| 278 | + memory.read(&store, start, &mut string_buffer)?; |
| 279 | + let string = String::from_utf8(string_buffer)?; |
| 280 | + |
| 281 | + return Ok(string); |
| 282 | +} |
| 283 | + |
225 | 284 | rustler::init!("Elixir.ComponentsGuide.Rustler.Math", [
|
226 | 285 | add,
|
227 | 286 | reverse_string,
|
228 | 287 | wasm_example_0,
|
229 | 288 | wasm_example_1_i32,
|
230 | 289 | wasm_example_2_i32,
|
231 |
| - wasm_buffer_2_i32 |
| 290 | + wasm_buffer_2_i32, |
| 291 | + wasm_string_2_i32 |
232 | 292 | ]);
|
0 commit comments