传递给Rust WebAssembly模块时,JavaScript字符串为空

时间:2019-05-22 01:10:32

标签: javascript rust wasm

根据real_code::compute函数中匹配的模式,将字符串传递给Rust WASM模块时,传递的数据显示为空白

以下代码是我尝试过的。我不知道它是否与返回值有关,但是当我传递一个硬编码的&str时,它可以正常工作。但是,JsInteropString显示为空白。

这是在将字符串发送到WASM之前(从Passing a JavaScript string to a Rust function compiled to WebAssembly发送给我)的方式

const memory = new WebAssembly.Memory({ initial: 20, 
                                        maximum: 100 });

const importObject = {
  env: { memory }
};

const memoryManager = (memory) => {
  var base = 0;

  // NULL is conventionally at address 0, so we "use up" the first 4
  // bytes of address space to make our lives a bit simpler.
  base += 4;

  return {
    encodeString: (jsString) => {
      // Convert the JS String to UTF-8 data
      const encoder = new TextEncoder();
      const encodedString = encoder.encode(jsString);

      // Organize memory with space for the JsInteropString at the
      // beginning, followed by the UTF-8 string bytes.
      const asU32 = new Uint32Array(memory.buffer, base, 2);
      const asBytes = new Uint8Array(memory.buffer, asU32.byteOffset + asU32.byteLength, encodedString.length);

      // Copy the UTF-8 into the WASM memory.
      asBytes.set(encodedString);

      // Assign the data pointer and length values.
      asU32[0] = asBytes.byteOffset;
      asU32[1] = asBytes.length;

      // Update our memory allocator base address for the next call
      const originalBase = base;
      base += asBytes.byteOffset + asBytes.byteLength;

      return originalBase;
    }
  };
};

像这样调用wasm:

//...loading and compiling WASM, getting instance from promise (standard)
const testStr = "TEST"
const input = myMemory.encodeString(testStr);
const offset = instance.exports.func_to_call(input);
// A struct with a known memory layout that we can pass string information in
#[repr(C)]
pub struct JsInteropString {
    data: *const u8,
    len: usize,
}

// Our FFI shim function
#[no_mangle]
pub unsafe extern "C" fn func_to_call(s: *const JsInteropString) -> *mut c_char {
    // ... check for nulls etc

    /*
    THROWS ERROR
    error[E0609]: no field `data` on type `*const JsInteropString`
    */
    //////let data = std::slice::from_raw_parts(s.data, s.len);

    //this fixes the above error
    let data = std::slice::from_raw_parts((*s).data, (*s).len);

    let dataToPrint: Result<_, _> = std::str::from_utf8(data);

    let real_res: &str = match dataToPrint {
        Ok(s) => real_code::compute(dataToPrint.unwrap()), //IS BLANK
        //Ok(s) => real_code::compute("SUCCESS"), //RETURNS "SUCCESS made it"
        Err(_) => real_code::compute("ERROR"),
    };

    unsafe {
        let s = CString::new(real_res).unwrap();
        println!("result: {:?}", &s);
        s.into_raw()
    }
}

mod real_code {
    pub fn compute(operator: &str) -> &str {
        match operator {
            "SUCCESS" => "SUCCESS made it",
            "ERROR" => "ERROR made it",
            "TEST" => "TEST made it",
            _ => operator,
        }
    }
}

从JavaScript调用该函数时,应返回传递的相同字符串。我什至竭力用rustup更新我的Rust环境...有什么想法吗?

更新

使用所引用帖子的更具代表性的版本:

#[no_mangle]
pub unsafe extern "C" fn compute(s: *const JsInteropString) -> i32 {

    let s = match s.as_ref() {
        Some(s) => s,
        None => return -1,
    };

    // Convert the pointer and length to a `&[u8]`.
    let data = std::slice::from_raw_parts(s.data, s.len);

    // Convert the `&[u8]` to a `&str`    
    match std::str::from_utf8(data) {
        Ok(s) => real_code::compute(s),
        Err(_) => -2,
    }

}

mod real_code {
    pub fn compute(operator: &str) -> i32 {
        match operator {
            "SUCCESS"  => 1,
            "ERROR" => 2,
            "TEST" => 3,
            _ => 10,
        }
    }
}

无论通过js编码传递的字符串如何,它仍然会返回来自compute的默认值。我不知道所引用的帖子是否真的可以解决问题。

是的,代码可以编译。这是我要解决的运行时问题。关于如何对字符串进行编码并将其传递给WASM的事情还没有结束。

更新2

试图将我的工具链切换为Nightly,并且我还发现以下宏/属性会引发有关不稳定属性的错误

#![feature(wasm_import_memory)]
#![wasm_import_memory]

意识到我需要告诉rust内存将被导入后,这似乎已经解决了将字符串传递为空的问题。它不是空的,甚至都没有通过。

.cargo文件内部

[target.wasm32-unknown-unknown]
rustflags = [
    "-Clink-args=-s EXPORTED_FUNCTIONS=['_func_to_call'] -s ASSERTIONS=1",
    "-C", "link-args=--import-memory",
]

这似乎可以解决问题! @Shepmaster,从去年开始为其他偶然发现它的人更新您的答案,因为它具有良好的SEO。这是由于生锈环境的变化。

0 个答案:

没有答案