Реализация Send отсутствует при вызове FutureExt :: boxed () - PullRequest
1 голос
/ 12 мая 2019

Я экспериментирую с фьючерсами на WASM, используя wasm-bindgen-futures и rust-webpack-template; полный рабочий код и проблема код доступен.

Мой эксперимент - вызвать async fn run(), обернутый fn run_js() -> js_sys::Promise, из JavaScript. Работает следующее:

pub async fn run() -> Result<(), JsValue> {
    Ok(())
}

// Called by our JS entry point to run the example.
#[wasm_bindgen(js_name = run)]
pub fn run_js() -> js_sys::Promise {
    use crate::compat::future_to_promise;
    use futures::future::FutureExt;

    future_to_promise(async move {
        run().await?;
        Ok(JsValue::UNDEFINED)
    }.boxed())
}

Следующим шагом было добавление функции сна и вызов ее из run():

// in run:
sleep(500).await?;

pub async fn sleep(millis: i32) -> Result<(), JsValue> {
    use crate::compat::promise_to_future;

    let promise = js_sys::Promise::new(&mut move |resolve, _| {
        let window = web_sys::window().expect("should have a Window");
        window.set_timeout_with_callback_and_timeout_and_arguments_0(
            &resolve, millis
        ).expect("don't expect error on setTimeout()");
    });

    promise_to_future(promise).await?;
    Ok(())
}

crate::compat преобразует Будущее 0,3 -> Будущее 0,1 -> Обещание и обратно. Для полноты, вот promise_to_future:

pub fn promise_to_future(promise: Promise) -> impl Future<Output=Result<JsValue, JsValue>> {
    // promise to 0.1
    let future01 = JsFuture::from(promise);
    // 0.1 to 0.3
    Compat01As03::new(future01)
}

Добавляя это, я получаю ошибку компиляции здесь:

error[E0277]: `*mut u8` cannot be sent between threads safely
  --> src/lib.rs:45:7
   |
42 |     future_to_promise(async move {
43 |         run().await?;
44 |         Ok(JsValue::UNDEFINED)
45 |     }.boxed())
   |       ^^^^^ `*mut u8` cannot be sent between threads safely
   |
   = help: within `impl core::future::future::Future`, the trait `std::marker::Send` is not implemented for `*mut u8`
error[E0277]: `(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)` cannot be sent between threads safely
  --> src/lib.rs:45:7
   |
42 |     future_to_promise(async move {
43 |         run().await?;
44 |         Ok(JsValue::UNDEFINED)
45 |     }.boxed())
   |       ^^^^^ `(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)` cannot be sent between threads safely
   |
   = help: the trait `std::marker::Send` is not implemented for `(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)`

(больше контекста исходного кода добавлено и сокращено; полная версия ниже)

Я не могу понять, что это за ошибка; что-то здесь не Send, но это примерно столько, сколько я понимаю из этого.

Разве это не должно быть возможно в принципе? Или как мне правильно написать функцию сна?


Полный вывод компилятора:

   Compiling rust-webpack v0.1.0 (/data/Documents/Programmieren/rust/hello-web/crate)
error[E0277]: `*mut u8` cannot be sent between threads safely
  --> src/lib.rs:45:7
   |
