簡體   English   中英

如何使用字符串作為參數從 Go 調用 Rust function?

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

我一直在嘗試將字符串傳遞給 Rust function(編譯為 Wasm),但是據我所知,目前無法直接傳遞字符串,因為“str”不是“FFI 世界”中的類型(至少 rust 編譯器是這么說的): = help: consider using `*const u8` and a length instead

所以我所做的是將 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)
}

這意味着我需要一個指針和 u8 中字符串的長度。

但是,有人讓我注意到 WASM 模塊是沙盒的,因此它們不能像普通應用程序那樣使用普通指針。 因此,我必須使用像這樣的 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)
}

這是一個使用 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;
}

我的問題是我不知道如何將此 function 轉換為 Go,這是因為我被困在“var mem”行,原因如下:

  • 我在 Go 中找不到等效的“instance.exports.memory.buffer”(實例是“*wasmtime.Instance”類型)。
  • 我不知道 Unit8Buffer 在 Go 中的作用。

閱讀有關 Wasm 中 memory 的好書:( https://radu-matei.com/blog/practical-guide-to-wasm-memory/#exchanging-strings-between-modules-and-runtimes

花了我一點時間來了解 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