matrix_sdk_ui/timeline/controller/
observable_items.rs

1// Copyright 2024 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::{
16    cmp::Ordering,
17    collections::{vec_deque::Iter, VecDeque},
18    ops::{Deref, RangeBounds},
19    sync::Arc,
20};
21
22use eyeball_im::{
23    ObservableVector, ObservableVectorEntries, ObservableVectorEntry, ObservableVectorTransaction,
24    ObservableVectorTransactionEntry, VectorSubscriber,
25};
26use imbl::Vector;
27use ruma::EventId;
28
29use super::{metadata::EventMeta, TimelineItem};
30
31/// An `ObservableItems` is a type similar to
32/// [`ObservableVector<Arc<TimelineItem>>`] except the API is limited and,
33/// internally, maintains the mapping between remote events and timeline items.
34#[derive(Debug)]
35pub struct ObservableItems {
36    /// All timeline items.
37    ///
38    /// Yeah, there are here! This [`ObservableVector`] contains all the
39    /// timeline items that are rendered in your magnificent Matrix client.
40    ///
41    /// These items are the _core_ of the timeline, see [`TimelineItem`] to
42    /// learn more.
43    items: ObservableVector<Arc<TimelineItem>>,
44
45    /// List of all the remote events as received in the timeline, even the ones
46    /// that are discarded in the timeline items.
47    ///
48    /// The list of all remote events is used to compute the read receipts and
49    /// read markers; additionally it's used to map events to timeline items,
50    /// for more info about that, take a look at the documentation for
51    /// [`EventMeta::timeline_item_index`].
52    all_remote_events: AllRemoteEvents,
53}
54
55impl ObservableItems {
56    /// Create an empty `ObservableItems`.
57    pub fn new() -> Self {
58        Self {
59            // Upstream default capacity is currently 16, which is making
60            // sliding-sync tests with 20 events lag. This should still be
61            // small enough.
62            items: ObservableVector::with_capacity(32),
63            all_remote_events: AllRemoteEvents::default(),
64        }
65    }
66
67    /// Get a reference to all remote events.
68    pub fn all_remote_events(&self) -> &AllRemoteEvents {
69        &self.all_remote_events
70    }
71
72    /// Check whether there is timeline items.
73    pub fn is_empty(&self) -> bool {
74        self.items.is_empty()
75    }
76
77    /// Subscribe to timeline item updates.
78    pub fn subscribe(&self) -> VectorSubscriber<Arc<TimelineItem>> {
79        self.items.subscribe()
80    }
81
82    /// Get a clone of all timeline items.
83    ///
84    /// Note that it doesn't clone `Self`, only the inner timeline items.
85    pub fn clone_items(&self) -> Vector<Arc<TimelineItem>> {
86        self.items.clone()
87    }
88
89    /// Start a new transaction to make multiple updates as one unit.
90    pub fn transaction(&mut self) -> ObservableItemsTransaction<'_> {
91        ObservableItemsTransaction {
92            items: self.items.transaction(),
93            all_remote_events: &mut self.all_remote_events,
94        }
95    }
96
97    /// Replace the timeline item at position `timeline_item_index` by
98    /// `timeline_item`.
99    ///
100    /// # Panics
101    ///
102    /// Panics if `timeline_item_index > total_number_of_timeline_items`.
103    pub fn replace(
104        &mut self,
105        timeline_item_index: usize,
106        timeline_item: Arc<TimelineItem>,
107    ) -> Arc<TimelineItem> {
108        self.items.set(timeline_item_index, timeline_item)
109    }
110
111    /// Get an iterator over all the entries in this `ObservableItems`.
112    pub fn entries(&mut self) -> ObservableItemsEntries<'_> {
113        ObservableItemsEntries(self.items.entries())
114    }
115
116    /// Call the given closure for every element in this `ObservableItems`,
117    /// with an entry struct that allows updating that element.
118    pub fn for_each<F>(&mut self, mut f: F)
119    where
120        F: FnMut(ObservableItemsEntry<'_>),
121    {
122        self.items.for_each(|entry| f(ObservableItemsEntry(entry)))
123    }
124}
125
126// It's fine to deref to an immutable reference to `Vector`.
127//
128// We don't want, however, to deref to a mutable reference: it should be done
129// via proper methods to control precisely the mapping between remote events and
130// timeline items.
131impl Deref for ObservableItems {
132    type Target = Vector<Arc<TimelineItem>>;
133
134    fn deref(&self) -> &Self::Target {
135        &self.items
136    }
137}
138
139/// An iterator that yields entries into an `ObservableItems`.
140///
141/// It doesn't implement [`Iterator`] though because of a lifetime conflict: the
142/// returned `Iterator::Item` could live longer than the `Iterator` itself.
143/// Ideally, `Iterator::next` should take a `&'a mut self`, but this is not
144/// possible.
145pub struct ObservableItemsEntries<'a>(ObservableVectorEntries<'a, Arc<TimelineItem>>);
146
147impl ObservableItemsEntries<'_> {
148    /// Advance this iterator, yielding an `ObservableItemsEntry` for the next
149    /// item in the timeline, or `None` if all items have been visited.
150    pub fn next(&mut self) -> Option<ObservableItemsEntry<'_>> {
151        self.0.next().map(ObservableItemsEntry)
152    }
153}
154
155/// A handle to a single timeline item in an `ObservableItems`.
156#[derive(Debug)]
157pub struct ObservableItemsEntry<'a>(ObservableVectorEntry<'a, Arc<TimelineItem>>);
158
159impl ObservableItemsEntry<'_> {
160    /// Replace the timeline item by `timeline_item`.
161    pub fn replace(this: &mut Self, timeline_item: Arc<TimelineItem>) -> Arc<TimelineItem> {
162        ObservableVectorEntry::set(&mut this.0, timeline_item)
163    }
164}
165
166// It's fine to deref to an immutable reference to `Arc<TimelineItem>`.
167//
168// We don't want, however, to deref to a mutable reference: it should be done
169// via proper methods to control precisely the mapping between remote events and
170// timeline items.
171impl Deref for ObservableItemsEntry<'_> {
172    type Target = Arc<TimelineItem>;
173
174    fn deref(&self) -> &Self::Target {
175        &self.0
176    }
177}
178
179/// A transaction that allows making multiple updates to an `ObservableItems` as
180/// an atomic unit.
181///
182/// For updates from the transaction to have affect, it has to be finalized with
183/// [`ObservableItemsTransaction::commit`]. If the transaction is dropped
184/// without that method being called, the updates will be discarded.
185#[derive(Debug)]
186pub struct ObservableItemsTransaction<'observable_items> {
187    items: ObservableVectorTransaction<'observable_items, Arc<TimelineItem>>,
188    all_remote_events: &'observable_items mut AllRemoteEvents,
189}
190
191impl<'observable_items> ObservableItemsTransaction<'observable_items> {
192    /// Get a reference to the timeline item at position `timeline_item_index`.
193    pub fn get(&self, timeline_item_index: usize) -> Option<&Arc<TimelineItem>> {
194        self.items.get(timeline_item_index)
195    }
196
197    /// Get a reference to all remote events.
198    pub fn all_remote_events(&self) -> &AllRemoteEvents {
199        self.all_remote_events
200    }
201
202    /// Remove a remote event at the `event_index` position.
203    ///
204    /// Not to be confused with removing a timeline item!
205    pub fn remove_remote_event(&mut self, event_index: usize) -> Option<EventMeta> {
206        self.all_remote_events.remove(event_index)
207    }
208
209    /// Push a new remote event at the front of all remote events.
210    ///
211    /// Not to be confused with pushing a timeline item to the front!
212    pub fn push_front_remote_event(&mut self, event_meta: EventMeta) {
213        self.all_remote_events.push_front(event_meta);
214    }
215
216    /// Push a new remote event at the back of all remote events.
217    ///
218    /// Not to be confused with pushing a timeline item to the back!
219    pub fn push_back_remote_event(&mut self, event_meta: EventMeta) {
220        self.all_remote_events.push_back(event_meta);
221    }
222
223    /// Insert a new remote event at a specific index.
224    ///
225    /// Not to be confused with inserting a timeline item!
226    pub fn insert_remote_event(&mut self, event_index: usize, event_meta: EventMeta) {
227        self.all_remote_events.insert(event_index, event_meta);
228    }
229
230    /// Get a remote event by using an event ID.
231    pub fn get_remote_event_by_event_id_mut(
232        &mut self,
233        event_id: &EventId,
234    ) -> Option<&mut EventMeta> {
235        self.all_remote_events.get_by_event_id_mut(event_id)
236    }
237
238    /// Get a remote event by using an event ID.
239    pub fn get_remote_event_by_event_id(&self, event_id: &EventId) -> Option<&EventMeta> {
240        self.all_remote_events.get_by_event_id(event_id)
241    }
242
243    /// Replace a timeline item at position `timeline_item_index` by
244    /// `timeline_item`.
245    pub fn replace(
246        &mut self,
247        timeline_item_index: usize,
248        timeline_item: Arc<TimelineItem>,
249    ) -> Arc<TimelineItem> {
250        self.items.set(timeline_item_index, timeline_item)
251    }
252
253    /// Remove a timeline item at position `timeline_item_index`.
254    pub fn remove(&mut self, timeline_item_index: usize) -> Arc<TimelineItem> {
255        let removed_timeline_item = self.items.remove(timeline_item_index);
256        self.all_remote_events.timeline_item_has_been_removed_at(timeline_item_index);
257
258        removed_timeline_item
259    }
260
261    /// Insert a new `timeline_item` at position `timeline_item_index`, with an
262    /// optionally associated `event_index`.
263    ///
264    /// If `event_index` is `Some(_)`, it means `timeline_item_index` has an
265    /// associated remote event (at position `event_index`) that maps to it.
266    /// Otherwise, if it is `None`, it means there is no remote event associated
267    /// to it; that's the case for virtual timeline item for example. See
268    /// [`EventMeta::timeline_item_index`] to learn more.
269    pub fn insert(
270        &mut self,
271        timeline_item_index: usize,
272        timeline_item: Arc<TimelineItem>,
273        event_index: Option<usize>,
274    ) {
275        self.items.insert(timeline_item_index, timeline_item);
276        self.all_remote_events.timeline_item_has_been_inserted_at(timeline_item_index, event_index);
277    }
278
279    /// Push a new `timeline_item` at position 0, with an optionally associated
280    /// `event_index`.
281    ///
282    /// If `event_index` is `Some(_)`, it means `timeline_item_index` has an
283    /// associated remote event (at position `event_index`) that maps to it.
284    /// Otherwise, if it is `None`, it means there is no remote event associated
285    /// to it; that's the case for virtual timeline item for example. See
286    /// [`EventMeta::timeline_item_index`] to learn more.
287    pub fn push_front(&mut self, timeline_item: Arc<TimelineItem>, event_index: Option<usize>) {
288        self.items.push_front(timeline_item);
289        self.all_remote_events.timeline_item_has_been_inserted_at(0, event_index);
290    }
291
292    /// Push a new `timeline_item` at position `len() - 1`, with an optionally
293    /// associated `event_index`.
294    ///
295    /// If `event_index` is `Some(_)`, it means `timeline_item_index` has an
296    /// associated remote event (at position `event_index`) that maps to it.
297    /// Otherwise, if it is `None`, it means there is no remote event associated
298    /// to it; that's the case for virtual timeline item for example. See
299    /// [`EventMeta::timeline_item_index`] to learn more.
300    pub fn push_back(&mut self, timeline_item: Arc<TimelineItem>, event_index: Option<usize>) {
301        self.items.push_back(timeline_item);
302        self.all_remote_events
303            .timeline_item_has_been_inserted_at(self.items.len().saturating_sub(1), event_index);
304    }
305
306    /// Clear all timeline items and all remote events.
307    pub fn clear(&mut self) {
308        self.items.clear();
309        self.all_remote_events.clear();
310    }
311
312    /// Call the given closure for every element in this `ObservableItems`,
313    /// with an entry struct that allows updating that element.
314    pub fn for_each<F>(&mut self, mut f: F)
315    where
316        F: FnMut(ObservableItemsTransactionEntry<'_, 'observable_items>),
317    {
318        self.items.for_each(|entry| {
319            f(ObservableItemsTransactionEntry { entry, all_remote_events: self.all_remote_events })
320        })
321    }
322
323    /// Commit this transaction, persisting the changes and notifying
324    /// subscribers.
325    pub fn commit(self) {
326        self.items.commit()
327    }
328}
329
330// It's fine to deref to an immutable reference to `Vector`.
331//
332// We don't want, however, to deref to a mutable reference: it should be done
333// via proper methods to control precisely the mapping between remote events and
334// timeline items.
335impl Deref for ObservableItemsTransaction<'_> {
336    type Target = Vector<Arc<TimelineItem>>;
337
338    fn deref(&self) -> &Self::Target {
339        &self.items
340    }
341}
342
343/// A handle to a single timeline item in an `ObservableItemsTransaction`.
344pub struct ObservableItemsTransactionEntry<'observable_transaction_items, 'observable_items> {
345    entry: ObservableVectorTransactionEntry<
346        'observable_transaction_items,
347        'observable_items,
348        Arc<TimelineItem>,
349    >,
350    all_remote_events: &'observable_transaction_items mut AllRemoteEvents,
351}
352
353impl ObservableItemsTransactionEntry<'_, '_> {
354    /// Remove this timeline item.
355    pub fn remove(this: Self) {
356        let entry_index = ObservableVectorTransactionEntry::index(&this.entry);
357
358        ObservableVectorTransactionEntry::remove(this.entry);
359        this.all_remote_events.timeline_item_has_been_removed_at(entry_index);
360    }
361}
362
363// It's fine to deref to an immutable reference to `Arc<TimelineItem>`.
364//
365// We don't want, however, to deref to a mutable reference: it should be done
366// via proper methods to control precisely the mapping between remote events and
367// timeline items.
368impl Deref for ObservableItemsTransactionEntry<'_, '_> {
369    type Target = Arc<TimelineItem>;
370
371    fn deref(&self) -> &Self::Target {
372        &self.entry
373    }
374}
375
376#[cfg(test)]
377mod observable_items_tests {
378    use std::ops::Not;
379
380    use assert_matches::assert_matches;
381    use eyeball_im::VectorDiff;
382    use ruma::{
383        events::room::message::{MessageType, TextMessageEventContent},
384        owned_user_id, MilliSecondsSinceUnixEpoch,
385    };
386    use stream_assert::assert_next_matches;
387
388    use super::*;
389    use crate::timeline::{
390        controller::{EventTimelineItemKind, RemoteEventOrigin},
391        event_item::RemoteEventTimelineItem,
392        EventTimelineItem, Message, TimelineDetails, TimelineItemContent, TimelineUniqueId,
393    };
394
395    fn item(event_id: &str) -> Arc<TimelineItem> {
396        TimelineItem::new(
397            EventTimelineItem::new(
398                owned_user_id!("@ivan:mnt.io"),
399                TimelineDetails::Unavailable,
400                MilliSecondsSinceUnixEpoch(0u32.into()),
401                TimelineItemContent::Message(Message {
402                    msgtype: MessageType::Text(TextMessageEventContent::plain("hello")),
403                    in_reply_to: None,
404                    thread_root: None,
405                    edited: false,
406                    mentions: None,
407                    reactions: Default::default(),
408                }),
409                EventTimelineItemKind::Remote(RemoteEventTimelineItem {
410                    event_id: event_id.parse().unwrap(),
411                    transaction_id: None,
412                    read_receipts: Default::default(),
413                    is_own: false,
414                    is_highlighted: false,
415                    encryption_info: None,
416                    original_json: None,
417                    latest_edit_json: None,
418                    origin: RemoteEventOrigin::Sync,
419                }),
420                false,
421            ),
422            TimelineUniqueId(format!("__id_{event_id}")),
423        )
424    }
425
426    fn read_marker() -> Arc<TimelineItem> {
427        TimelineItem::read_marker()
428    }
429
430    fn event_meta(event_id: &str) -> EventMeta {
431        EventMeta { event_id: event_id.parse().unwrap(), timeline_item_index: None, visible: false }
432    }
433
434    macro_rules! assert_event_id {
435        ( $timeline_item:expr, $event_id:literal $( , $message:expr )? $(,)? ) => {
436            assert_eq!($timeline_item.as_event().unwrap().event_id().unwrap().as_str(), $event_id $( , $message)? );
437        };
438    }
439
440    macro_rules! assert_mapping {
441        ( on $transaction:ident:
442          | event_id | event_index | timeline_item_index |
443          | $( - )+ | $( - )+ | $( - )+ |
444          $(
445            | $event_id:literal | $event_index:literal | $( $timeline_item_index:literal )? |
446          )+
447        ) => {
448            let all_remote_events = $transaction .all_remote_events();
449
450            $(
451                // Remote event exists at this index…
452                assert_matches!(all_remote_events.0.get( $event_index ), Some(EventMeta { event_id, timeline_item_index, .. }) => {
453                    // … this is the remote event with the expected event ID
454                    assert_eq!(
455                        event_id.as_str(),
456                        $event_id ,
457                        concat!("event #", $event_index, " should have ID ", $event_id)
458                    );
459
460
461                    // (tiny hack to handle the case where `$timeline_item_index` is absent)
462                    #[allow(unused_variables)]
463                    let timeline_item_index_is_expected = false;
464                    $(
465                        let timeline_item_index_is_expected = true;
466                        let _ = $timeline_item_index;
467                    )?
468
469                    if timeline_item_index_is_expected.not() {
470                        // … this remote event does NOT map to a timeline item index
471                        assert!(
472                            timeline_item_index.is_none(),
473                            concat!("event #", $event_index, " with ID ", $event_id, " should NOT map to a timeline item index" )
474                        );
475                    }
476
477                    $(
478                        // … this remote event maps to a timeline item index
479                        assert_eq!(
480                            *timeline_item_index,
481                            Some( $timeline_item_index ),
482                            concat!("event #", $event_index, " with ID ", $event_id, " should map to timeline item #", $timeline_item_index )
483                        );
484
485                        // … this timeline index exists
486                        assert_matches!( $transaction .get( $timeline_item_index ), Some(timeline_item) => {
487                            // … this timelime item has the expected event ID
488                            assert_event_id!(
489                                timeline_item,
490                                $event_id ,
491                                concat!("timeline item #", $timeline_item_index, " should map to event ID ", $event_id )
492                            );
493                        });
494                    )?
495                });
496            )*
497        }
498    }
499
500    #[test]
501    fn test_is_empty() {
502        let mut items = ObservableItems::new();
503
504        assert!(items.is_empty());
505
506        // Push one event to check if `is_empty` returns false.
507        let mut transaction = items.transaction();
508        transaction.push_back(item("$ev0"), Some(0));
509        transaction.commit();
510
511        assert!(items.is_empty().not());
512    }
513
514    #[test]
515    fn test_subscribe() {
516        let mut items = ObservableItems::new();
517        let mut subscriber = items.subscribe().into_stream();
518
519        // Push one event to check the subscriber is emitting something.
520        let mut transaction = items.transaction();
521        transaction.push_back(item("$ev0"), Some(0));
522        transaction.commit();
523
524        // It does!
525        assert_next_matches!(subscriber, VectorDiff::PushBack { value: event } => {
526            assert_event_id!(event, "$ev0");
527        });
528    }
529
530    #[test]
531    fn test_clone_items() {
532        let mut items = ObservableItems::new();
533
534        let mut transaction = items.transaction();
535        transaction.push_back(item("$ev0"), Some(0));
536        transaction.push_back(item("$ev1"), Some(1));
537        transaction.commit();
538
539        let items = items.clone_items();
540        assert_eq!(items.len(), 2);
541        assert_event_id!(items[0], "$ev0");
542        assert_event_id!(items[1], "$ev1");
543    }
544
545    #[test]
546    fn test_replace() {
547        let mut items = ObservableItems::new();
548
549        // Push one event that will be replaced.
550        let mut transaction = items.transaction();
551        transaction.push_back(item("$ev0"), Some(0));
552        transaction.commit();
553
554        // That's time to replace it!
555        items.replace(0, item("$ev1"));
556
557        let items = items.clone_items();
558        assert_eq!(items.len(), 1);
559        assert_event_id!(items[0], "$ev1");
560    }
561
562    #[test]
563    fn test_entries() {
564        let mut items = ObservableItems::new();
565
566        // Push events to iterate on.
567        let mut transaction = items.transaction();
568        transaction.push_back(item("$ev0"), Some(0));
569        transaction.push_back(item("$ev1"), Some(1));
570        transaction.push_back(item("$ev2"), Some(2));
571        transaction.commit();
572
573        let mut entries = items.entries();
574
575        assert_matches!(entries.next(), Some(entry) => {
576            assert_event_id!(entry, "$ev0");
577        });
578        assert_matches!(entries.next(), Some(entry) => {
579            assert_event_id!(entry, "$ev1");
580        });
581        assert_matches!(entries.next(), Some(entry) => {
582            assert_event_id!(entry, "$ev2");
583        });
584        assert_matches!(entries.next(), None);
585    }
586
587    #[test]
588    fn test_entry_replace() {
589        let mut items = ObservableItems::new();
590
591        // Push events to iterate on.
592        let mut transaction = items.transaction();
593        transaction.push_back(item("$ev0"), Some(0));
594        transaction.commit();
595
596        let mut entries = items.entries();
597
598        // Replace one event by another one.
599        assert_matches!(entries.next(), Some(mut entry) => {
600            assert_event_id!(entry, "$ev0");
601            ObservableItemsEntry::replace(&mut entry, item("$ev1"));
602        });
603        assert_matches!(entries.next(), None);
604
605        // Check the new event.
606        let mut entries = items.entries();
607
608        assert_matches!(entries.next(), Some(entry) => {
609            assert_event_id!(entry, "$ev1");
610        });
611        assert_matches!(entries.next(), None);
612    }
613
614    #[test]
615    fn test_for_each() {
616        let mut items = ObservableItems::new();
617
618        // Push events to iterate on.
619        let mut transaction = items.transaction();
620        transaction.push_back(item("$ev0"), Some(0));
621        transaction.push_back(item("$ev1"), Some(1));
622        transaction.push_back(item("$ev2"), Some(2));
623        transaction.commit();
624
625        let mut nth = 0;
626
627        // Iterate over events.
628        items.for_each(|entry| {
629            match nth {
630                0 => {
631                    assert_event_id!(entry, "$ev0");
632                }
633                1 => {
634                    assert_event_id!(entry, "$ev1");
635                }
636                2 => {
637                    assert_event_id!(entry, "$ev2");
638                }
639                _ => unreachable!(),
640            }
641
642            nth += 1;
643        });
644    }
645
646    #[test]
647    fn test_transaction_commit() {
648        let mut items = ObservableItems::new();
649
650        // Don't commit the transaction.
651        let mut transaction = items.transaction();
652        transaction.push_back(item("$ev0"), Some(0));
653        drop(transaction);
654
655        assert!(items.is_empty());
656
657        // Commit the transaction.
658        let mut transaction = items.transaction();
659        transaction.push_back(item("$ev0"), Some(0));
660        transaction.commit();
661
662        assert!(items.is_empty().not());
663    }
664
665    #[test]
666    fn test_transaction_get() {
667        let mut items = ObservableItems::new();
668
669        let mut transaction = items.transaction();
670        transaction.push_back(item("$ev0"), Some(0));
671
672        assert_matches!(transaction.get(0), Some(event) => {
673            assert_event_id!(event, "$ev0");
674        });
675    }
676
677    #[test]
678    fn test_transaction_replace() {
679        let mut items = ObservableItems::new();
680
681        let mut transaction = items.transaction();
682        transaction.push_back(item("$ev0"), Some(0));
683        transaction.replace(0, item("$ev1"));
684
685        assert_matches!(transaction.get(0), Some(event) => {
686            assert_event_id!(event, "$ev1");
687        });
688    }
689
690    #[test]
691    fn test_transaction_insert() {
692        let mut items = ObservableItems::new();
693
694        let mut transaction = items.transaction();
695
696        // Remote event with its timeline item.
697        transaction.push_back_remote_event(event_meta("$ev0"));
698        transaction.insert(0, item("$ev0"), Some(0));
699
700        assert_mapping! {
701            on transaction:
702
703            | event_id | event_index | timeline_item_index |
704            |----------|-------------|---------------------|
705            | "$ev0"   | 0           | 0                   | // new
706        }
707
708        // Timeline item without a remote event (for example a read marker).
709        transaction.insert(0, read_marker(), None);
710
711        assert_mapping! {
712            on transaction:
713
714            | event_id | event_index | timeline_item_index |
715            |----------|-------------|---------------------|
716            | "$ev0"   | 0           | 1                   | // has shifted
717        }
718
719        // Remote event with its timeline item.
720        transaction.push_back_remote_event(event_meta("$ev1"));
721        transaction.insert(2, item("$ev1"), Some(1));
722
723        assert_mapping! {
724            on transaction:
725
726            | event_id | event_index | timeline_item_index |
727            |----------|-------------|---------------------|
728            | "$ev0"   | 0           | 1                   |
729            | "$ev1"   | 1           | 2                   | // new
730        }
731
732        // Remote event without a timeline item (for example a state event).
733        transaction.push_back_remote_event(event_meta("$ev2"));
734
735        assert_mapping! {
736            on transaction:
737
738            | event_id | event_index | timeline_item_index |
739            |----------|-------------|---------------------|
740            | "$ev0"   | 0           | 1                   |
741            | "$ev1"   | 1           | 2                   |
742            | "$ev2"   | 2           |                     | // new
743        }
744
745        // Remote event with its timeline item.
746        transaction.push_back_remote_event(event_meta("$ev3"));
747        transaction.insert(3, item("$ev3"), Some(3));
748
749        assert_mapping! {
750            on transaction:
751
752            | event_id | event_index | timeline_item_index |
753            |----------|-------------|---------------------|
754            | "$ev0"   | 0           | 1                   |
755            | "$ev1"   | 1           | 2                   |
756            | "$ev2"   | 2           |                     |
757            | "$ev3"   | 3           | 3                   | // new
758        }
759
760        // Timeline item with a remote event, but late.
761        // I don't know if this case is possible in reality, but let's be robust.
762        transaction.insert(3, item("$ev2"), Some(2));
763
764        assert_mapping! {
765            on transaction:
766
767            | event_id | event_index | timeline_item_index |
768            |----------|-------------|---------------------|
769            | "$ev0"   | 0           | 1                   |
770            | "$ev1"   | 1           | 2                   |
771            | "$ev2"   | 2           | 3                   | // updated
772            | "$ev3"   | 3           | 4                   | // has shifted
773        }
774
775        // Let's move the read marker for the fun.
776        transaction.remove(0);
777        transaction.insert(2, read_marker(), None);
778
779        assert_mapping! {
780            on transaction:
781
782            | event_id | event_index | timeline_item_index |
783            |----------|-------------|---------------------|
784            | "$ev0"   | 0           | 0                   | // has shifted
785            | "$ev1"   | 1           | 1                   | // has shifted
786            | "$ev2"   | 2           | 3                   |
787            | "$ev3"   | 3           | 4                   |
788        }
789
790        assert_eq!(transaction.len(), 5);
791    }
792
793    #[test]
794    fn test_transaction_push_front() {
795        let mut items = ObservableItems::new();
796
797        let mut transaction = items.transaction();
798
799        // Remote event with its timeline item.
800        transaction.push_front_remote_event(event_meta("$ev0"));
801        transaction.push_front(item("$ev0"), Some(0));
802
803        assert_mapping! {
804            on transaction:
805
806            | event_id | event_index | timeline_item_index |
807            |----------|-------------|---------------------|
808            | "$ev0"   | 0           | 0                   | // new
809        }
810
811        // Timeline item without a remote event (for example a read marker).
812        transaction.push_front(read_marker(), None);
813
814        assert_mapping! {
815            on transaction:
816
817            | event_id | event_index | timeline_item_index |
818            |----------|-------------|---------------------|
819            | "$ev0"   | 0           | 1                   | // has shifted
820        }
821
822        // Remote event with its timeline item.
823        transaction.push_front_remote_event(event_meta("$ev1"));
824        transaction.push_front(item("$ev1"), Some(0));
825
826        assert_mapping! {
827            on transaction:
828
829            | event_id | event_index | timeline_item_index |
830            |----------|-------------|---------------------|
831            | "$ev1"   | 0           | 0                   | // new
832            | "$ev0"   | 1           | 2                   | // has shifted
833        }
834
835        // Remote event without a timeline item (for example a state event).
836        transaction.push_front_remote_event(event_meta("$ev2"));
837
838        assert_mapping! {
839            on transaction:
840
841            | event_id | event_index | timeline_item_index |
842            |----------|-------------|---------------------|
843            | "$ev2"   | 0           |                     |
844            | "$ev1"   | 1           | 0                   | // has shifted
845            | "$ev0"   | 2           | 2                   | // has shifted
846        }
847
848        // Remote event with its timeline item.
849        transaction.push_front_remote_event(event_meta("$ev3"));
850        transaction.push_front(item("$ev3"), Some(0));
851
852        assert_mapping! {
853            on transaction:
854
855            | event_id | event_index | timeline_item_index |
856            |----------|-------------|---------------------|
857            | "$ev3"   | 0           | 0                   | // new
858            | "$ev2"   | 1           |                     |
859            | "$ev1"   | 2           | 1                   | // has shifted
860            | "$ev0"   | 3           | 3                   | // has shifted
861        }
862
863        assert_eq!(transaction.len(), 4);
864    }
865
866    #[test]
867    fn test_transaction_push_back() {
868        let mut items = ObservableItems::new();
869
870        let mut transaction = items.transaction();
871
872        // Remote event with its timeline item.
873        transaction.push_back_remote_event(event_meta("$ev0"));
874        transaction.push_back(item("$ev0"), Some(0));
875
876        assert_mapping! {
877            on transaction:
878
879            | event_id | event_index | timeline_item_index |
880            |----------|-------------|---------------------|
881            | "$ev0"   | 0           | 0                   | // new
882        }
883
884        // Timeline item without a remote event (for example a read marker).
885        transaction.push_back(read_marker(), None);
886
887        assert_mapping! {
888            on transaction:
889
890            | event_id | event_index | timeline_item_index |
891            |----------|-------------|---------------------|
892            | "$ev0"   | 0           | 0                   |
893        }
894
895        // Remote event with its timeline item.
896        transaction.push_back_remote_event(event_meta("$ev1"));
897        transaction.push_back(item("$ev1"), Some(1));
898
899        assert_mapping! {
900            on transaction:
901
902            | event_id | event_index | timeline_item_index |
903            |----------|-------------|---------------------|
904            | "$ev0"   | 0           | 0                   |
905            | "$ev1"   | 1           | 2                   | // new
906        }
907
908        // Remote event without a timeline item (for example a state event).
909        transaction.push_back_remote_event(event_meta("$ev2"));
910
911        assert_mapping! {
912            on transaction:
913
914            | event_id | event_index | timeline_item_index |
915            |----------|-------------|---------------------|
916            | "$ev0"   | 0           | 0                   |
917            | "$ev1"   | 1           | 2                   |
918            | "$ev2"   | 2           |                     | // new
919        }
920
921        // Remote event with its timeline item.
922        transaction.push_back_remote_event(event_meta("$ev3"));
923        transaction.push_back(item("$ev3"), Some(3));
924
925        assert_mapping! {
926            on transaction:
927
928            | event_id | event_index | timeline_item_index |
929            |----------|-------------|---------------------|
930            | "$ev0"   | 0           | 0                   |
931            | "$ev1"   | 1           | 2                   |
932            | "$ev2"   | 2           |                     |
933            | "$ev3"   | 3           | 3                   | // new
934        }
935
936        assert_eq!(transaction.len(), 4);
937    }
938
939    #[test]
940    fn test_transaction_remove() {
941        let mut items = ObservableItems::new();
942
943        let mut transaction = items.transaction();
944
945        // Remote event with its timeline item.
946        transaction.push_back_remote_event(event_meta("$ev0"));
947        transaction.push_back(item("$ev0"), Some(0));
948
949        // Timeline item without a remote event (for example a read marker).
950        transaction.push_back(read_marker(), None);
951
952        // Remote event with its timeline item.
953        transaction.push_back_remote_event(event_meta("$ev1"));
954        transaction.push_back(item("$ev1"), Some(1));
955
956        // Remote event without a timeline item (for example a state event).
957        transaction.push_back_remote_event(event_meta("$ev2"));
958
959        // Remote event with its timeline item.
960        transaction.push_back_remote_event(event_meta("$ev3"));
961        transaction.push_back(item("$ev3"), Some(3));
962
963        assert_mapping! {
964            on transaction:
965
966            | event_id | event_index | timeline_item_index |
967            |----------|-------------|---------------------|
968            | "$ev0"   | 0           | 0                   |
969            | "$ev1"   | 1           | 2                   |
970            | "$ev2"   | 2           |                     |
971            | "$ev3"   | 3           | 3                   |
972        }
973
974        // Remove the timeline item that has no event.
975        transaction.remove(1);
976
977        assert_mapping! {
978            on transaction:
979
980            | event_id | event_index | timeline_item_index |
981            |----------|-------------|---------------------|
982            | "$ev0"   | 0           | 0                   |
983            | "$ev1"   | 1           | 1                   | // has shifted
984            | "$ev2"   | 2           |                     |
985            | "$ev3"   | 3           | 2                   | // has shifted
986        }
987
988        // Remove an timeline item that has an event.
989        transaction.remove(1);
990
991        assert_mapping! {
992            on transaction:
993
994            | event_id | event_index | timeline_item_index |
995            |----------|-------------|---------------------|
996            | "$ev0"   | 0           | 0                   |
997            | "$ev1"   | 1           |                     | // has been removed
998            | "$ev2"   | 2           |                     |
999            | "$ev3"   | 3           | 1                   | // has shifted
1000        }
1001
1002        // Remove the last timeline item to test off by 1 error.
1003        transaction.remove(1);
1004
1005        assert_mapping! {
1006            on transaction:
1007
1008            | event_id | event_index | timeline_item_index |
1009            |----------|-------------|---------------------|
1010            | "$ev0"   | 0           | 0                   |
1011            | "$ev1"   | 1           |                     |
1012            | "$ev2"   | 2           |                     |
1013            | "$ev3"   | 3           |                     | // has been removed
1014        }
1015
1016        // Remove all the items \o/
1017        transaction.remove(0);
1018
1019        assert_mapping! {
1020            on transaction:
1021
1022            | event_id | event_index | timeline_item_index |
1023            |----------|-------------|---------------------|
1024            | "$ev0"   | 0           |                     | // has been removed
1025            | "$ev1"   | 1           |                     |
1026            | "$ev2"   | 2           |                     |
1027            | "$ev3"   | 3           |                     |
1028        }
1029
1030        assert!(transaction.is_empty());
1031    }
1032
1033    #[test]
1034    fn test_transaction_clear() {
1035        let mut items = ObservableItems::new();
1036
1037        let mut transaction = items.transaction();
1038
1039        // Remote event with its timeline item.
1040        transaction.push_back_remote_event(event_meta("$ev0"));
1041        transaction.push_back(item("$ev0"), Some(0));
1042
1043        // Timeline item without a remote event (for example a read marker).
1044        transaction.push_back(read_marker(), None);
1045
1046        // Remote event with its timeline item.
1047        transaction.push_back_remote_event(event_meta("$ev1"));
1048        transaction.push_back(item("$ev1"), Some(1));
1049
1050        // Remote event without a timeline item (for example a state event).
1051        transaction.push_back_remote_event(event_meta("$ev2"));
1052
1053        // Remote event with its timeline item.
1054        transaction.push_back_remote_event(event_meta("$ev3"));
1055        transaction.push_back(item("$ev3"), Some(3));
1056
1057        assert_mapping! {
1058            on transaction:
1059
1060            | event_id | event_index | timeline_item_index |
1061            |----------|-------------|---------------------|
1062            | "$ev0"   | 0           | 0                   |
1063            | "$ev1"   | 1           | 2                   |
1064            | "$ev2"   | 2           |                     |
1065            | "$ev3"   | 3           | 3                   |
1066        }
1067
1068        assert_eq!(transaction.all_remote_events().0.len(), 4);
1069        assert_eq!(transaction.len(), 4);
1070
1071        // Let's clear everything.
1072        transaction.clear();
1073
1074        assert!(transaction.all_remote_events().0.is_empty());
1075        assert!(transaction.is_empty());
1076    }
1077
1078    #[test]
1079    fn test_transaction_for_each() {
1080        let mut items = ObservableItems::new();
1081
1082        // Push events to iterate on.
1083        let mut transaction = items.transaction();
1084        transaction.push_back(item("$ev0"), Some(0));
1085        transaction.push_back(item("$ev1"), Some(1));
1086        transaction.push_back(item("$ev2"), Some(2));
1087
1088        let mut nth = 0;
1089
1090        // Iterate over events.
1091        transaction.for_each(|entry| {
1092            match nth {
1093                0 => {
1094                    assert_event_id!(entry, "$ev0");
1095                }
1096                1 => {
1097                    assert_event_id!(entry, "$ev1");
1098                }
1099                2 => {
1100                    assert_event_id!(entry, "$ev2");
1101                }
1102                _ => unreachable!(),
1103            }
1104
1105            nth += 1;
1106        });
1107    }
1108
1109    #[test]
1110    fn test_transaction_for_each_remove() {
1111        let mut items = ObservableItems::new();
1112
1113        // Push events to iterate on.
1114        let mut transaction = items.transaction();
1115
1116        transaction.push_back_remote_event(event_meta("$ev0"));
1117        transaction.push_back(item("$ev0"), Some(0));
1118
1119        transaction.push_back_remote_event(event_meta("$ev1"));
1120        transaction.push_back(item("$ev1"), Some(1));
1121
1122        transaction.push_back_remote_event(event_meta("$ev2"));
1123        transaction.push_back(item("$ev2"), Some(2));
1124
1125        assert_mapping! {
1126            on transaction:
1127
1128            | event_id | event_index | timeline_item_index |
1129            |----------|-------------|---------------------|
1130            | "$ev0"   | 0           | 0                   |
1131            | "$ev1"   | 1           | 1                   |
1132            | "$ev2"   | 2           | 2                   |
1133        }
1134
1135        // Iterate over events, and remove one.
1136        transaction.for_each(|entry| {
1137            if entry.as_event().unwrap().event_id().unwrap().as_str() == "$ev1" {
1138                ObservableItemsTransactionEntry::remove(entry);
1139            }
1140        });
1141
1142        assert_mapping! {
1143            on transaction:
1144
1145            | event_id | event_index | timeline_item_index |
1146            |----------|-------------|---------------------|
1147            | "$ev0"   | 0           | 0                   |
1148            | "$ev2"   | 2           | 1                   | // has shifted
1149        }
1150
1151        assert_eq!(transaction.all_remote_events().0.len(), 3);
1152        assert_eq!(transaction.len(), 2);
1153    }
1154}
1155
1156/// A type for all remote events.
1157///
1158/// Having this type helps to know exactly which parts of the code and how they
1159/// use all remote events. It also helps to give a bit of semantics on top of
1160/// them.
1161#[derive(Clone, Debug, Default)]
1162pub struct AllRemoteEvents(VecDeque<EventMeta>);
1163
1164impl AllRemoteEvents {
1165    /// Return a reference to a remote event.
1166    pub fn get(&self, event_index: usize) -> Option<&EventMeta> {
1167        self.0.get(event_index)
1168    }
1169
1170    /// Return a front-to-back iterator over all remote events.
1171    pub fn iter(&self) -> Iter<'_, EventMeta> {
1172        self.0.iter()
1173    }
1174
1175    /// Return a front-to-back iterator covering ranges of all remote events
1176    /// described by `range`.
1177    pub fn range<R>(&self, range: R) -> Iter<'_, EventMeta>
1178    where
1179        R: RangeBounds<usize>,
1180    {
1181        self.0.range(range)
1182    }
1183
1184    /// Remove all remote events.
1185    fn clear(&mut self) {
1186        self.0.clear();
1187    }
1188
1189    /// Insert a new remote event at the front of all the others.
1190    fn push_front(&mut self, event_meta: EventMeta) {
1191        // If there is an associated `timeline_item_index`, shift all the
1192        // `timeline_item_index` that come after this one.
1193        if let Some(new_timeline_item_index) = event_meta.timeline_item_index {
1194            self.increment_all_timeline_item_index_after(new_timeline_item_index);
1195        }
1196
1197        // Push the event.
1198        self.0.push_front(event_meta)
1199    }
1200
1201    /// Insert a new remote event at the back of all the others.
1202    fn push_back(&mut self, event_meta: EventMeta) {
1203        // If there is an associated `timeline_item_index`, shift all the
1204        // `timeline_item_index` that come after this one.
1205        if let Some(new_timeline_item_index) = event_meta.timeline_item_index {
1206            self.increment_all_timeline_item_index_after(new_timeline_item_index);
1207        }
1208
1209        // Push the event.
1210        self.0.push_back(event_meta)
1211    }
1212
1213    /// Insert a new remote event at a specific index.
1214    fn insert(&mut self, event_index: usize, event_meta: EventMeta) {
1215        // If there is an associated `timeline_item_index`, shift all the
1216        // `timeline_item_index` that come after this one.
1217        if let Some(new_timeline_item_index) = event_meta.timeline_item_index {
1218            self.increment_all_timeline_item_index_after(new_timeline_item_index);
1219        }
1220
1221        // Insert the event.
1222        self.0.insert(event_index, event_meta)
1223    }
1224
1225    /// Remove one remote event at a specific index, and return it if it exists.
1226    fn remove(&mut self, event_index: usize) -> Option<EventMeta> {
1227        // Remove the event.
1228        let event_meta = self.0.remove(event_index)?;
1229
1230        // If there is an associated `timeline_item_index`, shift all the
1231        // `timeline_item_index` that come after this one.
1232        if let Some(removed_timeline_item_index) = event_meta.timeline_item_index {
1233            self.decrement_all_timeline_item_index_after(removed_timeline_item_index);
1234        };
1235
1236        Some(event_meta)
1237    }
1238
1239    /// Return a reference to the last remote event if it exists.
1240    pub fn last(&self) -> Option<&EventMeta> {
1241        self.0.back()
1242    }
1243
1244    /// Return the index of the last remote event if it exists.
1245    pub fn last_index(&self) -> Option<usize> {
1246        self.0.len().checked_sub(1)
1247    }
1248
1249    /// Get a mutable reference to a specific remote event by its ID.
1250    pub fn get_by_event_id_mut(&mut self, event_id: &EventId) -> Option<&mut EventMeta> {
1251        self.0.iter_mut().rev().find(|event_meta| event_meta.event_id == event_id)
1252    }
1253
1254    /// Get an immutable reference to a specific remote event by its ID.
1255    pub fn get_by_event_id(&self, event_id: &EventId) -> Option<&EventMeta> {
1256        self.0.iter().rev().find(|event_meta| event_meta.event_id == event_id)
1257    }
1258
1259    /// Shift to the right all timeline item indexes that are equal to or
1260    /// greater than `new_timeline_item_index`.
1261    fn increment_all_timeline_item_index_after(&mut self, new_timeline_item_index: usize) {
1262        // Traverse items from back to front because:
1263        // - if `new_timeline_item_index` is 0, we need to shift all items anyways, so
1264        //   all items must be traversed,
1265        // - otherwise, it's unlikely we want to traverse all items: the item has been
1266        //   either inserted or pushed back, so there is no need to traverse the first
1267        //   items; we can also break the iteration as soon as all timeline item index
1268        //   after `new_timeline_item_index` has been updated.
1269        for event_meta in self.0.iter_mut().rev() {
1270            if let Some(timeline_item_index) = event_meta.timeline_item_index.as_mut() {
1271                if *timeline_item_index >= new_timeline_item_index {
1272                    *timeline_item_index += 1;
1273                } else {
1274                    // Items are ordered.
1275                    break;
1276                }
1277            }
1278        }
1279    }
1280
1281    /// Shift to the left all timeline item indexes that are greater than
1282    /// `removed_wtimeline_item_index`.
1283    fn decrement_all_timeline_item_index_after(&mut self, removed_timeline_item_index: usize) {
1284        // Traverse items from back to front because:
1285        // - if `new_timeline_item_index` is 0, we need to shift all items anyways, so
1286        //   all items must be traversed,
1287        // - otherwise, it's unlikely we want to traverse all items: the item has been
1288        //   either inserted or pushed back, so there is no need to traverse the first
1289        //   items; we can also break the iteration as soon as all timeline item index
1290        //   after `new_timeline_item_index` has been updated.
1291        for event_meta in self.0.iter_mut().rev() {
1292            if let Some(timeline_item_index) = event_meta.timeline_item_index.as_mut() {
1293                if *timeline_item_index > removed_timeline_item_index {
1294                    *timeline_item_index -= 1;
1295                } else {
1296                    // Items are ordered.
1297                    break;
1298                }
1299            }
1300        }
1301    }
1302
1303    /// Notify that a timeline item has been inserted at
1304    /// `new_timeline_item_index`. If `event_index` is `Some(_)`, it means the
1305    /// remote event at `event_index` must be mapped to
1306    /// `new_timeline_item_index`.
1307    fn timeline_item_has_been_inserted_at(
1308        &mut self,
1309        new_timeline_item_index: usize,
1310        event_index: Option<usize>,
1311    ) {
1312        self.increment_all_timeline_item_index_after(new_timeline_item_index);
1313
1314        if let Some(event_index) = event_index {
1315            if let Some(event_meta) = self.0.get_mut(event_index) {
1316                event_meta.timeline_item_index = Some(new_timeline_item_index);
1317            }
1318        }
1319    }
1320
1321    /// Notify that a timeline item has been removed at
1322    /// `new_timeline_item_index`.
1323    fn timeline_item_has_been_removed_at(&mut self, timeline_item_index_to_remove: usize) {
1324        for event_meta in self.0.iter_mut() {
1325            let mut remove_timeline_item_index = false;
1326
1327            // A `timeline_item_index` is removed. Let's shift all indexes that come
1328            // after the removed one.
1329            if let Some(timeline_item_index) = event_meta.timeline_item_index.as_mut() {
1330                match (*timeline_item_index).cmp(&timeline_item_index_to_remove) {
1331                    Ordering::Equal => {
1332                        remove_timeline_item_index = true;
1333                    }
1334
1335                    Ordering::Greater => {
1336                        *timeline_item_index -= 1;
1337                    }
1338
1339                    Ordering::Less => {}
1340                }
1341            }
1342
1343            // This is the `event_meta` that holds the `timeline_item_index` that is being
1344            // removed. So let's clean it.
1345            if remove_timeline_item_index {
1346                event_meta.timeline_item_index = None;
1347            }
1348        }
1349    }
1350}
1351
1352#[cfg(test)]
1353mod all_remote_events_tests {
1354    use assert_matches::assert_matches;
1355    use ruma::event_id;
1356
1357    use super::{AllRemoteEvents, EventMeta};
1358
1359    fn event_meta(event_id: &str, timeline_item_index: Option<usize>) -> EventMeta {
1360        EventMeta { event_id: event_id.parse().unwrap(), timeline_item_index, visible: false }
1361    }
1362
1363    macro_rules! assert_events {
1364        ( $events:ident, [ $( ( $event_id:literal, $timeline_item_index:expr ) ),* $(,)? ] ) => {
1365            let mut iter = $events .iter();
1366
1367            $(
1368                assert_matches!(iter.next(), Some(EventMeta { event_id, timeline_item_index, .. }) => {
1369                    assert_eq!(event_id.as_str(), $event_id );
1370                    assert_eq!(*timeline_item_index, $timeline_item_index );
1371                });
1372            )*
1373
1374            assert!(iter.next().is_none(), "Not all events have been asserted");
1375        }
1376    }
1377
1378    #[test]
1379    fn test_range() {
1380        let mut events = AllRemoteEvents::default();
1381
1382        // Push some events.
1383        events.push_back(event_meta("$ev0", None));
1384        events.push_back(event_meta("$ev1", None));
1385        events.push_back(event_meta("$ev2", None));
1386
1387        assert_eq!(events.iter().count(), 3);
1388
1389        // Test a few combinations.
1390        assert_eq!(events.range(..).count(), 3);
1391        assert_eq!(events.range(1..).count(), 2);
1392        assert_eq!(events.range(0..=1).count(), 2);
1393
1394        // Iterate on some of them.
1395        let mut some_events = events.range(1..);
1396
1397        assert_matches!(some_events.next(), Some(EventMeta { event_id, .. }) => {
1398            assert_eq!(event_id.as_str(), "$ev1");
1399        });
1400        assert_matches!(some_events.next(), Some(EventMeta { event_id, .. }) => {
1401            assert_eq!(event_id.as_str(), "$ev2");
1402        });
1403        assert!(some_events.next().is_none());
1404    }
1405
1406    #[test]
1407    fn test_clear() {
1408        let mut events = AllRemoteEvents::default();
1409
1410        // Push some events.
1411        events.push_back(event_meta("$ev0", None));
1412        events.push_back(event_meta("$ev1", None));
1413        events.push_back(event_meta("$ev2", None));
1414
1415        assert_eq!(events.iter().count(), 3);
1416
1417        // And clear them!
1418        events.clear();
1419
1420        assert_eq!(events.iter().count(), 0);
1421    }
1422
1423    #[test]
1424    fn test_push_front() {
1425        let mut events = AllRemoteEvents::default();
1426
1427        // Push front on an empty set, nothing particular.
1428        events.push_front(event_meta("$ev0", Some(1)));
1429
1430        // Push front with no `timeline_item_index`.
1431        events.push_front(event_meta("$ev1", None));
1432
1433        // Push front with a `timeline_item_index`.
1434        events.push_front(event_meta("$ev2", Some(0)));
1435
1436        // Push front with the same `timeline_item_index`.
1437        events.push_front(event_meta("$ev3", Some(0)));
1438
1439        assert_events!(
1440            events,
1441            [
1442                // `timeline_item_index` is untouched
1443                ("$ev3", Some(0)),
1444                // `timeline_item_index` has been shifted once
1445                ("$ev2", Some(1)),
1446                // no `timeline_item_index`
1447                ("$ev1", None),
1448                // `timeline_item_index` has been shifted twice
1449                ("$ev0", Some(3)),
1450            ]
1451        );
1452    }
1453
1454    #[test]
1455    fn test_push_back() {
1456        let mut events = AllRemoteEvents::default();
1457
1458        // Push back on an empty set, nothing particular.
1459        events.push_back(event_meta("$ev0", Some(0)));
1460
1461        // Push back with no `timeline_item_index`.
1462        events.push_back(event_meta("$ev1", None));
1463
1464        // Push back with a `timeline_item_index`.
1465        events.push_back(event_meta("$ev2", Some(1)));
1466
1467        // Push back with a `timeline_item_index` pointing to a timeline item that is
1468        // not the last one. Is it possible in practise? Normally not, but let's test
1469        // it anyway.
1470        events.push_back(event_meta("$ev3", Some(1)));
1471
1472        assert_events!(
1473            events,
1474            [
1475                // `timeline_item_index` is untouched
1476                ("$ev0", Some(0)),
1477                // no `timeline_item_index`
1478                ("$ev1", None),
1479                // `timeline_item_index` has been shifted once
1480                ("$ev2", Some(2)),
1481                // `timeline_item_index` is untouched
1482                ("$ev3", Some(1)),
1483            ]
1484        );
1485    }
1486
1487    #[test]
1488    fn test_insert() {
1489        let mut events = AllRemoteEvents::default();
1490
1491        // Insert on an empty set, nothing particular.
1492        events.insert(0, event_meta("$ev0", Some(0)));
1493
1494        // Insert at the end with no `timeline_item_index`.
1495        events.insert(1, event_meta("$ev1", None));
1496
1497        // Insert at the end with a `timeline_item_index`.
1498        events.insert(2, event_meta("$ev2", Some(1)));
1499
1500        // Insert at the start, with a `timeline_item_index`.
1501        events.insert(0, event_meta("$ev3", Some(0)));
1502
1503        assert_events!(
1504            events,
1505            [
1506                // `timeline_item_index` is untouched
1507                ("$ev3", Some(0)),
1508                // `timeline_item_index` has been shifted once
1509                ("$ev0", Some(1)),
1510                // no `timeline_item_index`
1511                ("$ev1", None),
1512                // `timeline_item_index` has been shifted once
1513                ("$ev2", Some(2)),
1514            ]
1515        );
1516    }
1517
1518    #[test]
1519    fn test_remove() {
1520        let mut events = AllRemoteEvents::default();
1521
1522        // Push some events.
1523        events.push_back(event_meta("$ev0", Some(0)));
1524        events.push_back(event_meta("$ev1", Some(1)));
1525        events.push_back(event_meta("$ev2", None));
1526        events.push_back(event_meta("$ev3", Some(2)));
1527
1528        // Assert initial state.
1529        assert_events!(
1530            events,
1531            [("$ev0", Some(0)), ("$ev1", Some(1)), ("$ev2", None), ("$ev3", Some(2))]
1532        );
1533
1534        // Remove two events.
1535        events.remove(2); // $ev2 has no `timeline_item_index`
1536        events.remove(1); // $ev1 has a `timeline_item_index`
1537
1538        assert_events!(
1539            events,
1540            [
1541                ("$ev0", Some(0)),
1542                // `timeline_item_index` has shifted once
1543                ("$ev3", Some(1)),
1544            ]
1545        );
1546    }
1547
1548    #[test]
1549    fn test_last() {
1550        let mut events = AllRemoteEvents::default();
1551
1552        assert!(events.last().is_none());
1553        assert!(events.last_index().is_none());
1554
1555        // Push some events.
1556        events.push_back(event_meta("$ev0", Some(0)));
1557        events.push_back(event_meta("$ev1", Some(1)));
1558
1559        assert_matches!(events.last(), Some(EventMeta { event_id, .. }) => {
1560            assert_eq!(event_id.as_str(), "$ev1");
1561        });
1562        assert_eq!(events.last_index(), Some(1));
1563    }
1564
1565    #[test]
1566    fn test_get_by_event_by_mut() {
1567        let mut events = AllRemoteEvents::default();
1568
1569        // Push some events.
1570        events.push_back(event_meta("$ev0", Some(0)));
1571        events.push_back(event_meta("$ev1", Some(1)));
1572
1573        assert!(events.get_by_event_id_mut(event_id!("$ev0")).is_some());
1574        assert!(events.get_by_event_id_mut(event_id!("$ev42")).is_none());
1575    }
1576
1577    #[test]
1578    fn test_timeline_item_has_been_inserted_at() {
1579        let mut events = AllRemoteEvents::default();
1580
1581        // Push some events.
1582        events.push_back(event_meta("$ev0", Some(0)));
1583        events.push_back(event_meta("$ev1", Some(1)));
1584        events.push_back(event_meta("$ev2", None));
1585        events.push_back(event_meta("$ev3", None));
1586        events.push_back(event_meta("$ev4", Some(2)));
1587        events.push_back(event_meta("$ev5", Some(3)));
1588        events.push_back(event_meta("$ev6", None));
1589
1590        // A timeline item has been inserted at index 2, and maps to no event.
1591        events.timeline_item_has_been_inserted_at(2, None);
1592
1593        assert_events!(
1594            events,
1595            [
1596                ("$ev0", Some(0)),
1597                ("$ev1", Some(1)),
1598                ("$ev2", None),
1599                ("$ev3", None),
1600                // `timeline_item_index` is shifted once
1601                ("$ev4", Some(3)),
1602                // `timeline_item_index` is shifted once
1603                ("$ev5", Some(4)),
1604                ("$ev6", None),
1605            ]
1606        );
1607
1608        // A timeline item has been inserted at the back, and maps to `$ev6`.
1609        events.timeline_item_has_been_inserted_at(5, Some(6));
1610
1611        assert_events!(
1612            events,
1613            [
1614                ("$ev0", Some(0)),
1615                ("$ev1", Some(1)),
1616                ("$ev2", None),
1617                ("$ev3", None),
1618                ("$ev4", Some(3)),
1619                ("$ev5", Some(4)),
1620                // `timeline_item_index` has been updated
1621                ("$ev6", Some(5)),
1622            ]
1623        );
1624    }
1625
1626    #[test]
1627    fn test_timeline_item_has_been_removed_at() {
1628        let mut events = AllRemoteEvents::default();
1629
1630        // Push some events.
1631        events.push_back(event_meta("$ev0", Some(0)));
1632        events.push_back(event_meta("$ev1", Some(1)));
1633        events.push_back(event_meta("$ev2", None));
1634        events.push_back(event_meta("$ev3", None));
1635        events.push_back(event_meta("$ev4", Some(3)));
1636        events.push_back(event_meta("$ev5", Some(4)));
1637        events.push_back(event_meta("$ev6", None));
1638
1639        // A timeline item has been removed at index 2, which maps to no event.
1640        events.timeline_item_has_been_removed_at(2);
1641
1642        assert_events!(
1643            events,
1644            [
1645                ("$ev0", Some(0)),
1646                ("$ev1", Some(1)),
1647                ("$ev2", None),
1648                ("$ev3", None),
1649                // `timeline_item_index` is shifted once
1650                ("$ev4", Some(2)),
1651                // `timeline_item_index` is shifted once
1652                ("$ev5", Some(3)),
1653                ("$ev6", None),
1654            ]
1655        );
1656
1657        // A timeline item has been removed at index 2, which maps to `$ev4`.
1658        events.timeline_item_has_been_removed_at(2);
1659
1660        assert_events!(
1661            events,
1662            [
1663                ("$ev0", Some(0)),
1664                ("$ev1", Some(1)),
1665                ("$ev2", None),
1666                ("$ev3", None),
1667                // `timeline_item_index` has been updated
1668                ("$ev4", None),
1669                // `timeline_item_index` has shifted once
1670                ("$ev5", Some(2)),
1671                ("$ev6", None),
1672            ]
1673        );
1674
1675        // A timeline item has been removed at index 0, which maps to `$ev0`.
1676        events.timeline_item_has_been_removed_at(0);
1677
1678        assert_events!(
1679            events,
1680            [
1681                // `timeline_item_index` has been updated
1682                ("$ev0", None),
1683                // `timeline_item_index` has shifted once
1684                ("$ev1", Some(0)),
1685                ("$ev2", None),
1686                ("$ev3", None),
1687                ("$ev4", None),
1688                // `timeline_item_index` has shifted once
1689                ("$ev5", Some(1)),
1690                ("$ev6", None),
1691            ]
1692        );
1693    }
1694}