Skip to content

Commit 8d043d5

Browse files
committed
feat(base): Make ObservableMap::stream works on wasm32-unknown-unknown.
This patch updates `eyeball-im` and `eyeball-im-util` to integrate jplatte/eyeball#63. With this new feature, we can have a single implementation of `ObservableMap` (instead of 2: one for all targets, one for `wasm32-u-u`). It makes it possible to get `Client::rooms_stream` available on all targets now.
1 parent b2ad704 commit 8d043d5

File tree

4 files changed

+108
-191
lines changed

4 files changed

+108
-191
lines changed

Cargo.lock

Lines changed: 2 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/matrix-sdk-base/src/client.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ use std::{
2222
};
2323

2424
use eyeball::{SharedObservable, Subscriber};
25-
#[cfg(not(target_arch = "wasm32"))]
2625
use eyeball_im::{Vector, VectorDiff};
27-
#[cfg(not(target_arch = "wasm32"))]
2826
use futures_util::Stream;
2927
#[cfg(feature = "e2e-encryption")]
3028
use matrix_sdk_crypto::{
@@ -236,7 +234,6 @@ impl BaseClient {
236234

237235
/// Get a stream of all the rooms changes, in addition to the existing
238236
/// rooms.
239-
#[cfg(not(target_arch = "wasm32"))]
240237
pub fn rooms_stream(&self) -> (Vector<Room>, impl Stream<Item = Vec<VectorDiff<Room>>>) {
241238
self.store.rooms_stream()
242239
}

crates/matrix-sdk-base/src/store/mod.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ use std::{
2929
sync::{Arc, RwLock as StdRwLock},
3030
};
3131

32-
#[cfg(not(target_arch = "wasm32"))]
3332
use eyeball_im::{Vector, VectorDiff};
34-
#[cfg(not(target_arch = "wasm32"))]
3533
use futures_util::Stream;
3634
use once_cell::sync::OnceCell;
3735

@@ -267,7 +265,6 @@ impl Store {
267265

268266
/// Get a stream of all the rooms changes, in addition to the existing
269267
/// rooms.
270-
#[cfg(not(target_arch = "wasm32"))]
271268
pub fn rooms_stream(&self) -> (Vector<Room>, impl Stream<Item = Vec<VectorDiff<Room>>>) {
272269
self.rooms.read().unwrap().stream()
273270
}

crates/matrix-sdk-base/src/store/observable_map.rs

Lines changed: 106 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -14,212 +14,137 @@
1414

1515
//! An [`ObservableMap`] implementation.
1616
17-
#[cfg(not(target_arch = "wasm32"))]
18-
mod impl_non_wasm32 {
19-
use std::{borrow::Borrow, collections::HashMap, hash::Hash};
20-
21-
use eyeball_im::{ObservableVector, Vector, VectorDiff};
22-
use futures_util::Stream;
23-
24-
/// An observable map.
25-
///
26-
/// This is an “observable map” naive implementation. Just like regular
27-
/// hashmap, we have a redirection from a key to a position, and from a
28-
/// position to a value. The (key, position) tuples are stored in an
29-
/// [`HashMap`]. The (position, value) tuples are stored in an
30-
/// [`ObservableVector`]. The (key, position) tuple is only provided for
31-
/// fast _reading_ implementations, like `Self::get` and
32-
/// `Self::get_or_create`. The (position, value) tuples are observable,
33-
/// this is what interests us the most here.
34-
///
35-
/// Why not implementing a new `ObservableMap` type in `eyeball-im` instead
36-
/// of this custom implementation? Because we want to continue providing
37-
/// `VectorDiff` when observing the changes, so that the rest of the API in
38-
/// the Matrix Rust SDK aren't broken. Indeed, an `ObservableMap` must
39-
/// produce `MapDiff`, which would be quite different.
40-
/// Plus, we would like to re-use all our existing code, test, stream
41-
/// adapters and so on.
42-
///
43-
/// This is a trade-off. This implementation is simple enough for the
44-
/// moment, and basically does the job.
45-
#[derive(Debug)]
46-
pub(crate) struct ObservableMap<K, V>
47-
where
48-
V: Clone + Send + Sync + 'static,
49-
{
50-
/// The (key, position) tuples.
51-
mapping: HashMap<K, usize>,
17+
use std::{borrow::Borrow, collections::HashMap, hash::Hash};
18+
19+
use eyeball_im::{ObservableVector, Vector, VectorDiff};
20+
use futures_util::Stream;
21+
22+
/// An observable map.
23+
///
24+
/// This is an “observable map” naive implementation. Just like regular
25+
/// hashmap, we have a redirection from a key to a position, and from a
26+
/// position to a value. The (key, position) tuples are stored in an
27+
/// [`HashMap`]. The (position, value) tuples are stored in an
28+
/// [`ObservableVector`]. The (key, position) tuple is only provided for
29+
/// fast _reading_ implementations, like `Self::get` and
30+
/// `Self::get_or_create`. The (position, value) tuples are observable,
31+
/// this is what interests us the most here.
32+
///
33+
/// Why not implementing a new `ObservableMap` type in `eyeball-im` instead
34+
/// of this custom implementation? Because we want to continue providing
35+
/// `VectorDiff` when observing the changes, so that the rest of the API in
36+
/// the Matrix Rust SDK aren't broken. Indeed, an `ObservableMap` must
37+
/// produce `MapDiff`, which would be quite different.
38+
/// Plus, we would like to re-use all our existing code, test, stream
39+
/// adapters and so on.
40+
///
41+
/// This is a trade-off. This implementation is simple enough for the
42+
/// moment, and basically does the job.
43+
#[derive(Debug)]
44+
pub(crate) struct ObservableMap<K, V>
45+
where
46+
V: Clone + 'static,
47+
{
48+
/// The (key, position) tuples.
49+
mapping: HashMap<K, usize>,
50+
51+
/// The values where the indices are the `position` part of
52+
/// `Self::mapping`.
53+
values: ObservableVector<V>,
54+
}
5255

53-
/// The values where the indices are the `position` part of
54-
/// `Self::mapping`.
55-
values: ObservableVector<V>,
56+
impl<K, V> ObservableMap<K, V>
57+
where
58+
K: Hash + Eq,
59+
V: Clone + 'static,
60+
{
61+
/// Create a new `Self`.
62+
pub(crate) fn new() -> Self {
63+
Self { mapping: HashMap::new(), values: ObservableVector::new() }
5664
}
5765

58-
impl<K, V> ObservableMap<K, V>
59-
where
60-
K: Hash + Eq,
61-
V: Clone + Send + Sync + 'static,
62-
{
63-
/// Create a new `Self`.
64-
pub(crate) fn new() -> Self {
65-
Self { mapping: HashMap::new(), values: ObservableVector::new() }
66-
}
67-
68-
/// Insert a new `V` in the collection.
69-
///
70-
/// If the `V` value already exists, it will be updated to the new one.
71-
pub(crate) fn insert(&mut self, key: K, value: V) -> usize {
72-
match self.mapping.get(&key) {
73-
Some(position) => {
74-
self.values.set(*position, value);
75-
76-
*position
77-
}
78-
None => {
79-
let position = self.values.len();
80-
81-
self.values.push_back(value);
82-
self.mapping.insert(key, position);
66+
/// Insert a new `V` in the collection.
67+
///
68+
/// If the `V` value already exists, it will be updated to the new one.
69+
pub(crate) fn insert(&mut self, key: K, value: V) -> usize {
70+
match self.mapping.get(&key) {
71+
Some(position) => {
72+
self.values.set(*position, value);
8373

84-
position
85-
}
74+
*position
8675
}
87-
}
76+
None => {
77+
let position = self.values.len();
8878

89-
/// Reading one `V` value based on their ID, if it exists.
90-
pub(crate) fn get<L>(&self, key: &L) -> Option<&V>
91-
where
92-
K: Borrow<L>,
93-
L: Hash + Eq + ?Sized,
94-
{
95-
self.mapping.get(key).and_then(|position| self.values.get(*position))
96-
}
79+
self.values.push_back(value);
80+
self.mapping.insert(key, position);
9781

98-
/// Reading one `V` value based on their ID, or create a new one (by
99-
/// using `default`).
100-
pub(crate) fn get_or_create<L, F>(&mut self, key: &L, default: F) -> &V
101-
where
102-
K: Borrow<L>,
103-
L: Hash + Eq + ?Sized + ToOwned<Owned = K>,
104-
F: FnOnce() -> V,
105-
{
106-
let position = match self.mapping.get(key) {
107-
Some(position) => *position,
108-
None => {
109-
let value = default();
110-
let position = self.values.len();
111-
112-
self.values.push_back(value);
113-
self.mapping.insert(key.to_owned(), position);
114-
115-
position
116-
}
117-
};
118-
119-
self.values
120-
.get(position)
121-
.expect("Value should be present or has just been inserted, but it's missing")
122-
}
123-
124-
/// Return an iterator over the existing values.
125-
pub(crate) fn iter(&self) -> impl Iterator<Item = &V> {
126-
self.values.iter()
127-
}
128-
129-
/// Get a [`Stream`] of the values.
130-
pub(crate) fn stream(&self) -> (Vector<V>, impl Stream<Item = Vec<VectorDiff<V>>>) {
131-
self.values.subscribe().into_values_and_batched_stream()
132-
}
133-
134-
/// Remove a `V` value based on their ID, if it exists.
135-
///
136-
/// Returns the removed value.
137-
pub(crate) fn remove<L>(&mut self, key: &L) -> Option<V>
138-
where
139-
K: Borrow<L>,
140-
L: Hash + Eq + ?Sized,
141-
{
142-
let position = self.mapping.remove(key)?;
143-
Some(self.values.remove(position))
82+
position
83+
}
14484
}
14585
}
146-
}
14786

148-
#[cfg(target_arch = "wasm32")]
149-
mod impl_wasm32 {
150-
use std::{borrow::Borrow, collections::BTreeMap, hash::Hash};
151-
152-
/// An observable map for Wasm. It's a simple wrapper around `BTreeMap`.
153-
#[derive(Debug)]
154-
pub(crate) struct ObservableMap<K, V>(BTreeMap<K, V>)
87+
/// Reading one `V` value based on their ID, if it exists.
88+
pub(crate) fn get<L>(&self, key: &L) -> Option<&V>
15589
where
156-
V: Clone + 'static;
90+
K: Borrow<L>,
91+
L: Hash + Eq + ?Sized,
92+
{
93+
self.mapping.get(key).and_then(|position| self.values.get(*position))
94+
}
15795

158-
impl<K, V> ObservableMap<K, V>
96+
/// Reading one `V` value based on their ID, or create a new one (by
97+
/// using `default`).
98+
pub(crate) fn get_or_create<L, F>(&mut self, key: &L, default: F) -> &V
15999
where
160-
K: Hash + Eq + Ord,
161-
V: Clone + 'static,
100+
K: Borrow<L>,
101+
L: Hash + Eq + ?Sized + ToOwned<Owned = K>,
102+
F: FnOnce() -> V,
162103
{
163-
/// Create a new `Self`.
164-
pub(crate) fn new() -> Self {
165-
Self(BTreeMap::new())
166-
}
104+
let position = match self.mapping.get(key) {
105+
Some(position) => *position,
106+
None => {
107+
let value = default();
108+
let position = self.values.len();
167109

168-
/// Insert a new `V` in the collection.
169-
///
170-
/// If the `V` value already exists, it will be updated to the new one.
171-
pub(crate) fn insert(&mut self, key: K, value: V) {
172-
self.0.insert(key, value);
173-
}
110+
self.values.push_back(value);
111+
self.mapping.insert(key.to_owned(), position);
174112

175-
/// Reading one `V` value based on their ID, if it exists.
176-
pub(crate) fn get<L>(&self, key: &L) -> Option<&V>
177-
where
178-
K: Borrow<L>,
179-
L: Hash + Eq + Ord + ?Sized,
180-
{
181-
self.0.get(key)
182-
}
113+
position
114+
}
115+
};
183116

184-
/// Reading one `V` value based on their ID, or create a new one (by
185-
/// using `default`).
186-
pub(crate) fn get_or_create<L, F>(&mut self, key: &L, default: F) -> &V
187-
where
188-
K: Borrow<L>,
189-
L: Hash + Eq + ?Sized + ToOwned<Owned = K>,
190-
F: FnOnce() -> V,
191-
{
192-
self.0.entry(key.to_owned()).or_insert_with(default)
193-
}
117+
self.values
118+
.get(position)
119+
.expect("Value should be present or has just been inserted, but it's missing")
120+
}
194121

195-
/// Return an iterator over the existing values.
196-
pub(crate) fn iter(&self) -> impl Iterator<Item = &V> {
197-
self.0.values()
198-
}
122+
/// Return an iterator over the existing values.
123+
pub(crate) fn iter(&self) -> impl Iterator<Item = &V> {
124+
self.values.iter()
125+
}
199126

200-
/// Remove a `V` value based on their ID, if it exists.
201-
///
202-
/// Returns the removed value.
203-
pub(crate) fn remove<L>(&mut self, key: &L) -> Option<V>
204-
where
205-
K: Borrow<L>,
206-
L: Hash + Eq + Ord + ?Sized,
207-
{
208-
self.0.remove(key)
209-
}
127+
/// Get a [`Stream`] of the values.
128+
pub(crate) fn stream(&self) -> (Vector<V>, impl Stream<Item = Vec<VectorDiff<V>>>) {
129+
self.values.subscribe().into_values_and_batched_stream()
210130
}
211-
}
212131

213-
#[cfg(not(target_arch = "wasm32"))]
214-
pub(crate) use impl_non_wasm32::ObservableMap;
215-
#[cfg(target_arch = "wasm32")]
216-
pub(crate) use impl_wasm32::ObservableMap;
132+
/// Remove a `V` value based on their ID, if it exists.
133+
///
134+
/// Returns the removed value.
135+
pub(crate) fn remove<L>(&mut self, key: &L) -> Option<V>
136+
where
137+
K: Borrow<L>,
138+
L: Hash + Eq + ?Sized,
139+
{
140+
let position = self.mapping.remove(key)?;
141+
Some(self.values.remove(position))
142+
}
143+
}
217144

218145
#[cfg(test)]
219146
mod tests {
220-
#[cfg(not(target_arch = "wasm32"))]
221147
use eyeball_im::VectorDiff;
222-
#[cfg(not(target_arch = "wasm32"))]
223148
use stream_assert::{assert_closed, assert_next_eq, assert_pending};
224149

225150
use super::ObservableMap;
@@ -314,7 +239,6 @@ mod tests {
314239
);
315240
}
316241

317-
#[cfg(not(target_arch = "wasm32"))]
318242
#[test]
319243
fn test_stream() {
320244
let mut map = ObservableMap::<char, char>::new();

0 commit comments

Comments
 (0)