Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start addressing some wasm32-unknown-unknown errors for matrix-sdk-ui crate #4122

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions crates/matrix-sdk-base/src/client.rs
Original file line number Diff line number Diff line change
@@ -22,9 +22,7 @@ use std::{
};

use eyeball::{SharedObservable, Subscriber};
#[cfg(not(target_arch = "wasm32"))]
use eyeball_im::{Vector, VectorDiff};
#[cfg(not(target_arch = "wasm32"))]
use futures_util::Stream;
#[cfg(feature = "e2e-encryption")]
use matrix_sdk_crypto::{
@@ -234,7 +232,6 @@ impl BaseClient {

/// Get a stream of all the rooms changes, in addition to the existing
/// rooms.
#[cfg(not(target_arch = "wasm32"))]
pub fn rooms_stream(&self) -> (Vector<Room>, impl Stream<Item = Vec<VectorDiff<Room>>>) {
self.store.rooms_stream()
}
7 changes: 5 additions & 2 deletions crates/matrix-sdk-base/src/read_receipts.rs
Original file line number Diff line number Diff line change
@@ -123,7 +123,10 @@ use std::{
};

use eyeball_im::Vector;
use matrix_sdk_common::{deserialized_responses::SyncTimelineEvent, ring_buffer::RingBuffer};
use matrix_sdk_common::{
deserialized_responses::SyncTimelineEvent, ring_buffer::RingBuffer, SendOutsideWasm,
SyncOutsideWasm,
};
use ruma::{
events::{
poll::{start::PollStartEventContent, unstable_start::UnstablePollStartEventContent},
@@ -266,7 +269,7 @@ impl RoomReadReceipts {
}

/// Provider for timeline events prior to the current sync.
pub trait PreviousEventsProvider: Send + Sync {
pub trait PreviousEventsProvider: SendOutsideWasm + SyncOutsideWasm {
/// Returns the list of known timeline events, in sync order, for the given
/// room.
fn for_room(&self, room_id: &RoomId) -> Vector<SyncTimelineEvent>;
3 changes: 0 additions & 3 deletions crates/matrix-sdk-base/src/store/mod.rs
Original file line number Diff line number Diff line change
@@ -29,9 +29,7 @@ use std::{
sync::{Arc, RwLock as StdRwLock},
};

#[cfg(not(target_arch = "wasm32"))]
use eyeball_im::{Vector, VectorDiff};
#[cfg(not(target_arch = "wasm32"))]
use futures_util::Stream;
use once_cell::sync::OnceCell;

@@ -266,7 +264,6 @@ impl Store {

/// Get a stream of all the rooms changes, in addition to the existing
/// rooms.
#[cfg(not(target_arch = "wasm32"))]
pub fn rooms_stream(&self) -> (Vector<Room>, impl Stream<Item = Vec<VectorDiff<Room>>>) {
self.rooms.read().unwrap().stream()
}
13 changes: 11 additions & 2 deletions crates/matrix-sdk-base/src/store/observable_map.rs
Original file line number Diff line number Diff line change
@@ -149,6 +149,9 @@ mod impl_non_wasm32 {
mod impl_wasm32 {
use std::{borrow::Borrow, collections::BTreeMap, hash::Hash};

use eyeball_im::{Vector, VectorDiff};
use futures_util::{stream, Stream, StreamExt};

/// An observable map for Wasm. It's a simple wrapper around `BTreeMap`.
#[derive(Debug)]
pub(crate) struct ObservableMap<K, V>(BTreeMap<K, V>)
@@ -197,15 +200,21 @@ mod impl_wasm32 {
self.0.values()
}

/// Get a [`Stream`] of the values.
pub(crate) fn stream(&self) -> (Vector<V>, impl Stream<Item = Vec<VectorDiff<V>>>) {
self.values.subscribe().into_values_and_batched_stream()
}

/// Remove a `V` value based on their ID, if it exists.
///
/// Returns the removed value.
pub(crate) fn remove<L>(&mut self, key: &L) -> Option<V>
where
K: Borrow<L>,
L: Hash + Eq + Ord + ?Sized,
L: Hash + Eq + ?Sized,
{
self.0.remove(key)
let position = self.mapping.remove(key)?;
Some(self.values.remove(position))
}
}
}
5 changes: 4 additions & 1 deletion crates/matrix-sdk-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -31,13 +31,16 @@ tokio = { workspace = true, features = ["rt", "time"] }
uniffi = { workspace = true, optional = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
futures-util = { workspace = true, features = ["channel"] }
wasm-bindgen-futures = { version = "0.4.33", optional = true }
gloo-timers = { version = "0.3.0", features = ["futures"] }
futures-util = { workspace = true, features = ["channel"] }
web-sys = { version = "0.3.60", features = ["console"] }
tracing-subscriber = { workspace = true, features = ["fmt", "ansi"] }
wasm-bindgen = "0.2.84"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
futures-util = { workspace = true }

[dev-dependencies]
assert_matches = { workspace = true }
proptest = { version = "1.4.0", default-features = false, features = ["std"] }
88 changes: 82 additions & 6 deletions crates/matrix-sdk-common/src/executor.rs
Original file line number Diff line number Diff line change
@@ -14,8 +14,6 @@

//! Abstraction over an executor so we can spawn tasks under WASM the same way
//! we do usually.

#[cfg(target_arch = "wasm32")]
use std::{
future::Future,
pin::Pin,
@@ -25,13 +23,17 @@ use std::{
#[cfg(target_arch = "wasm32")]
pub use futures_util::future::Aborted as JoinError;
#[cfg(target_arch = "wasm32")]
use futures_util::{
future::{AbortHandle, Abortable, RemoteHandle},
FutureExt,
};
use futures_util::future::{AbortHandle, Abortable, RemoteHandle};
use futures_util::FutureExt;
#[cfg(not(target_arch = "wasm32"))]
pub use tokio::task::{spawn, JoinError, JoinHandle};

/// A `Box::pin` future that is `Send` on non-wasm, and without `Send` on wasm.
#[cfg(target_arch = "wasm32")]
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
#[cfg(not(target_arch = "wasm32"))]
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
Comment on lines +32 to +35
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#[cfg(target_arch = "wasm32")]
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
#[cfg(not(target_arch = "wasm32"))]
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + SendOutsideWasm + 'a>>;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this definition already existed though, why did you move it here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I needed to expose the .boxed method on the wasm version of the code (it was present on the real future, but not the Wasm version). It seemed like this was where the wasm future was being defined, so I wanted to move the BoxFuture method here so it can be exposed in the same place.


#[cfg(target_arch = "wasm32")]
pub fn spawn<F, T>(future: F) -> JoinHandle<T>
where
@@ -50,6 +52,32 @@ where
JoinHandle { remote_handle, abort_handle }
}

pub trait BoxFutureExt<'a, T: 'a> {
fn box_future(self) -> BoxFuture<'a, T>;
}

#[cfg(not(target_arch = "wasm32"))]
impl<'a, F, T> BoxFutureExt<'a, T> for F
where
F: Future<Output = T> + 'a + Send,
T: 'a,
{
fn box_future(self) -> BoxFuture<'a, T> {
self.boxed()
}
}

#[cfg(target_arch = "wasm32")]
impl<'a, F, T> BoxFutureExt<'a, T> for F
where
F: Future<Output = T> + 'a,
T: 'a,
{
fn box_future(self) -> BoxFuture<'a, T> {
self.boxed_local()
}
}
Comment on lines +59 to +79
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

impl blocks can be merged the same way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was struggling to get it to compile with the extra + Send trait needed on the not-wasm32 version.


#[cfg(target_arch = "wasm32")]
#[derive(Debug)]
pub struct JoinHandle<T> {
@@ -78,6 +106,54 @@ impl<T: 'static> Future for JoinHandle<T> {
}
}

#[derive(Debug)]
pub struct AbortOnDrop<T>(JoinHandle<T>);

impl<T> AbortOnDrop<T> {
pub fn new(join_handle: JoinHandle<T>) -> Self {
Self(join_handle)
}
}

impl<T> Drop for AbortOnDrop<T> {
fn drop(&mut self) {
self.0.abort();
}
}

#[cfg(not(target_arch = "wasm32"))]
impl<T> Future for AbortOnDrop<T> {
type Output = Result<T, JoinError>;

fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Pin::new(&mut self.0).poll(cx)
}
}

#[cfg(target_arch = "wasm32")]
impl<T: 'static> Future for AbortOnDrop<T> {
type Output = Result<T, JoinError>;

fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.0.abort_handle.is_aborted() {
// The future has been aborted. It is not possible to poll it again.
Poll::Ready(Err(JoinError))
} else {
Pin::new(&mut self.0.remote_handle).poll(cx).map(Ok)
}
}
}

/// Trait to create a `AbortOnDrop` from a `JoinHandle`.
pub trait JoinHandleExt<T> {
fn abort_on_drop(self) -> AbortOnDrop<T>;
}

impl<T> JoinHandleExt<T> for JoinHandle<T> {
fn abort_on_drop(self) -> AbortOnDrop<T> {
AbortOnDrop::new(self)
}
}
#[cfg(test)]
mod tests {
use assert_matches::assert_matches;
9 changes: 0 additions & 9 deletions crates/matrix-sdk-common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -15,9 +15,6 @@
#![doc = include_str!("../README.md")]
#![warn(missing_debug_implementations)]

use std::pin::Pin;

use futures_core::Future;
#[doc(no_inline)]
pub use ruma;

@@ -90,11 +87,5 @@ macro_rules! boxed_into_future {
};
}

/// A `Box::pin` future that is `Send` on non-wasm, and without `Send` on wasm.
#[cfg(target_arch = "wasm32")]
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
#[cfg(not(target_arch = "wasm32"))]
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;

#[cfg(feature = "uniffi")]
uniffi::setup_scaffolding!();
2 changes: 1 addition & 1 deletion crates/matrix-sdk-crypto/src/machine/mod.rs
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ use matrix_sdk_common::{
UnableToDecryptReason, UnsignedDecryptionResult, UnsignedEventLocation, VerificationLevel,
VerificationState,
},
BoxFuture,
executor::BoxFuture,
};
use ruma::{
api::client::{
3 changes: 3 additions & 0 deletions crates/matrix-sdk-ui/src/room_list_service/filters/mod.rs
Original file line number Diff line number Diff line change
@@ -102,7 +102,10 @@ pub trait Filter: Fn(&Room) -> bool {}
impl<F> Filter for F where F: Fn(&Room) -> bool {}

/// Type alias for a boxed filter function.
#[cfg(not(target_arch = "wasm32"))]
pub type BoxedFilterFn = Box<dyn Filter + Send + Sync>;
#[cfg(target_arch = "wasm32")]
pub type BoxedFilterFn = Box<dyn Filter>;

/// Normalize a string, i.e. decompose it into NFD (Normalization Form D, i.e. a
/// canonical decomposition, see http://www.unicode.org/reports/tr15/) and
10 changes: 4 additions & 6 deletions crates/matrix-sdk-ui/src/sync_service.rs
Original file line number Diff line number Diff line change
@@ -29,13 +29,11 @@ use eyeball::{SharedObservable, Subscriber};
use futures_core::Future;
use futures_util::{pin_mut, StreamExt as _};
use matrix_sdk::Client;
use matrix_sdk_base::executor::{spawn, JoinHandle};
use thiserror::Error;
use tokio::{
sync::{
mpsc::{Receiver, Sender},
Mutex as AsyncMutex, OwnedMutexGuard,
},
task::{spawn, JoinHandle},
use tokio::sync::{
mpsc::{Receiver, Sender},
Mutex as AsyncMutex, OwnedMutexGuard,
};
use tracing::{error, info, instrument, trace, warn, Instrument, Level};

4 changes: 3 additions & 1 deletion crates/matrix-sdk-ui/src/timeline/futures.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::{fs, future::IntoFuture, path::PathBuf};

use eyeball::{SharedObservable, Subscriber};
use eyeball::SharedObservable;
#[cfg(not(target_arch = "wasm32"))]
use eyeball::Subscriber;
use matrix_sdk::{attachment::AttachmentConfig, TransmissionProgress};
use matrix_sdk_base::boxed_into_future;
use mime::Mime;
12 changes: 7 additions & 5 deletions crates/matrix-sdk-ui/src/timeline/pinned_events_loader.rs
Original file line number Diff line number Diff line change
@@ -14,10 +14,12 @@

use std::{fmt::Formatter, sync::Arc};

use futures_util::{stream, FutureExt as _, StreamExt};
use futures_util::{stream, StreamExt};
use matrix_sdk::{
config::RequestConfig, event_cache::paginator::PaginatorError, BoxFuture, Room,
SendOutsideWasm, SyncOutsideWasm,
config::RequestConfig,
event_cache::paginator::PaginatorError,
executor::{BoxFuture, BoxFutureExt},
Room,
};
use matrix_sdk_base::deserialized_responses::SyncTimelineEvent;
use ruma::{events::relation::RelationType, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId};
@@ -120,7 +122,7 @@ impl PinnedEventsLoader {
}
}

pub trait PinnedEventsRoom: SendOutsideWasm + SyncOutsideWasm {
pub trait PinnedEventsRoom: Send + Sync {
/// Load a single room event using the cache or network and any events
/// related to it, if they are cached.
///
@@ -166,7 +168,7 @@ impl PinnedEventsRoom for Room {
.map(|e| (e.into(), Vec::new()))
.map_err(|err| PaginatorError::SdkError(Box::new(err)))
}
.boxed()
.box_future()
}

fn pinned_event_ids(&self) -> Option<Vec<OwnedEventId>> {
Loading