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.
This commit is contained in:
Ivan Enderlin
2025-04-07 17:30:37 +02:00
parent 5c011a8400
commit 2ee0e175fa
4 changed files with 88 additions and 66 deletions

View File

@@ -636,19 +636,19 @@ impl BaseClient {
&self,
context: &mut Context,
room: &Room,
events: &[(Raw<AnyStrippedStateEvent>, AnyStrippedStateEvent)],
events: (Vec<Raw<AnyStrippedStateEvent>>, Vec<AnyStrippedStateEvent>),
push_rules: &Ruleset,
room_info: &mut RoomInfo,
notifications: &mut BTreeMap<OwnedRoomId, Vec<Notification>>,
) -> 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<AnySyncStateEvent>],
) -> Vec<(Raw<AnySyncStateEvent>, 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<AnyStrippedStateEvent>],
) -> Vec<(Raw<AnyStrippedStateEvent>, 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.

View File

@@ -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;

View File

@@ -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<AnySyncStateEvent>],
) -> (Vec<Raw<AnySyncStateEvent>>, Vec<AnySyncStateEvent>) {
collect(raw_events)
}
pub fn collect_stripped(
_context: &mut Context,
raw_events: &[Raw<AnyStrippedStateEvent>],
) -> (Vec<Raw<AnyStrippedStateEvent>>, Vec<AnyStrippedStateEvent>) {
collect(raw_events)
}
fn collect<'a, T>(raw_events: &'a [Raw<T>]) -> (Vec<Raw<T>>, Vec<T>)
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()
}

View File

@@ -363,32 +363,28 @@ impl BaseClient {
Option<InvitedRoom>,
Option<KnockedRoom>,
)> {
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<Vec<(Raw<AnyStrippedStateEvent>, 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>, AnyStrippedStateEvent)>>,
stripped_state: &Option<(Vec<Raw<AnyStrippedStateEvent>>, Vec<AnyStrippedStateEvent>)>,
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::<Vec<_>>();
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 {