根据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的事情还没有结束。
试图将我的工具链切换为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。这是由于生锈环境的变化。