diff --git a/crates/matrix-sdk-common/src/lib.rs b/crates/matrix-sdk-common/src/lib.rs index 687e0ee13..ca768cd96 100644 --- a/crates/matrix-sdk-common/src/lib.rs +++ b/crates/matrix-sdk-common/src/lib.rs @@ -1,6 +1,8 @@ #![doc = include_str!("../README.md")] #![warn(missing_debug_implementations)] +use std::future::Future; + pub use instant; pub mod deserialized_responses; @@ -36,6 +38,13 @@ pub trait SyncOutsideWasm {} #[cfg(target_arch = "wasm32")] impl SyncOutsideWasm for T {} +/// Alias for `Future + SendOutsideWasm`. +/// +/// Useful as a separate trait because the former trait bound can't be used +/// with `dyn`. +pub trait FutureSendOutsideWasm: Future + SendOutsideWasm {} +impl FutureSendOutsideWasm for T {} + /// Super trait that is used for our store traits, this trait will differ if /// it's used on WASM. WASM targets will not require `Send` and `Sync` to have /// implemented, while other targets will. diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index 312ffeb95..aee95c648 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -32,7 +32,7 @@ use futures_signals::signal::Signal; use matrix_sdk_base::{ deserialized_responses::SyncResponse, media::{MediaEventContent, MediaFormat, MediaRequest, MediaThumbnailSize}, - BaseClient, Session, SessionMeta, SessionTokens, StateStore, + BaseClient, FutureSendOutsideWasm, Session, SessionMeta, SessionTokens, StateStore, }; use matrix_sdk_common::{ instant::{Duration, Instant}, @@ -110,7 +110,7 @@ const MIN_UPLOAD_REQUEST_TIMEOUT: Duration = Duration::from_secs(60 * 5); type EventHandlerMap = BTreeMap>; -type NotificationHandlerFut = Pin + Send>>; +type NotificationHandlerFut = Pin>>; type NotificationHandlerFn = Box NotificationHandlerFut + Send + Sync>; diff --git a/crates/matrix-sdk/src/event_handler.rs b/crates/matrix-sdk/src/event_handler.rs index 5e2b08abd..d7d16436f 100644 --- a/crates/matrix-sdk/src/event_handler.rs +++ b/crates/matrix-sdk/src/event_handler.rs @@ -43,7 +43,10 @@ use std::{ sync::atomic::Ordering::SeqCst, }; -use matrix_sdk_base::deserialized_responses::{EncryptionInfo, SyncRoomEvent}; +use matrix_sdk_base::{ + deserialized_responses::{EncryptionInfo, SyncRoomEvent}, + FutureSendOutsideWasm, SendOutsideWasm, +}; use ruma::{events::AnySyncStateEvent, serde::Raw, OwnedRoomId}; use serde::{de::DeserializeOwned, Deserialize}; use serde_json::value::RawValue as RawJsonValue; @@ -51,7 +54,7 @@ use tracing::{error, warn}; use crate::{room, Client}; -type EventHandlerFut = Pin + Send>>; +type EventHandlerFut = Pin>>; type EventHandlerFn = dyn Fn(EventHandlerData<'_>) -> EventHandlerFut + Send + Sync; #[doc(hidden)] @@ -181,7 +184,7 @@ impl EventHandlerContext for EventHandlerHandle { pub trait EventHandler: Send + Sync + 'static { /// The future returned by `handle_event`. #[doc(hidden)] - type Future: Future + Send + 'static; + type Future: Future + SendOutsideWasm + 'static; /// Create a future for handling the given event. /// @@ -540,7 +543,7 @@ macro_rules! impl_event_handler { where Ev: SyncEvent, Fun: Fn(Ev, $($ty),*) -> Fut + Send + Sync + 'static, - Fut: Future + Send + 'static, + Fut: Future + SendOutsideWasm + 'static, Fut::Output: EventHandlerResult, $($ty: EventHandlerContext),* { @@ -949,4 +952,20 @@ mod tests { assert_eq!(client.event_handlers().len(), 0); } + + #[async_test] + async fn use_client_in_handler() { + // This used to not work because we were requiring `Send` of event + // handler futures even on WASM, where practically all futures that do + // I/O aren't. + let client = no_retry_test_client(None).await; + + client.add_event_handler(|_ev: OriginalSyncRoomMemberEvent, client: Client| async move { + // All of Client's async methods that do network requests (and + // possibly some that don't) are `!Send` on wasm. We obviously want + // to be able to use them in event handlers. + let _caps = client.get_capabilities().await?; + anyhow::Ok(()) + }); + } }