简体   繁体   English

如何使用字符串作为参数从 Go 调用 Rust function?

[英]How do I call a Rust function from Go with a string as a parameter?

I have been trying to pass a string to a Rust function (compiled to Wasm), however for what I understood, right now there is no way to pass strings directy, because the "str" is not a type in the "FFI world" (at least that's what the rust compiler is saying): = help: consider using `*const u8` and a length instead我一直在尝试将字符串传递给 Rust function(编译为 Wasm),但是据我所知,目前无法直接传递字符串,因为“str”不是“FFI 世界”中的类型(至少 rust 编译器是这么说的): = help: consider using `*const u8` and a length instead

So what I did was changing the function to this form (instead of using a simple &str type):所以我所做的是将 function 更改为这种形式(而不是使用简单的 &str 类型):

#[no_mangle]
pub extern "C" fn greet(s: *mut u8, len: usize) {
    let s = std::str::from_utf8(unsafe { std::slice::from_raw_parts(s, len) }).unwrap();
    println!("Hello, {}!", s)
}

This means that I need a pointer and the length of the string in u8.这意味着我需要一个指针和 u8 中字符串的长度。

However, someone made me notice that WASM modules are sandboxed, so they can't use normal pointers like normal applications.但是,有人让我注意到 WASM 模块是沙盒的,因此它们不能像普通应用程序那样使用普通指针。 Thus, I have to use a function like this one to allocate memory into the module's linear memory:因此,我必须使用像这样的 function 将 memory 分配到模块的线性 memory 中:

use std::alloc::{alloc, dealloc, Layout};
#[no_mangle]
pub unsafe fn my_alloc(len: usize) -> *mut u8 {
    let align = std::mem::align_of::<usize>();
    let layout = Layout::from_size_align_unchecked(size, align);
    alloc(layout)
}

This is an example of a JS function that uses an alloc function like this one:这是一个使用 alloc function 的 JS function 示例,如下所示:

function copyMemory(data, instance) {
  var ptr = instance.exports.alloc(data.length);
  var mem = new Uint8Array(instance.exports.memory.buffer, ptr, data.length);
  mem.set(new Uint8Array(data));
  return ptr;
}

My problem is that I don't know how to convert this function to Go, that's because I am stuck at the "var mem" line, for these reasons:我的问题是我不知道如何将此 function 转换为 Go,这是因为我被困在“var mem”行,原因如下:

  • I can't find the equivalent of "instance.exports.memory.buffer" in Go (instance is a "*wasmtime.Instance" type).我在 Go 中找不到等效的“instance.exports.memory.buffer”(实例是“*wasmtime.Instance”类型)。
  • I don't know how to do what Unit8Buffer does in Go.我不知道 Unit8Buffer 在 Go 中的作用。

Good read about memory in Wasm: ( https://radu-matei.com/blog/practical-guide-to-wasm-memory/#exchanging-strings-between-modules-and-runtimes )阅读有关 Wasm 中 memory 的好书:( https://radu-matei.com/blog/practical-guide-to-wasm-memory/#exchanging-strings-between-modules-and-runtimes

Took me a little to understand exactly how the wasmtime Go-package worked, but in the end I resolved my problem doing this:花了我一点时间来了解 wasmtime Go-package 是如何工作的,但最后我解决了我的问题:

func main() {
    dir, err := ioutil.TempDir("", "out")
    check(err)
    defer os.RemoveAll(dir)
    stdoutPath := filepath.Join(dir, "stdout")

    engine := wasmtime.NewEngine()
    store := wasmtime.NewStore(engine)

    linker := wasmtime.NewLinker(store)

    // Configure WASI imports to write stdout into a file.
    wasiConfig := wasmtime.NewWasiConfig()
    wasiConfig.SetStdoutFile(stdoutPath)


    wasi, err := wasmtime.NewWasiInstance(store, wasiConfig, "wasi_snapshot_preview1")
    check(err)

    // Link WASI
    err = linker.DefineWasi(wasi)
    check(err)

    // Create our module
    module, err := wasmtime.NewModuleFromFile(store.Engine, "wasm_file.wasm")
    check(err)
    instance, err := linker.Instantiate(module)
    check(err)


    fn := instance.GetExport("greet").Func()
    memory := instance.GetExport("memory").Memory()
    alloc := instance.GetExport("my_alloc").Func()

    // // string for alloc
    size2 := int32(len([]byte("Elvis")))

    // //Allocate memomory
    ptr2, err := alloc.Call(size2)
    pointer, _ := ptr2.(int32)

    buf := memory.UnsafeData()
    for i, v := range []byte("Elvis") {
        buf[pointer+int32(i)] = v
    }

    // Use string func
    _, err = fn.Call(pointer, size2 )
    check(err)
    
    // Print WASM stdout
    out, err := ioutil.ReadFile(stdoutPath)
    check(err)
    fmt.Print(string(out))
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM