From 2ee0e175face366df912efa13388e8fec85be499 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 7 Apr 2025 17:30:37 +0200 Subject: [PATCH] refactor(base): Create the `state_events::collect_*` response processors. This patch creates the `state_events::collect_sync` and `collect_stripped` response processors. It removes the `BaseClient::deserialize_state_events` and `deserialize_stripped_state_events` methods. It also removes a couple of `Vec` allocations and a couple of clones. --- crates/matrix-sdk-base/src/client.rs | 63 ++++++------------- .../src/response_processors/mod.rs | 1 + .../src/response_processors/state_events.rs | 52 +++++++++++++++ crates/matrix-sdk-base/src/sliding_sync.rs | 38 +++++------ 4 files changed, 88 insertions(+), 66 deletions(-) create mode 100644 crates/matrix-sdk-base/src/response_processors/state_events.rs diff --git a/crates/matrix-sdk-base/src/client.rs b/crates/matrix-sdk-base/src/client.rs index 5ea8e6f5b..19d7dda96 100644 --- a/crates/matrix-sdk-base/src/client.rs +++ b/crates/matrix-sdk-base/src/client.rs @@ -636,19 +636,19 @@ impl BaseClient { &self, context: &mut Context, room: &Room, - events: &[(Raw, AnyStrippedStateEvent)], + events: (Vec>, Vec), push_rules: &Ruleset, room_info: &mut RoomInfo, notifications: &mut BTreeMap>, ) -> Result<()> { let mut state_events = BTreeMap::new(); - for (raw_event, event) in events { - room_info.handle_stripped_state_event(event); + for (raw_event, event) in events.0.into_iter().zip(events.1.into_iter()) { + room_info.handle_stripped_state_event(&event); state_events .entry(event.event_type()) .or_insert_with(BTreeMap::new) - .insert(event.state_key().to_owned(), raw_event.clone()); + .insert(event.state_key().to_owned(), raw_event); } context @@ -1018,9 +1018,8 @@ impl BaseClient { room_info.mark_state_fully_synced(); room_info.handle_encryption_state(requested_required_states.for_room(&room_id)); - let state_events = Self::deserialize_state_events(&new_info.state.events); - let (raw_state_events, state_events): (Vec<_>, Vec<_>) = - state_events.into_iter().unzip(); + let (raw_state_events, state_events) = + processors::state_events::collect_sync(&mut context, &new_info.state.events); let mut new_user_ids = self .handle_state( @@ -1128,9 +1127,8 @@ impl BaseClient { room_info.mark_state_partially_synced(); room_info.handle_encryption_state(requested_required_states.for_room(&room_id)); - let state_events = Self::deserialize_state_events(&new_info.state.events); - let (raw_state_events, state_events): (Vec<_>, Vec<_>) = - state_events.into_iter().unzip(); + let (raw_state_events, state_events) = + processors::state_events::collect_sync(&mut context, &new_info.state.events); let mut user_ids = self .handle_state( @@ -1184,8 +1182,10 @@ impl BaseClient { self.room_info_notable_update_sender.clone(), ); - let invite_state = - Self::deserialize_stripped_state_events(&new_info.invite_state.events); + let invite_state = processors::state_events::collect_stripped( + &mut context, + &new_info.invite_state.events, + ); let mut room_info = room.clone_info(); room_info.mark_as_invited(); @@ -1194,7 +1194,7 @@ impl BaseClient { self.handle_invited_state( &mut context, &room, - &invite_state, + invite_state, &push_rules, &mut room_info, &mut notifications, @@ -1213,7 +1213,10 @@ impl BaseClient { self.room_info_notable_update_sender.clone(), ); - let knock_state = Self::deserialize_stripped_state_events(&new_info.knock_state.events); + let knock_state = processors::state_events::collect_stripped( + &mut context, + &new_info.knock_state.events, + ); let mut room_info = room.clone_info(); room_info.mark_as_knocked(); @@ -1222,7 +1225,7 @@ impl BaseClient { self.handle_invited_state( &mut context, &room, - &knock_state, + knock_state, &push_rules, &mut room_info, &mut notifications, @@ -1666,36 +1669,6 @@ impl BaseClient { self.ignore_user_list_changes.subscribe() } - pub(crate) fn deserialize_state_events( - raw_events: &[Raw], - ) -> Vec<(Raw, AnySyncStateEvent)> { - raw_events - .iter() - .filter_map(|raw_event| match raw_event.deserialize() { - Ok(event) => Some((raw_event.clone(), event)), - Err(e) => { - warn!("Couldn't deserialize state event: {e}"); - None - } - }) - .collect() - } - - pub(crate) fn deserialize_stripped_state_events( - raw_events: &[Raw], - ) -> Vec<(Raw, AnyStrippedStateEvent)> { - raw_events - .iter() - .filter_map(|raw_event| match raw_event.deserialize() { - Ok(event) => Some((raw_event.clone(), event)), - Err(e) => { - warn!("Couldn't deserialize stripped state event: {e}"); - None - } - }) - .collect() - } - /// Returns a new receiver that gets future room info notable updates. /// /// Learn more by reading the [`RoomInfoNotableUpdate`] type. diff --git a/crates/matrix-sdk-base/src/response_processors/mod.rs b/crates/matrix-sdk-base/src/response_processors/mod.rs index afdffe38b..e88c29911 100644 --- a/crates/matrix-sdk-base/src/response_processors/mod.rs +++ b/crates/matrix-sdk-base/src/response_processors/mod.rs @@ -19,6 +19,7 @@ pub mod e2ee; #[cfg(feature = "e2e-encryption")] pub mod latest_event; pub mod profiles; +pub mod state_events; #[cfg(feature = "e2e-encryption")] pub mod verification; diff --git a/crates/matrix-sdk-base/src/response_processors/state_events.rs b/crates/matrix-sdk-base/src/response_processors/state_events.rs new file mode 100644 index 000000000..848f10fcc --- /dev/null +++ b/crates/matrix-sdk-base/src/response_processors/state_events.rs @@ -0,0 +1,52 @@ +// Copyright 2025 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use ruma::{ + events::{AnyStrippedStateEvent, AnySyncStateEvent}, + serde::Raw, +}; +use serde::Deserialize; +use tracing::warn; + +use super::Context; + +pub fn collect_sync( + _context: &mut Context, + raw_events: &[Raw], +) -> (Vec>, Vec) { + collect(raw_events) +} + +pub fn collect_stripped( + _context: &mut Context, + raw_events: &[Raw], +) -> (Vec>, Vec) { + collect(raw_events) +} + +fn collect<'a, T>(raw_events: &'a [Raw]) -> (Vec>, Vec) +where + T: Deserialize<'a>, +{ + raw_events + .iter() + .filter_map(|raw_event| match raw_event.deserialize() { + Ok(event) => Some((raw_event.clone(), event)), + Err(e) => { + warn!("Couldn't deserialize stripped state event: {e}"); + None + } + }) + .unzip() +} diff --git a/crates/matrix-sdk-base/src/sliding_sync.rs b/crates/matrix-sdk-base/src/sliding_sync.rs index c0ae3e2b4..e6416a215 100644 --- a/crates/matrix-sdk-base/src/sliding_sync.rs +++ b/crates/matrix-sdk-base/src/sliding_sync.rs @@ -363,32 +363,28 @@ impl BaseClient { Option, Option, )> { - let (raw_state_events, state_events): (Vec<_>, Vec<_>) = { - // Read state events from the `required_state` field. - let state_events = Self::deserialize_state_events(&room_data.required_state); - - // Don't read state events from the `timeline` field, because they might be - // incomplete or staled already. We must only read state events from - // `required_state`. - - state_events.into_iter().unzip() - }; + // Read state events from the `required_state` field. + // + // Don't read state events from the `timeline` field, because they might be + // incomplete or staled already. We must only read state events from + // `required_state`. + let (raw_state_events, state_events) = + processors::state_events::collect_sync(context, &room_data.required_state); // Find or create the room in the store let is_new_room = !state_store.room_exists(room_id); - let stripped_state: Option, AnyStrippedStateEvent)>> = - room_data - .invite_state - .as_ref() - .map(|invite_state| Self::deserialize_stripped_state_events(invite_state)); + let stripped_state = room_data + .invite_state + .as_ref() + .map(|invite_state| processors::state_events::collect_stripped(context, invite_state)); #[allow(unused_mut)] // Required for some feature flag combinations let (mut room, mut room_info, invited_room, knocked_room) = self .process_sliding_sync_room_membership( context, &state_events, - stripped_state.as_ref(), + &stripped_state, state_store, user_id, room_id, @@ -413,7 +409,7 @@ impl BaseClient { let push_rules = self.get_push_rules(account_data_processor).await?; // This will be used for both invited and knocked rooms. - if let Some(invite_state) = &stripped_state { + if let Some(invite_state) = stripped_state { self.handle_invited_state( context, &room, @@ -524,7 +520,7 @@ impl BaseClient { &self, context: &mut processors::Context, state_events: &[AnySyncStateEvent], - stripped_state: Option<&Vec<(Raw, AnyStrippedStateEvent)>>, + stripped_state: &Option<(Vec>, Vec)>, store: &BaseStateStore, user_id: &UserId, room_id: &RoomId, @@ -539,7 +535,7 @@ impl BaseClient { // We need to find the membership event since it could be for either an invited // or knocked room - let membership_event_content = stripped_state.iter().find_map(|(_, event)| { + let membership_event_content = stripped_state.1.iter().find_map(|event| { if let AnyStrippedStateEvent::RoomMember(membership_event) = event { if membership_event.state_key == user_id { return Some(membership_event.content.clone()); @@ -552,7 +548,7 @@ impl BaseClient { if membership_event_content.membership == MembershipState::Knock { // If we have a `Knock` membership state, set the room as such room_info.mark_as_knocked(); - let raw_events = stripped_state.iter().map(|(raw, _)| raw.clone()).collect(); + let raw_events = stripped_state.0.clone(); let knock_state = assign!(v3::KnockState::default(), { events: raw_events }); let knocked_room = assign!(KnockedRoom::default(), { knock_state: knock_state }); @@ -562,7 +558,7 @@ impl BaseClient { // Otherwise assume it's an invited room room_info.mark_as_invited(); - let raw_events = stripped_state.iter().map(|(raw, _)| raw.clone()).collect::>(); + let raw_events = stripped_state.0.clone(); let invited_room = InvitedRoom::from(v3::InviteState::from(raw_events)); (room, room_info, Some(invited_room), None) } else {