我正在使用 wasm-bindgen-futures
和 rust-webpack-template
试验 WASM 的 future ;完整 working代码和problem代码可用。
我的实验是从 JavaScript 调用 async fn run()
,由 fn run_js() -> js_sys::Promise
包装。以下是工作:
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())
}
下一步是添加 sleep 函数并从 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
转换 Future 0.3 -> Future 0.1 -> Promise,然后返回。为了完整起见,这里是 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)`
(添加和删节了更多源代码上下文;下面是完整版本)
我不知道错误是什么; something here is not Send
,但这是我从这里了解到的。
这在原则上不应该是可能的吗?或者我应该如何编写 sleep 函数才能正常工作?
完整的编译器输出:
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`
最佳答案
.boxed()
扩展函数要求 Future
为 Send
,因为 a recent change in futures .显然你的 future 不满足这个约束 - 可能是因为 JS futures 只在主 JS 线程上有效。
如果 .boxed()
发生在你的库范围内,你可以使用 Box::pin(future)
而不是 future.boxed()
以便在没有 Send
要求的情况下获得类型删除的盒装 future 。
关于async-await - 调用 FutureExt::boxed() 时缺少 Send 的实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56100028/