Skip to content

Commit 27aba4f

Browse files
committed
refactor: Use AsyncMutex to avoid most of the issues about the MutexGuard and .await
1 parent 48740d1 commit 27aba4f

3 files changed

Lines changed: 56 additions & 70 deletions

File tree

bindings/matrix-sdk-ffi/src/spaces.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -252,16 +252,16 @@ impl SpaceRoomList {
252252
}
253253

254254
/// Return the current list of rooms.
255-
pub fn rooms(&self) -> Vec<SpaceRoom> {
256-
self.inner.rooms().into_iter().map(Into::into).collect()
255+
pub async fn rooms(&self) -> Vec<SpaceRoom> {
256+
self.inner.rooms().await.into_iter().map(Into::into).collect()
257257
}
258258

259259
/// Subscribes to room list updates.
260-
pub fn subscribe_to_room_update(
260+
pub async fn subscribe_to_room_update(
261261
&self,
262262
listener: Box<dyn SpaceRoomListEntriesListener>,
263263
) -> Arc<TaskHandle> {
264-
let (initial_values, mut stream) = self.inner.subscribe_to_room_updates();
264+
let (initial_values, mut stream) = self.inner.subscribe_to_room_updates().await;
265265

266266
listener.on_update(vec![SpaceListUpdate::Reset {
267267
values: initial_values.into_iter().map(Into::into).collect(),

crates/matrix-sdk-ui/src/spaces/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ struct SpaceState {
134134
/// .await;
135135
///
136136
/// // Which can be used to retrieve information about the children rooms
137-
/// let children = room_list.rooms();
137+
/// let children = room_list.rooms().await;
138138
/// # anyhow::Ok(()) };
139139
/// ```
140140
pub struct SpaceService {

crates/matrix-sdk-ui/src/spaces/room_list.rs

Lines changed: 51 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ pub enum SpaceRoomListPaginationState {
7070
/// .await;
7171
///
7272
/// // Start off with an empty and idle list
73-
/// room_list.rooms().is_empty();
73+
/// room_list.rooms().await.is_empty();
7474
///
7575
/// assert_eq!(
7676
/// room_list.pagination_state(),
@@ -82,7 +82,7 @@ pub enum SpaceRoomListPaginationState {
8282
/// room_list.subscribe_to_pagination_state_updates();
8383
///
8484
/// // And to room list updates
85-
/// let (_, room_stream) = room_list.subscribe_to_room_updates();
85+
/// let (_, room_stream) = room_list.subscribe_to_room_updates().await;
8686
///
8787
/// // Run this in a background task so it doesn't block
8888
/// while let Some(pagination_state) = pagination_state_stream.next().await {
@@ -98,7 +98,7 @@ pub enum SpaceRoomListPaginationState {
9898
/// room_list.paginate().await.unwrap();
9999
///
100100
/// // And, if successful, rooms are available
101-
/// let rooms = room_list.rooms();
101+
/// let rooms = room_list.await.rooms();
102102
/// # anyhow::Ok(()) };
103103
/// ```
104104
pub struct SpaceRoomList {
@@ -114,7 +114,7 @@ pub struct SpaceRoomList {
114114

115115
pagination_state: SharedObservable<SpaceRoomListPaginationState>,
116116

117-
rooms: Arc<Mutex<ObservableVector<SpaceRoom>>>,
117+
rooms: Arc<AsyncMutex<ObservableVector<SpaceRoom>>>,
118118

119119
_space_update_handle: Option<BackgroundTaskHandle>,
120120

@@ -124,7 +124,7 @@ pub struct SpaceRoomList {
124124
impl SpaceRoomList {
125125
/// Creates a new `SpaceRoomList` for the given space identifier.
126126
pub async fn new(client: Client, space_id: OwnedRoomId) -> Self {
127-
let rooms = Arc::new(Mutex::new(ObservableVector::<SpaceRoom>::new()));
127+
let rooms = Arc::new(AsyncMutex::new(ObservableVector::<SpaceRoom>::new()));
128128

129129
let all_room_updates_receiver = client.subscribe_to_all_room_updates();
130130

@@ -144,35 +144,25 @@ impl SpaceRoomList {
144144
continue;
145145
}
146146

147-
// Given the MutexGuard used by `rooms`, we need to drop any
148-
// possible guard before calling `.await`, otherwise the compiler
149-
// will complain.
150-
let mut rooms_to_update_with_index = Vec::new();
151-
{
152-
let mutable_rooms = rooms.lock();
153-
for updated_room_id in updates.iter_all_room_ids() {
154-
if let Some((position, room)) = mutable_rooms
155-
.iter()
156-
.find_position(|room| &room.room_id == updated_room_id)
157-
{
158-
rooms_to_update_with_index
159-
.push((position, room.clone()));
160-
}
147+
let mut mutable_rooms = rooms.lock().await;
148+
149+
for updated_room_id in updates.iter_all_room_ids() {
150+
if let Some((position, room)) = mutable_rooms
151+
.clone()
152+
.iter()
153+
.find_position(|room| &room.room_id == updated_room_id)
154+
&& let Some(updated_room) = client.get_room(updated_room_id)
155+
{
156+
mutable_rooms.set(
157+
position,
158+
SpaceRoom::new_from_known(
159+
&updated_room,
160+
room.children_count,
161+
)
162+
.await,
163+
);
161164
}
162165
}
163-
164-
for (idx, room) in rooms_to_update_with_index {
165-
let Some(updated_room) = client.get_room(&room.room_id) else {
166-
continue;
167-
};
168-
let space_room = SpaceRoom::new_from_known(
169-
&updated_room,
170-
room.children_count,
171-
)
172-
.await;
173-
let mut mutable_rooms = rooms.lock();
174-
mutable_rooms.set(idx, space_room);
175-
}
176166
}
177167
Err(err) => {
178168
error!("error when listening to room updates: {err}");
@@ -258,15 +248,15 @@ impl SpaceRoomList {
258248
}
259249

260250
/// Return the current list of rooms.
261-
pub fn rooms(&self) -> Vec<SpaceRoom> {
262-
self.rooms.lock().iter().cloned().collect_vec()
251+
pub async fn rooms(&self) -> Vec<SpaceRoom> {
252+
self.rooms.lock().await.iter().cloned().collect_vec()
263253
}
264254

265255
/// Subscribes to room list updates.
266-
pub fn subscribe_to_room_updates(
256+
pub async fn subscribe_to_room_updates(
267257
&self,
268258
) -> (Vector<SpaceRoom>, VectorSubscriberBatchedStream<SpaceRoom>) {
269-
self.rooms.lock().subscribe().into_values_and_batched_stream()
259+
self.rooms.lock().await.subscribe().into_values_and_batched_stream()
270260
}
271261

272262
/// Ask the list to retrieve the next page if the end hasn't been reached
@@ -340,10 +330,9 @@ impl SpaceRoomList {
340330
}
341331

342332
let children_state = (*self.children_state.lock()).clone().unwrap_or_default();
333+
let mut rooms = self.rooms.lock().await;
343334

344-
// Because of the `MutexGuard` used by `SpaceRoomList::rooms`, we need to
345-
// perform all calls that involve `.await` before acquiring the lock.
346-
let children_space_rooms = join_all(children.into_iter().map(|room| {
335+
join_all(children.into_iter().map(|room| {
347336
let children_state = children_state.clone();
348337
async move {
349338
let child_state = children_state.get(&room.summary.room_id);
@@ -361,13 +350,10 @@ impl SpaceRoomList {
361350
.await
362351
}
363352
}))
364-
.await;
365-
366-
let mut rooms = self.rooms.lock();
367-
children_space_rooms
368-
.into_iter()
369-
.sorted_by(|a, b| Self::compare_rooms(a, b, &children_state))
370-
.for_each(|room| rooms.push_back(room));
353+
.await
354+
.into_iter()
355+
.sorted_by(|a, b| Self::compare_rooms(a, b, &children_state))
356+
.for_each(|room| rooms.push_back(room));
371357

372358
self.pagination_state.set(SpaceRoomListPaginationState::Idle {
373359
end_reached: result.next_batch.is_none(),
@@ -395,7 +381,7 @@ impl SpaceRoomList {
395381
let mut pagination_token = self.token.lock().await;
396382
*pagination_token = None.into();
397383

398-
self.rooms.lock().clear();
384+
self.rooms.lock().await.clear();
399385
self.children_state.lock().take();
400386

401387
self.pagination_state.set(SpaceRoomListPaginationState::Idle { end_reached: false });
@@ -488,15 +474,15 @@ mod tests {
488474
);
489475

490476
// without any rooms
491-
assert_eq!(room_list.rooms(), vec![]);
477+
assert_eq!(room_list.rooms().await, vec![]);
492478

493479
// and with pending subscribers
494480

495481
let pagination_state_subscriber = room_list.subscribe_to_pagination_state_updates();
496482
pin_mut!(pagination_state_subscriber);
497483
assert_pending!(pagination_state_subscriber);
498484

499-
let (_, rooms_subscriber) = room_list.subscribe_to_room_updates();
485+
let (_, rooms_subscriber) = room_list.subscribe_to_room_updates().await;
500486
pin_mut!(rooms_subscriber);
501487
assert_pending!(rooms_subscriber);
502488

@@ -579,14 +565,14 @@ mod tests {
579565
room_list.paginate().await.unwrap();
580566

581567
// This space contains 2 rooms
582-
assert_eq!(room_list.rooms().first().unwrap().room_id, child_room_id_1);
583-
assert_eq!(room_list.rooms().last().unwrap().room_id, child_room_id_2);
568+
assert_eq!(room_list.rooms().await.first().unwrap().room_id, child_room_id_1);
569+
assert_eq!(room_list.rooms().await.last().unwrap().room_id, child_room_id_2);
584570

585571
// and we don't know about either of them
586-
assert_eq!(room_list.rooms().first().unwrap().state, None);
587-
assert_eq!(room_list.rooms().last().unwrap().state, None);
572+
assert_eq!(room_list.rooms().await.first().unwrap().state, None);
573+
assert_eq!(room_list.rooms().await.last().unwrap().state, None);
588574

589-
let (_, rooms_subscriber) = room_list.subscribe_to_room_updates();
575+
let (_, rooms_subscriber) = room_list.subscribe_to_room_updates().await;
590576
pin_mut!(rooms_subscriber);
591577
assert_pending!(rooms_subscriber);
592578

@@ -595,21 +581,21 @@ mod tests {
595581

596582
// Results in an update being pushed through
597583
assert_ready!(rooms_subscriber);
598-
assert_eq!(room_list.rooms().first().unwrap().state, Some(RoomState::Joined));
599-
assert_eq!(room_list.rooms().last().unwrap().state, None);
584+
assert_eq!(room_list.rooms().await.first().unwrap().state, Some(RoomState::Joined));
585+
assert_eq!(room_list.rooms().await.last().unwrap().state, None);
600586

601587
// Same for the second one
602588
server.sync_room(&client, JoinedRoomBuilder::new(child_room_id_2)).await;
603589
assert_ready!(rooms_subscriber);
604-
assert_eq!(room_list.rooms().first().unwrap().state, Some(RoomState::Joined));
605-
assert_eq!(room_list.rooms().last().unwrap().state, Some(RoomState::Joined));
590+
assert_eq!(room_list.rooms().await.first().unwrap().state, Some(RoomState::Joined));
591+
assert_eq!(room_list.rooms().await.last().unwrap().state, Some(RoomState::Joined));
606592

607593
// And when leaving them
608594
server.sync_room(&client, LeftRoomBuilder::new(child_room_id_1)).await;
609595
server.sync_room(&client, LeftRoomBuilder::new(child_room_id_2)).await;
610596
assert_ready!(rooms_subscriber);
611-
assert_eq!(room_list.rooms().first().unwrap().state, Some(RoomState::Left));
612-
assert_eq!(room_list.rooms().last().unwrap().state, Some(RoomState::Left));
597+
assert_eq!(room_list.rooms().await.first().unwrap().state, Some(RoomState::Left));
598+
assert_eq!(room_list.rooms().await.last().unwrap().state, Some(RoomState::Left));
613599
}
614600

615601
#[async_test]
@@ -735,7 +721,7 @@ mod tests {
735721

736722
let room_list = space_service.space_room_list(parent_space_id.to_owned()).await;
737723

738-
let (_, rooms_subscriber) = room_list.subscribe_to_room_updates();
724+
let (_, rooms_subscriber) = room_list.subscribe_to_room_updates().await;
739725
pin_mut!(rooms_subscriber);
740726

741727
// When retrieving the parent and children via /hierarchy
@@ -807,7 +793,7 @@ mod tests {
807793

808794
let room_list = space_service.space_room_list(parent_space_id.to_owned()).await;
809795

810-
let (_, rooms_subscriber) = room_list.subscribe_to_room_updates();
796+
let (_, rooms_subscriber) = room_list.subscribe_to_room_updates().await;
811797
pin_mut!(rooms_subscriber);
812798

813799
// Mock a /hierarchy response where one child is suggested and the other is not.
@@ -1048,21 +1034,21 @@ mod tests {
10481034
room_list.paginate().await.unwrap();
10491035

10501036
// This space contains 1 room
1051-
assert_eq!(room_list.rooms().len(), 1);
1037+
assert_eq!(room_list.rooms().await.len(), 1);
10521038

10531039
// Resetting the room list
10541040
room_list.reset().await;
10551041

10561042
// Clears the rooms and pagination token
1057-
assert_eq!(room_list.rooms().len(), 0);
1043+
assert_eq!(room_list.rooms().await.len(), 0);
10581044
assert_matches!(
10591045
room_list.pagination_state(),
10601046
SpaceRoomListPaginationState::Idle { end_reached: false }
10611047
);
10621048

10631049
// Allows paginating again
10641050
room_list.paginate().await.unwrap();
1065-
assert_eq!(room_list.rooms().len(), 1);
1051+
assert_eq!(room_list.rooms().await.len(), 1);
10661052
}
10671053

10681054
fn make_space_room(

0 commit comments

Comments
 (0)