77a67de7df
This patch improves the performance of `ReadReceiptTimelineUpdate::apply`, which does 2 things: it calls `remove_old_receipt` and `add_new_receipt`. Both of them need an timeline item position. Until this patch, `rfind_event_by_id` was used and was the bottleneck. The improvement is twofold as is as follows. First off, when collecting data to create `ReadReceiptTimelineUpdate`, the timeline item position can be known ahead of time by using `EventMeta::timeline_item_index`. This data is not always available, for example if the timeline item isn't created yet. But let's try to collect these data if there are some. Second, inside `ReadReceiptTimelineUpdate::remove_old_receipt`, we use the timeline item position collected from `EventMeta` if it exists. Otherwise, let's fallback to a similar `rfind_event_by_id` pattern, without using intermediate types. It's more straightforward here: we don't need an `EventTimelineItemWithId`, we only need the position. Once the position is known, it is stored in `Self` (!), this is the biggest improvement here. Le't see why. Finally, inside `ReadReceiptTimelineUpdate::add_new_receipt`, we use the timeline item position collected from `EventMeta` if it exists, similarly to what `remove_old_receipt` does. Otherwise, let's fallback to an iterator to find the position. However, instead of iterating over **all** items, we can skip the first ones, up to the position of the timeline item holding the old receipt, so up to the position found by `remove_old_receipt`. I'm testing this patch with the `test_lazy_back_pagination` test in https://github.com/matrix-org/matrix-rust-sdk/pull/4594. With 10_000 events in the sync, the `ReadReceipts::maybe_update_read_receipt` method was taking 52% of the whole execution time. With this patch, it takes 8.1%.