При передаче строки в модуль Rust WASM переданные данные отображаются как пустые в соответствии с шаблоном в функции real_code::compute
Следующий код - это то, что я пробовал.Я не знаю, связано ли это с тем, как его возвращают, но когда я передаю жестко закодированный &str
, он работает нормально.Тем не менее, JsInteropString
отображается пустым.
Вот как я кодировал строку перед ее отправкой в WASM (из Передача строки JavaScript в функцию Rust, скомпилированную в 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 какthis:
//...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, она должна возвращать ту же самую переданную строку.Я даже зашел так далеко, что обновил мою среду Rust с помощью rustup ... есть идеи?
ОБНОВЛЕНИЕ
Используя более репрезентативную версию ссылочного поста:
#[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, он по-прежнему возвращает значение по умолчанию для вычисления,Я не знаю, действительно ли упомянутая ссылка решает проблему.
Так что да, код компилируется.Это проблема времени выполнения, которую я пытаюсь решить.Что-то не так в том, как строка кодируется и передается в WASM.
Обновление 2
Попытка переключения моей цепочки инструментов на Nightly, и я также обнаружил, что следующие макросы / атрибуты выдаютошибка, связанная с нестабильными атрибутами
#![feature(wasm_import_memory)]
#![wasm_import_memory]
После того, как я понял, что нужно сообщить ржавчине, что память будет импортирована, это, похоже, решило проблему передачи строки как пустой.Он не был пустым, его даже не передавали, кажется.
Внутри файла .cargo
[target.wasm32-unknown-unknown]
rustflags = [
"-Clink-args=-s EXPORTED_FUNCTIONS=['_func_to_call'] -s ASSERTIONS=1",
"-C", "link-args=--import-memory",
]
Похоже, что сработало!@Shepmaster, обновите свой ответ с прошлого года для тех, кто наткнулся на него, так как он имеет хороший SEO.Это связано с изменениями в среде ржавчины.