45 |     }.boxed())
   |       ^^^^^ `*mut u8` cannot be sent between threads safely
   |
   = help: within `impl core::future::future::Future`, the trait `std::marker::Send` is not implemented for `*mut u8`
   = note: required because it appears within the type `std::marker::PhantomData<*mut u8>`
   = note: required because it appears within the type `wasm_bindgen::JsValue`
   = note: required because it appears within the type `js_sys::Object`
   = note: required because it appears within the type `js_sys::Promise`
   = note: required because it appears within the type `{i32, js_sys::Promise, fn(std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}`
   = note: required because it appears within the type `[static generator@src/sleep.rs:4:56: 16:2 millis:i32 {i32, js_sys::Promise, fn(std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]`
   = note: required because it appears within the type `std::future::GenFuture<[static generator@src/sleep.rs:4:56: 16:2 millis:i32 {i32, js_sys::Promise, fn(std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]>`
   = note: required because it appears within the type `impl core::future::future::Future`
   = note: required because it appears within the type `impl core::future::future::Future`
   = note: required because it appears within the type `{fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}`
   = note: required because it appears within the type `[static generator@src/lib.rs:16:43: 34:2 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]`
   = note: required because it appears within the type `std::future::GenFuture<[static generator@src/lib.rs:16:43: 34:2 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]>`
   = note: required because it appears within the type `impl core::future::future::Future`
   = note: required because it appears within the type `impl core::future::future::Future`
   = note: required because it appears within the type `{fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}`
   = note: required because it appears within the type `[static generator@src/lib.rs:42:34: 45:6 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]`
   = note: required because it appears within the type `std::future::GenFuture<[static generator@src/lib.rs:42:34: 45:6 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]>`
   = note: required because it appears within the type `impl core::future::future::Future`

error[E0277]: `(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)` cannot be sent between threads safely
  --> src/lib.rs:45:7
   |
45 |     }.boxed())
   |       ^^^^^ `(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)` cannot be sent between threads safely
   |
   = help: the trait `std::marker::Send` is not implemented for `(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)`
   = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>`
   = note: required because it appears within the type `std::boxed::Box<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>`
   = note: required because it appears within the type `std::mem::ManuallyDrop<std::boxed::Box<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>>`
   = note: required because it appears within the type `wasm_bindgen::closure::Closure<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>`
   = note: required because it appears within the type `(wasm_bindgen::closure::Closure<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>, wasm_bindgen::closure::Closure<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>)`
   = note: required because it appears within the type `std::option::Option<(wasm_bindgen::closure::Closure<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>, wasm_bindgen::closure::Closure<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>)>`
   = note: required because it appears within the type `wasm_bindgen_futures::JsFuture`
   = note: required because it appears within the type `futures::task_impl::Spawn<wasm_bindgen_futures::JsFuture>`
   = note: required because it appears within the type `futures_util::compat::compat01as03::Compat01As03<wasm_bindgen_futures::JsFuture>`
   = note: required because it appears within the type `impl core::future::future::Future`
   = note: required because it appears within the type `{i32, js_sys::Promise, fn(std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}`
   = note: required because it appears within the type `[static generator@src/sleep.rs:4:56: 16:2 millis:i32 {i32, js_sys::Promise, fn(std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]`
   = note: required because it appears within the type `std::future::GenFuture<[static generator@src/sleep.rs:4:56: 16:2 millis:i32 {i32, js_sys::Promise, fn(std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]>`
   = note: required because it appears within the type `impl core::future::future::Future`
   = note: required because it appears within the type `impl core::future::future::Future`
   = note: required because it appears within the type `{fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}`
   = note: required because it appears within the type `[static generator@src/lib.rs:16:43: 34:2 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]`
   = note: required because it appears within the type `std::future::GenFuture<[static generator@src/lib.rs:16:43: 34:2 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]>`
   = note: required because it appears within the type `impl core::future::future::Future`
   = note: required because it appears within the type `impl core::future::future::Future`
   = note: required because it appears within the type `{fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}`
   = note: required because it appears within the type `[static generator@src/lib.rs:42:34: 45:6 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]`
   = note: required because it appears within the type `std::future::GenFuture<[static generator@src/lib.rs:42:34: 45:6 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]>`
   = note: required because it appears within the type `impl core::future::future::Future`

1 Ответ

1 голос
/ 13 мая 2019

Функция расширения .boxed() требует, чтобы Future было Send, поскольку недавнее изменение фьючерса . Очевидно, ваше будущее не соответствует этому ограничению - вероятно, потому что фьючерсы JS действительны только в основном потоке JS.

Если в области видимости вашей библиотеки происходит .boxed(), вы можете использовать Box::pin(future) вместо future.boxed(), чтобы получить стертое в штучной упаковке будущее без требования Send.

...