Строка JavaScript пуста при передаче в модуль Rust WebAssembly - PullRequest
0 голосов
/ 22 мая 2019

При передаче строки в модуль 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.Это связано с изменениями в среде ржавчины.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...