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, MsgLikeContent, MsgLikeKind, TimelineDetails,
393        TimelineItemContent, TimelineUniqueId,
394    };
395
396    fn item(event_id: &str) -> Arc<TimelineItem> {
397        TimelineItem::new(
398            EventTimelineItem::new(
399                owned_user_id!("@ivan:mnt.io"),
400                TimelineDetails::Unavailable,
401                MilliSecondsSinceUnixEpoch(0u32.into()),
402                TimelineItemContent::MsgLike(MsgLikeContent {
403                    kind: MsgLikeKind::Message(Message {
404                        msgtype: MessageType::Text(TextMessageEventContent::plain("hello")),
405                        edited: false,
406                        mentions: None,
407                    }),
408                    reactions: Default::default(),
409                    thread_root: None,
410                    in_reply_to: None,
411                }),
412                EventTimelineItemKind::Remote(RemoteEventTimelineItem {
413                    event_id: event_id.parse().unwrap(),
414                    transaction_id: None,
415                    read_receipts: Default::default(),
416                    is_own: false,
417                    is_highlighted: false,
418                    encryption_info: None,
419                    original_json: None,
420                    latest_edit_json: None,
421                    origin: RemoteEventOrigin::Sync,
422                }),
423                false,
424            ),
425            TimelineUniqueId(format!("__id_{event_id}")),
426        )
427    }
428
429    fn read_marker() -> Arc<TimelineItem> {
430        TimelineItem::read_marker()
431    }
432
433    fn event_meta(event_id: &str) -> EventMeta {
434        EventMeta { event_id: event_id.parse().unwrap(), timeline_item_index: None, visible: false }
435    }
436
437    macro_rules! assert_event_id {
438        ( $timeline_item:expr, $event_id:literal $( , $message:expr )? $(,)? ) => {
439            assert_eq!($timeline_item.as_event().unwrap().event_id().unwrap().as_str(), $event_id $( , $message)? );
440        };
441    }
442
443    macro_rules! assert_mapping {
444        ( on $transaction:ident:
445          | event_id | event_index | timeline_item_index |
446          | $( - )+ | $( - )+ | $( - )+ |
447          $(
448            | $event_id:literal | $event_index:literal | $( $timeline_item_index:literal )? |
449          )+
450        ) => {
451            let all_remote_events = $transaction .all_remote_events();
452
453            $(
454                // Remote event exists at this index…
455                assert_matches!(all_remote_events.0.get( $event_index ), Some(EventMeta { event_id, timeline_item_index, .. }) => {
456                    // … this is the remote event with the expected event ID
457                    assert_eq!(
458                        event_id.as_str(),
459                        $event_id ,
460                        concat!("event #", $event_index, " should have ID ", $event_id)
461                    );
462
463
464                    // (tiny hack to handle the case where `$timeline_item_index` is absent)
465                    #[allow(unused_variables)]
466                    let timeline_item_index_is_expected = false;
467                    $(
468                        let timeline_item_index_is_expected = true;
469                        let _ = $timeline_item_index;
470                    )?
471
472                    if timeline_item_index_is_expected.not() {
473                        // … this remote event does NOT map to a timeline item index
474                        assert!(
475                            timeline_item_index.is_none(),
476                            concat!("event #", $event_index, " with ID ", $event_id, " should NOT map to a timeline item index" )
477                        );
478                    }
479
480                    $(
481                        // … this remote event maps to a timeline item index
482                        assert_eq!(
483                            *timeline_item_index,
484                            Some( $timeline_item_index ),
485                            concat!("event #", $event_index, " with ID ", $event_id, " should map to timeline item #", $timeline_item_index )
486                        );
487
488                        // … this timeline index exists
489                        assert_matches!( $transaction .get( $timeline_item_index ), Some(timeline_item) => {
490                            // … this timelime item has the expected event ID
491                            assert_event_id!(
492                                timeline_item,
493                                $event_id ,
494                                concat!("timeline item #", $timeline_item_index, " should map to event ID ", $event_id )
495                            );
496                        });
497                    )?
498                });
499            )*
500        }
501    }
502
503    #[test]
504    fn test_is_empty() {
505        let mut items = ObservableItems::new();
506
507        assert!(items.is_empty());
508
509        // Push one event to check if `is_empty` returns false.
510        let mut transaction = items.transaction();
511        transaction.push_back(item("$ev0"), Some(0));
512        transaction.commit();
513
514        assert!(items.is_empty().not());
515    }
516
517    #[test]
518    fn test_subscribe() {
519        let mut items = ObservableItems::new();
520        let mut subscriber = items.subscribe().into_stream();
521
522        // Push one event to check the subscriber is emitting something.
523        let mut transaction = items.transaction();
524        transaction.push_back(item("$ev0"), Some(0));
525        transaction.commit();
526
527        // It does!
528        assert_next_matches!(subscriber, VectorDiff::PushBack { value: event } => {
529            assert_event_id!(event, "$ev0");
530        });
531    }
532
533    #[test]
534    fn test_clone_items() {
535        let mut items = ObservableItems::new();
536
537        let mut transaction = items.transaction();
538        transaction.push_back(item("$ev0"), Some(0));
539        transaction.push_back(item("$ev1"), Some(1));
540        transaction.commit();
541
542        let items = items.clone_items();
543        assert_eq!(items.len(), 2);
544        assert_event_id!(items[0], "$ev0");
545        assert_event_id!(items[1], "$ev1");
546    }
547
548    #[test]
549    fn test_replace() {
550        let mut items = ObservableItems::new();
551
552        // Push one event that will be replaced.
553        let mut transaction = items.transaction();
554        transaction.push_back(item("$ev0"), Some(0));
555        transaction.commit();
556
557        // That's time to replace it!
558        items.replace(0, item("$ev1"));
559
560        let items = items.clone_items();
561        assert_eq!(items.len(), 1);
562        assert_event_id!(items[0], "$ev1");
563    }
564
565    #[test]
566    fn test_entries() {
567        let mut items = ObservableItems::new();
568
569        // Push events to iterate on.
570        let mut transaction = items.transaction();
571        transaction.push_back(item("$ev0"), Some(0));
572        transaction.push_back(item("$ev1"), Some(1));
573        transaction.push_back(item("$ev2"), Some(2));
574        transaction.commit();
575
576        let mut entries = items.entries();
577
578        assert_matches!(entries.next(), Some(entry) => {
579            assert_event_id!(entry, "$ev0");
580        });
581        assert_matches!(entries.next(), Some(entry) => {
582            assert_event_id!(entry, "$ev1");
583        });
584        assert_matches!(entries.next(), Some(entry) => {
585            assert_event_id!(entry, "$ev2");
586        });
587        assert_matches!(entries.next(), None);
588    }
589
590    #[test]
591    fn test_entry_replace() {
592        let mut items = ObservableItems::new();
593
594        // Push events to iterate on.
595        let mut transaction = items.transaction();
596        transaction.push_back(item("$ev0"), Some(0));
597        transaction.commit();
598
599        let mut entries = items.entries();
600
601        // Replace one event by another one.
602        assert_matches!(entries.next(), Some(mut entry) => {
603            assert_event_id!(entry, "$ev0");
604            ObservableItemsEntry::replace(&mut entry, item("$ev1"));
605        });
606        assert_matches!(entries.next(), None);
607
608        // Check the new event.
609        let mut entries = items.entries();
610
611        assert_matches!(entries.next(), Some(entry) => {
612            assert_event_id!(entry, "$ev1");
613        });
614        assert_matches!(entries.next(), None);
615    }
616
617    #[test]
618    fn test_for_each() {
619        let mut items = ObservableItems::new();
620
621        // Push events to iterate on.
622        let mut transaction = items.transaction();
623        transaction.push_back(item("$ev0"), Some(0));
624        transaction.push_back(item("$ev1"), Some(1));
625        transaction.push_back(item("$ev2"), Some(2));
626        transaction.commit();
627
628        let mut nth = 0;
629
630        // Iterate over events.
631        items.for_each(|entry| {
632            match nth {
633                0 => {
634                    assert_event_id!(entry, "$ev0");
635                }
636                1 => {
637                    assert_event_id!(entry, "$ev1");
638                }
639                2 => {
640                    assert_event_id!(entry, "$ev2");
641                }
642                _ => unreachable!(),
643            }
644
645            nth += 1;
646        });
647    }
648
649    #[test]
650    fn test_transaction_commit() {
651        let mut items = ObservableItems::new();
652
653        // Don't commit the transaction.
654        let mut transaction = items.transaction();
655        transaction.push_back(item("$ev0"), Some(0));
656        drop(transaction);
657
658        assert!(items.is_empty());
659
660        // Commit the transaction.
661        let mut transaction = items.transaction();
662        transaction.push_back(item("$ev0"), Some(0));
663        transaction.commit();
664
665        assert!(items.is_empty().not());
666    }
667
668    #[test]
669    fn test_transaction_get() {
670        let mut items = ObservableItems::new();
671
672        let mut transaction = items.transaction();
673        transaction.push_back(item("$ev0"), Some(0));
674
675        assert_matches!(transaction.get(0), Some(event) => {
676            assert_event_id!(event, "$ev0");
677        });
678    }
679
680    #[test]
681    fn test_transaction_replace() {
682        let mut items = ObservableItems::new();
683
684        let mut transaction = items.transaction();
685        transaction.push_back(item("$ev0"), Some(0));
686        transaction.replace(0, item("$ev1"));
687
688        assert_matches!(transaction.get(0), Some(event) => {
689            assert_event_id!(event, "$ev1");
690        });
691    }
692
693    #[test]
694    fn test_transaction_insert() {
695        let mut items = ObservableItems::new();
696
697        let mut transaction = items.transaction();
698
699        // Remote event with its timeline item.
700        transaction.push_back_remote_event(event_meta("$ev0"));
701        transaction.insert(0, item("$ev0"), Some(0));
702
703        assert_mapping! {
704            on transaction:
705
706            | event_id | event_index | timeline_item_index |
707            |----------|-------------|---------------------|
708            | "$ev0"   | 0           | 0                   | // new
709        }
710
711        // Timeline item without a remote event (for example a read marker).
712        transaction.insert(0, read_marker(), None);
713
714        assert_mapping! {
715            on transaction:
716
717            | event_id | event_index | timeline_item_index |
718            |----------|-------------|---------------------|
719            | "$ev0"   | 0           | 1                   | // has shifted
720        }
721
722        // Remote event with its timeline item.
723        transaction.push_back_remote_event(event_meta("$ev1"));
724        transaction.insert(2, item("$ev1"), Some(1));
725
726        assert_mapping! {
727            on transaction:
728
729            | event_id | event_index | timeline_item_index |
730            |----------|-------------|---------------------|
731            | "$ev0"   | 0           | 1                   |
732            | "$ev1"   | 1           | 2                   | // new
733        }
734
735        // Remote event without a timeline item (for example a state event).
736        transaction.push_back_remote_event(event_meta("$ev2"));
737
738        assert_mapping! {
739            on transaction:
740
741            | event_id | event_index | timeline_item_index |
742            |----------|-------------|---------------------|
743            | "$ev0"   | 0           | 1                   |
744            | "$ev1"   | 1           | 2                   |
745            | "$ev2"   | 2           |                     | // new
746        }
747
748        // Remote event with its timeline item.
749        transaction.push_back_remote_event(event_meta("$ev3"));
750        transaction.insert(3, item("$ev3"), Some(3));
751
752        assert_mapping! {
753            on transaction:
754
755            | event_id | event_index | timeline_item_index |
756            |----------|-------------|---------------------|
757            | "$ev0"   | 0           | 1                   |
758            | "$ev1"   | 1           | 2                   |
759            | "$ev2"   | 2           |                     |
760            | "$ev3"   | 3           | 3                   | // new
761        }
762
763        // Timeline item with a remote event, but late.
764        // I don't know if this case is possible in reality, but let's be robust.
765        transaction.insert(3, item("$ev2"), Some(2));
766
767        assert_mapping! {
768            on transaction:
769
770            | event_id | event_index | timeline_item_index |
771            |----------|-------------|---------------------|
772            | "$ev0"   | 0           | 1                   |
773            | "$ev1"   | 1           | 2                   |
774            | "$ev2"   | 2           | 3                   | // updated
775            | "$ev3"   | 3           | 4                   | // has shifted
776        }
777
778        // Let's move the read marker for the fun.
779        transaction.remove(0);
780        transaction.insert(2, read_marker(), None);
781
782        assert_mapping! {
783            on transaction:
784
785            | event_id | event_index | timeline_item_index |
786            |----------|-------------|---------------------|
787            | "$ev0"   | 0           | 0                   | // has shifted
788            | "$ev1"   | 1           | 1                   | // has shifted
789            | "$ev2"   | 2           | 3                   |
790            | "$ev3"   | 3           | 4                   |
791        }
792
793        assert_eq!(transaction.len(), 5);
794    }
795
796    #[test]
797    fn test_transaction_push_front() {
798        let mut items = ObservableItems::new();
799
800        let mut transaction = items.transaction();
801
802        // Remote event with its timeline item.
803        transaction.push_front_remote_event(event_meta("$ev0"));
804        transaction.push_front(item("$ev0"), Some(0));
805
806        assert_mapping! {
807            on transaction:
808
809            | event_id | event_index | timeline_item_index |
810            |----------|-------------|---------------------|
811            | "$ev0"   | 0           | 0                   | // new
812        }
813
814        // Timeline item without a remote event (for example a read marker).
815        transaction.push_front(read_marker(), None);
816
817        assert_mapping! {
818            on transaction:
819
820            | event_id | event_index | timeline_item_index |
821            |----------|-------------|---------------------|
822            | "$ev0"   | 0           | 1                   | // has shifted
823        }
824
825        // Remote event with its timeline item.
826        transaction.push_front_remote_event(event_meta("$ev1"));
827        transaction.push_front(item("$ev1"), Some(0));
828
829        assert_mapping! {
830            on transaction:
831
832            | event_id | event_index | timeline_item_index |
833            |----------|-------------|---------------------|
834            | "$ev1"   | 0           | 0                   | // new
835            | "$ev0"   | 1           | 2                   | // has shifted
836        }
837
838        // Remote event without a timeline item (for example a state event).
839        transaction.push_front_remote_event(event_meta("$ev2"));
840
841        assert_mapping! {
842            on transaction:
843
844            | event_id | event_index | timeline_item_index |
845            |----------|-------------|---------------------|
846            | "$ev2"   | 0           |                     |
847            | "$ev1"   | 1           | 0                   | // has shifted
848            | "$ev0"   | 2           | 2                   | // has shifted
849        }
850
851        // Remote event with its timeline item.
852        transaction.push_front_remote_event(event_meta("$ev3"));
853        transaction.push_front(item("$ev3"), Some(0));
854
855        assert_mapping! {
856            on transaction:
857
858            | event_id | event_index | timeline_item_index |
859            |----------|-------------|---------------------|
860            | "$ev3"   | 0           | 0                   | // new
861            | "$ev2"   | 1           |                     |
862            | "$ev1"   | 2           | 1                   | // has shifted
863            | "$ev0"   | 3           | 3                   | // has shifted
864        }
865
866        assert_eq!(transaction.len(), 4);
867    }
868
869    #[test]
870    fn test_transaction_push_back() {
871        let mut items = ObservableItems::new();
872
873        let mut transaction = items.transaction();
874
875        // Remote event with its timeline item.
876        transaction.push_back_remote_event(event_meta("$ev0"));
877        transaction.push_back(item("$ev0"), Some(0));
878
879        assert_mapping! {
880            on transaction:
881
882            | event_id | event_index | timeline_item_index |
883            |----------|-------------|---------------------|
884            | "$ev0"   | 0           | 0                   | // new
885        }
886
887        // Timeline item without a remote event (for example a read marker).
888        transaction.push_back(read_marker(), None);
889
890        assert_mapping! {
891            on transaction:
892
893            | event_id | event_index | timeline_item_index |
894            |----------|-------------|---------------------|
895            | "$ev0"   | 0           | 0                   |
896        }
897
898        // Remote event with its timeline item.
899        transaction.push_back_remote_event(event_meta("$ev1"));
900        transaction.push_back(item("$ev1"), Some(1));
901
902        assert_mapping! {
903            on transaction:
904
905            | event_id | event_index | timeline_item_index |
906            |----------|-------------|---------------------|
907            | "$ev0"   | 0           | 0                   |
908            | "$ev1"   | 1           | 2                   | // new
909        }
910
911        // Remote event without a timeline item (for example a state event).
912        transaction.push_back_remote_event(event_meta("$ev2"));
913
914        assert_mapping! {
915            on transaction:
916
917            | event_id | event_index | timeline_item_index |
918            |----------|-------------|---------------------|
919            | "$ev0"   | 0           | 0                   |
920            | "$ev1"   | 1           | 2                   |
921            | "$ev2"   | 2           |                     | // new
922        }
923
924        // Remote event with its timeline item.
925        transaction.push_back_remote_event(event_meta("$ev3"));
926        transaction.push_back(item("$ev3"), Some(3));
927
928        assert_mapping! {
929            on transaction:
930
931            | event_id | event_index | timeline_item_index |
932            |----------|-------------|---------------------|
933            | "$ev0"   | 0           | 0                   |
934            | "$ev1"   | 1           | 2                   |
935            | "$ev2"   | 2           |                     |
936            | "$ev3"   | 3           | 3                   | // new
937        }
938
939        assert_eq!(transaction.len(), 4);
940    }
941
942    #[test]
943    fn test_transaction_remove() {
944        let mut items = ObservableItems::new();
945
946        let mut transaction = items.transaction();
947
948        // Remote event with its timeline item.
949        transaction.push_back_remote_event(event_meta("$ev0"));
950        transaction.push_back(item("$ev0"), Some(0));
951
952        // Timeline item without a remote event (for example a read marker).
953        transaction.push_back(read_marker(), None);
954
955        // Remote event with its timeline item.
956        transaction.push_back_remote_event(event_meta("$ev1"));
957        transaction.push_back(item("$ev1"), Some(1));
958
959        // Remote event without a timeline item (for example a state event).
960        transaction.push_back_remote_event(event_meta("$ev2"));
961
962        // Remote event with its timeline item.
963        transaction.push_back_remote_event(event_meta("$ev3"));
964        transaction.push_back(item("$ev3"), Some(3));
965
966        assert_mapping! {
967            on transaction:
968
969            | event_id | event_index | timeline_item_index |
970            |----------|-------------|---------------------|
971            | "$ev0"   | 0           | 0                   |
972            | "$ev1"   | 1           | 2                   |
973            | "$ev2"   | 2           |                     |
974            | "$ev3"   | 3           | 3                   |
975        }
976
977        // Remove the timeline item that has no event.
978        transaction.remove(1);
979
980        assert_mapping! {
981            on transaction:
982
983            | event_id | event_index | timeline_item_index |
984            |----------|-------------|---------------------|
985            | "$ev0"   | 0           | 0                   |
986            | "$ev1"   | 1           | 1                   | // has shifted
987            | "$ev2"   | 2           |                     |
988            | "$ev3"   | 3           | 2                   | // has shifted
989        }
990
991        // Remove an timeline item that has an event.
992        transaction.remove(1);
993
994        assert_mapping! {
995            on transaction:
996
997            | event_id | event_index | timeline_item_index |
998            |----------|-------------|---------------------|
999            | "$ev0"   | 0           | 0                   |
1000            | "$ev1"   | 1           |                     | // has been removed
1001            | "$ev2"   | 2           |                     |
1002            | "$ev3"   | 3           | 1                   | // has shifted
1003        }
1004
1005        // Remove the last timeline item to test off by 1 error.
1006        transaction.remove(1);
1007
1008        assert_mapping! {
1009            on transaction:
1010
1011            | event_id | event_index | timeline_item_index |
1012            |----------|-------------|---------------------|
1013            | "$ev0"   | 0           | 0                   |
1014            | "$ev1"   | 1           |                     |
1015            | "$ev2"   | 2           |                     |
1016            | "$ev3"   | 3           |                     | // has been removed
1017        }
1018
1019        // Remove all the items \o/
1020        transaction.remove(0);
1021
1022        assert_mapping! {
1023            on transaction:
1024
1025            | event_id | event_index | timeline_item_index |
1026            |----------|-------------|---------------------|
1027            | "$ev0"   | 0           |                     | // has been removed
1028            | "$ev1"   | 1           |                     |
1029            | "$ev2"   | 2           |                     |
1030            | "$ev3"   | 3           |                     |
1031        }
1032
1033        assert!(transaction.is_empty());
1034    }
1035
1036    #[test]
1037    fn test_transaction_clear() {
1038        let mut items = ObservableItems::new();
1039
1040        let mut transaction = items.transaction();
1041
1042        // Remote event with its timeline item.
1043        transaction.push_back_remote_event(event_meta("$ev0"));
1044        transaction.push_back(item("$ev0"), Some(0));
1045
1046        // Timeline item without a remote event (for example a read marker).
1047        transaction.push_back(read_marker(), None);
1048
1049        // Remote event with its timeline item.
1050        transaction.push_back_remote_event(event_meta("$ev1"));
1051        transaction.push_back(item("$ev1"), Some(1));
1052
1053        // Remote event without a timeline item (for example a state event).
1054        transaction.push_back_remote_event(event_meta("$ev2"));
1055
1056        // Remote event with its timeline item.
1057        transaction.push_back_remote_event(event_meta("$ev3"));
1058        transaction.push_back(item("$ev3"), Some(3));
1059
1060        assert_mapping! {
1061            on transaction:
1062
1063            | event_id | event_index | timeline_item_index |
1064            |----------|-------------|---------------------|
1065            | "$ev0"   | 0           | 0                   |
1066            | "$ev1"   | 1           | 2                   |
1067            | "$ev2"   | 2           |                     |
1068            | "$ev3"   | 3           | 3                   |
1069        }
1070
1071        assert_eq!(transaction.all_remote_events().0.len(), 4);
1072        assert_eq!(transaction.len(), 4);
1073
1074        // Let's clear everything.
1075        transaction.clear();
1076
1077        assert!(transaction.all_remote_events().0.is_empty());
1078        assert!(transaction.is_empty());
1079    }
1080
1081    #[test]
1082    fn test_transaction_for_each() {
1083        let mut items = ObservableItems::new();
1084
1085        // Push events to iterate on.
1086        let mut transaction = items.transaction();
1087        transaction.push_back(item("$ev0"), Some(0));
1088        transaction.push_back(item("$ev1"), Some(1));
1089        transaction.push_back(item("$ev2"), Some(2));
1090
1091        let mut nth = 0;
1092
1093        // Iterate over events.
1094        transaction.for_each(|entry| {
1095            match nth {
1096                0 => {
1097                    assert_event_id!(entry, "$ev0");
1098                }
1099                1 => {
1100                    assert_event_id!(entry, "$ev1");
1101                }
1102                2 => {
1103                    assert_event_id!(entry, "$ev2");
1104                }
1105                _ => unreachable!(),
1106            }
1107
1108            nth += 1;
1109        });
1110    }
1111
1112    #[test]
1113    fn test_transaction_for_each_remove() {
1114        let mut items = ObservableItems::new();
1115
1116        // Push events to iterate on.
1117        let mut transaction = items.transaction();
1118
1119        transaction.push_back_remote_event(event_meta("$ev0"));
1120        transaction.push_back(item("$ev0"), Some(0));
1121
1122        transaction.push_back_remote_event(event_meta("$ev1"));
1123        transaction.push_back(item("$ev1"), Some(1));
1124
1125        transaction.push_back_remote_event(event_meta("$ev2"));
1126        transaction.push_back(item("$ev2"), Some(2));
1127
1128        assert_mapping! {
1129            on transaction:
1130
1131            | event_id | event_index | timeline_item_index |
1132            |----------|-------------|---------------------|
1133            | "$ev0"   | 0           | 0                   |
1134            | "$ev1"   | 1           | 1                   |
1135            | "$ev2"   | 2           | 2                   |
1136        }
1137
1138        // Iterate over events, and remove one.
1139        transaction.for_each(|entry| {
1140            if entry.as_event().unwrap().event_id().unwrap().as_str() == "$ev1" {
1141                ObservableItemsTransactionEntry::remove(entry);
1142            }
1143        });
1144
1145        assert_mapping! {
1146            on transaction:
1147
1148            | event_id | event_index | timeline_item_index |
1149            |----------|-------------|---------------------|
1150            | "$ev0"   | 0           | 0                   |
1151            | "$ev2"   | 2           | 1                   | // has shifted
1152        }
1153
1154        assert_eq!(transaction.all_remote_events().0.len(), 3);
1155        assert_eq!(transaction.len(), 2);
1156    }
1157}
1158
1159/// A type for all remote events.
1160///
1161/// Having this type helps to know exactly which parts of the code and how they
1162/// use all remote events. It also helps to give a bit of semantics on top of
1163/// them.
1164#[derive(Clone, Debug, Default)]
1165pub struct AllRemoteEvents(VecDeque<EventMeta>);
1166
1167impl AllRemoteEvents {
1168    /// Return a reference to a remote event.
1169    pub fn get(&self, event_index: usize) -> Option<&EventMeta> {
1170        self.0.get(event_index)
1171    }
1172
1173    /// Return a front-to-back iterator over all remote events.
1174    pub fn iter(&self) -> Iter<'_, EventMeta> {
1175        self.0.iter()
1176    }
1177
1178    /// Return a front-to-back iterator covering ranges of all remote events
1179    /// described by `range`.
1180    pub fn range<R>(&self, range: R) -> Iter<'_, EventMeta>
1181    where
1182        R: RangeBounds<usize>,
1183    {
1184        self.0.range(range)
1185    }
1186
1187    /// Remove all remote events.
1188    fn clear(&mut self) {
1189        self.0.clear();
1190    }
1191
1192    /// Insert a new remote event at the front of all the others.
1193    fn push_front(&mut self, event_meta: EventMeta) {
1194        // If there is an associated `timeline_item_index`, shift all the
1195        // `timeline_item_index` that come after this one.
1196        if let Some(new_timeline_item_index) = event_meta.timeline_item_index {
1197            self.increment_all_timeline_item_index_after(new_timeline_item_index);
1198        }
1199
1200        // Push the event.
1201        self.0.push_front(event_meta)
1202    }
1203
1204    /// Insert a new remote event at the back of all the others.
1205    fn push_back(&mut self, event_meta: EventMeta) {
1206        // If there is an associated `timeline_item_index`, shift all the
1207        // `timeline_item_index` that come after this one.
1208        if let Some(new_timeline_item_index) = event_meta.timeline_item_index {
1209            self.increment_all_timeline_item_index_after(new_timeline_item_index);
1210        }
1211
1212        // Push the event.
1213        self.0.push_back(event_meta)
1214    }
1215
1216    /// Insert a new remote event at a specific index.
1217    fn insert(&mut self, event_index: usize, event_meta: EventMeta) {
1218        // If there is an associated `timeline_item_index`, shift all the
1219        // `timeline_item_index` that come after this one.
1220        if let Some(new_timeline_item_index) = event_meta.timeline_item_index {
1221            self.increment_all_timeline_item_index_after(new_timeline_item_index);
1222        }
1223
1224        // Insert the event.
1225        self.0.insert(event_index, event_meta)
1226    }
1227
1228    /// Remove one remote event at a specific index, and return it if it exists.
1229    fn remove(&mut self, event_index: usize) -> Option<EventMeta> {
1230        // Remove the event.
1231        let event_meta = self.0.remove(event_index)?;
1232
1233        // If there is an associated `timeline_item_index`, shift all the
1234        // `timeline_item_index` that come after this one.
1235        if let Some(removed_timeline_item_index) = event_meta.timeline_item_index {
1236            self.decrement_all_timeline_item_index_after(removed_timeline_item_index);
1237        };
1238
1239        Some(event_meta)
1240    }
1241
1242    /// Return a reference to the last remote event if it exists.
1243    pub fn last(&self) -> Option<&EventMeta> {
1244        self.0.back()
1245    }
1246
1247    /// Return the index of the last remote event if it exists.
1248    pub fn last_index(&self) -> Option<usize> {
1249        self.0.len().checked_sub(1)
1250    }
1251
1252    /// Get a mutable reference to a specific remote event by its ID.
1253    pub fn get_by_event_id_mut(&mut self, event_id: &EventId) -> Option<&mut EventMeta> {
1254        self.0.iter_mut().rev().find(|event_meta| event_meta.event_id == event_id)
1255    }
1256
1257    /// Get an immutable reference to a specific remote event by its ID.
1258    pub fn get_by_event_id(&self, event_id: &EventId) -> Option<&EventMeta> {
1259        self.0.iter().rev().find(|event_meta| event_meta.event_id == event_id)
1260    }
1261
1262    /// Shift to the right all timeline item indexes that are equal to or
1263    /// greater than `new_timeline_item_index`.
1264    fn increment_all_timeline_item_index_after(&mut self, new_timeline_item_index: usize) {
1265        // Traverse items from back to front because:
1266        // - if `new_timeline_item_index` is 0, we need to shift all items anyways, so
1267        //   all items must be traversed,
1268        // - otherwise, it's unlikely we want to traverse all items: the item has been
1269        //   either inserted or pushed back, so there is no need to traverse the first
1270        //   items; we can also break the iteration as soon as all timeline item index
1271        //   after `new_timeline_item_index` has been updated.
1272        for event_meta in self.0.iter_mut().rev() {
1273            if let Some(timeline_item_index) = event_meta.timeline_item_index.as_mut() {
1274                if *timeline_item_index >= new_timeline_item_index {
1275                    *timeline_item_index += 1;
1276                } else {
1277                    // Items are ordered.
1278                    break;
1279                }
1280            }
1281        }
1282    }
1283
1284    /// Shift to the left all timeline item indexes that are greater than
1285    /// `removed_wtimeline_item_index`.
1286    fn decrement_all_timeline_item_index_after(&mut self, removed_timeline_item_index: usize) {
1287        // Traverse items from back to front because:
1288        // - if `new_timeline_item_index` is 0, we need to shift all items anyways, so
1289        //   all items must be traversed,
1290        // - otherwise, it's unlikely we want to traverse all items: the item has been
1291        //   either inserted or pushed back, so there is no need to traverse the first
1292        //   items; we can also break the iteration as soon as all timeline item index
1293        //   after `new_timeline_item_index` has been updated.
1294        for event_meta in self.0.iter_mut().rev() {
1295            if let Some(timeline_item_index) = event_meta.timeline_item_index.as_mut() {
1296                if *timeline_item_index > removed_timeline_item_index {
1297                    *timeline_item_index -= 1;
1298                } else {
1299                    // Items are ordered.
1300                    break;
1301                }
1302            }
1303        }
1304    }
1305
1306    /// Notify that a timeline item has been inserted at
1307    /// `new_timeline_item_index`. If `event_index` is `Some(_)`, it means the
1308    /// remote event at `event_index` must be mapped to
1309    /// `new_timeline_item_index`.
1310    fn timeline_item_has_been_inserted_at(
1311        &mut self,
1312        new_timeline_item_index: usize,
1313        event_index: Option<usize>,
1314    ) {
1315        self.increment_all_timeline_item_index_after(new_timeline_item_index);
1316
1317        if let Some(event_index) = event_index {
1318            if let Some(event_meta) = self.0.get_mut(event_index) {
1319                event_meta.timeline_item_index = Some(new_timeline_item_index);
1320            }
1321        }
1322    }
1323
1324    /// Notify that a timeline item has been removed at
1325    /// `new_timeline_item_index`.
1326    fn timeline_item_has_been_removed_at(&mut self, timeline_item_index_to_remove: usize) {
1327        for event_meta in self.0.iter_mut() {
1328            let mut remove_timeline_item_index = false;
1329
1330            // A `timeline_item_index` is removed. Let's shift all indexes that come
1331            // after the removed one.
1332            if let Some(timeline_item_index) = event_meta.timeline_item_index.as_mut() {
1333                match (*timeline_item_index).cmp(&timeline_item_index_to_remove) {
1334                    Ordering::Equal => {
1335                        remove_timeline_item_index = true;
1336                    }
1337
1338                    Ordering::Greater => {
1339                        *timeline_item_index -= 1;
1340                    }
1341
1342                    Ordering::Less => {}
1343                }
1344            }
1345
1346            // This is the `event_meta` that holds the `timeline_item_index` that is being
1347            // removed. So let's clean it.
1348            if remove_timeline_item_index {
1349                event_meta.timeline_item_index = None;
1350            }
1351        }
1352    }
1353}
1354
1355#[cfg(test)]
1356mod all_remote_events_tests {
1357    use assert_matches::assert_matches;
1358    use ruma::event_id;
1359
1360    use super::{AllRemoteEvents, EventMeta};
1361
1362    fn event_meta(event_id: &str, timeline_item_index: Option<usize>) -> EventMeta {
1363        EventMeta { event_id: event_id.parse().unwrap(), timeline_item_index, visible: false }
1364    }
1365
1366    macro_rules! assert_events {
1367        ( $events:ident, [ $( ( $event_id:literal, $timeline_item_index:expr ) ),* $(,)? ] ) => {
1368            let mut iter = $events .iter();
1369
1370            $(
1371                assert_matches!(iter.next(), Some(EventMeta { event_id, timeline_item_index, .. }) => {
1372                    assert_eq!(event_id.as_str(), $event_id );
1373                    assert_eq!(*timeline_item_index, $timeline_item_index );
1374                });
1375            )*
1376
1377            assert!(iter.next().is_none(), "Not all events have been asserted");
1378        }
1379    }
1380
1381    #[test]
1382    fn test_range() {
1383        let mut events = AllRemoteEvents::default();
1384
1385        // Push some events.
1386        events.push_back(event_meta("$ev0", None));
1387        events.push_back(event_meta("$ev1", None));
1388        events.push_back(event_meta("$ev2", None));
1389
1390        assert_eq!(events.iter().count(), 3);
1391
1392        // Test a few combinations.
1393        assert_eq!(events.range(..).count(), 3);
1394        assert_eq!(events.range(1..).count(), 2);
1395        assert_eq!(events.range(0..=1).count(), 2);
1396
1397        // Iterate on some of them.
1398        let mut some_events = events.range(1..);
1399
1400        assert_matches!(some_events.next(), Some(EventMeta { event_id, .. }) => {
1401            assert_eq!(event_id.as_str(), "$ev1");
1402        });
1403        assert_matches!(some_events.next(), Some(EventMeta { event_id, .. }) => {
1404            assert_eq!(event_id.as_str(), "$ev2");
1405        });
1406        assert!(some_events.next().is_none());
1407    }
1408
1409    #[test]
1410    fn test_clear() {
1411        let mut events = AllRemoteEvents::default();
1412
1413        // Push some events.
1414        events.push_back(event_meta("$ev0", None));
1415        events.push_back(event_meta("$ev1", None));
1416        events.push_back(event_meta("$ev2", None));
1417
1418        assert_eq!(events.iter().count(), 3);
1419
1420        // And clear them!
1421        events.clear();
1422
1423        assert_eq!(events.iter().count(), 0);
1424    }
1425
1426    #[test]
1427    fn test_push_front() {
1428        let mut events = AllRemoteEvents::default();
1429
1430        // Push front on an empty set, nothing particular.
1431        events.push_front(event_meta("$ev0", Some(1)));
1432
1433        // Push front with no `timeline_item_index`.
1434        events.push_front(event_meta("$ev1", None));
1435
1436        // Push front with a `timeline_item_index`.
1437        events.push_front(event_meta("$ev2", Some(0)));
1438
1439        // Push front with the same `timeline_item_index`.
1440        events.push_front(event_meta("$ev3", Some(0)));
1441
1442        assert_events!(
1443            events,
1444            [
1445                // `timeline_item_index` is untouched
1446                ("$ev3", Some(0)),
1447                // `timeline_item_index` has been shifted once
1448                ("$ev2", Some(1)),
1449                // no `timeline_item_index`
1450                ("$ev1", None),
1451                // `timeline_item_index` has been shifted twice
1452                ("$ev0", Some(3)),
1453            ]
1454        );
1455    }
1456
1457    #[test]
1458    fn test_push_back() {
1459        let mut events = AllRemoteEvents::default();
1460
1461        // Push back on an empty set, nothing particular.
1462        events.push_back(event_meta("$ev0", Some(0)));
1463
1464        // Push back with no `timeline_item_index`.
1465        events.push_back(event_meta("$ev1", None));
1466
1467        // Push back with a `timeline_item_index`.
1468        events.push_back(event_meta("$ev2", Some(1)));
1469
1470        // Push back with a `timeline_item_index` pointing to a timeline item that is
1471        // not the last one. Is it possible in practise? Normally not, but let's test
1472        // it anyway.
1473        events.push_back(event_meta("$ev3", Some(1)));
1474
1475        assert_events!(
1476            events,
1477            [
1478                // `timeline_item_index` is untouched
1479                ("$ev0", Some(0)),
1480                // no `timeline_item_index`
1481                ("$ev1", None),
1482                // `timeline_item_index` has been shifted once
1483                ("$ev2", Some(2)),
1484                // `timeline_item_index` is untouched
1485                ("$ev3", Some(1)),
1486            ]
1487        );
1488    }
1489
1490    #[test]
1491    fn test_insert() {
1492        let mut events = AllRemoteEvents::default();
1493
1494        // Insert on an empty set, nothing particular.
1495        events.insert(0, event_meta("$ev0", Some(0)));
1496
1497        // Insert at the end with no `timeline_item_index`.
1498        events.insert(1, event_meta("$ev1", None));
1499
1500        // Insert at the end with a `timeline_item_index`.
1501        events.insert(2, event_meta("$ev2", Some(1)));
1502
1503        // Insert at the start, with a `timeline_item_index`.
1504        events.insert(0, event_meta("$ev3", Some(0)));
1505
1506        assert_events!(
1507            events,
1508            [
1509                // `timeline_item_index` is untouched
1510                ("$ev3", Some(0)),
1511                // `timeline_item_index` has been shifted once
1512                ("$ev0", Some(1)),
1513                // no `timeline_item_index`
1514                ("$ev1", None),
1515                // `timeline_item_index` has been shifted once
1516                ("$ev2", Some(2)),
1517            ]
1518        );
1519    }
1520
1521    #[test]
1522    fn test_remove() {
1523        let mut events = AllRemoteEvents::default();
1524
1525        // Push some events.
1526        events.push_back(event_meta("$ev0", Some(0)));
1527        events.push_back(event_meta("$ev1", Some(1)));
1528        events.push_back(event_meta("$ev2", None));
1529        events.push_back(event_meta("$ev3", Some(2)));
1530
1531        // Assert initial state.
1532        assert_events!(
1533            events,
1534            [("$ev0", Some(0)), ("$ev1", Some(1)), ("$ev2", None), ("$ev3", Some(2))]
1535        );
1536
1537        // Remove two events.
1538        events.remove(2); // $ev2 has no `timeline_item_index`
1539        events.remove(1); // $ev1 has a `timeline_item_index`
1540
1541        assert_events!(
1542            events,
1543            [
1544                ("$ev0", Some(0)),
1545                // `timeline_item_index` has shifted once
1546                ("$ev3", Some(1)),
1547            ]
1548        );
1549    }
1550
1551    #[test]
1552    fn test_last() {
1553        let mut events = AllRemoteEvents::default();
1554
1555        assert!(events.last().is_none());
1556        assert!(events.last_index().is_none());
1557
1558        // Push some events.
1559        events.push_back(event_meta("$ev0", Some(0)));
1560        events.push_back(event_meta("$ev1", Some(1)));
1561
1562        assert_matches!(events.last(), Some(EventMeta { event_id, .. }) => {
1563            assert_eq!(event_id.as_str(), "$ev1");
1564        });
1565        assert_eq!(events.last_index(), Some(1));
1566    }
1567
1568    #[test]
1569    fn test_get_by_event_by_mut() {
1570        let mut events = AllRemoteEvents::default();
1571
1572        // Push some events.
1573        events.push_back(event_meta("$ev0", Some(0)));
1574        events.push_back(event_meta("$ev1", Some(1)));
1575
1576        assert!(events.get_by_event_id_mut(event_id!("$ev0")).is_some());
1577        assert!(events.get_by_event_id_mut(event_id!("$ev42")).is_none());
1578    }
1579
1580    #[test]
1581    fn test_timeline_item_has_been_inserted_at() {
1582        let mut events = AllRemoteEvents::default();
1583
1584        // Push some events.
1585        events.push_back(event_meta("$ev0", Some(0)));
1586        events.push_back(event_meta("$ev1", Some(1)));
1587        events.push_back(event_meta("$ev2", None));
1588        events.push_back(event_meta("$ev3", None));
1589        events.push_back(event_meta("$ev4", Some(2)));
1590        events.push_back(event_meta("$ev5", Some(3)));
1591        events.push_back(event_meta("$ev6", None));
1592
1593        // A timeline item has been inserted at index 2, and maps to no event.
1594        events.timeline_item_has_been_inserted_at(2, None);
1595
1596        assert_events!(
1597            events,
1598            [
1599                ("$ev0", Some(0)),
1600                ("$ev1", Some(1)),
1601                ("$ev2", None),
1602                ("$ev3", None),
1603                // `timeline_item_index` is shifted once
1604                ("$ev4", Some(3)),
1605                // `timeline_item_index` is shifted once
1606                ("$ev5", Some(4)),
1607                ("$ev6", None),
1608            ]
1609        );
1610
1611        // A timeline item has been inserted at the back, and maps to `$ev6`.
1612        events.timeline_item_has_been_inserted_at(5, Some(6));
1613
1614        assert_events!(
1615            events,
1616            [
1617                ("$ev0", Some(0)),
1618                ("$ev1", Some(1)),
1619                ("$ev2", None),
1620                ("$ev3", None),
1621                ("$ev4", Some(3)),
1622                ("$ev5", Some(4)),
1623                // `timeline_item_index` has been updated
1624                ("$ev6", Some(5)),
1625            ]
1626        );
1627    }
1628
1629    #[test]
1630    fn test_timeline_item_has_been_removed_at() {
1631        let mut events = AllRemoteEvents::default();
1632
1633        // Push some events.
1634        events.push_back(event_meta("$ev0", Some(0)));
1635        events.push_back(event_meta("$ev1", Some(1)));
1636        events.push_back(event_meta("$ev2", None));
1637        events.push_back(event_meta("$ev3", None));
1638        events.push_back(event_meta("$ev4", Some(3)));
1639        events.push_back(event_meta("$ev5", Some(4)));
1640        events.push_back(event_meta("$ev6", None));
1641
1642        // A timeline item has been removed at index 2, which maps to no event.
1643        events.timeline_item_has_been_removed_at(2);
1644
1645        assert_events!(
1646            events,
1647            [
1648                ("$ev0", Some(0)),
1649                ("$ev1", Some(1)),
1650                ("$ev2", None),
1651                ("$ev3", None),
1652                // `timeline_item_index` is shifted once
1653                ("$ev4", Some(2)),
1654                // `timeline_item_index` is shifted once
1655                ("$ev5", Some(3)),
1656                ("$ev6", None),
1657            ]
1658        );
1659
1660        // A timeline item has been removed at index 2, which maps to `$ev4`.
1661        events.timeline_item_has_been_removed_at(2);
1662
1663        assert_events!(
1664            events,
1665            [
1666                ("$ev0", Some(0)),
1667                ("$ev1", Some(1)),
1668                ("$ev2", None),
1669                ("$ev3", None),
1670                // `timeline_item_index` has been updated
1671                ("$ev4", None),
1672                // `timeline_item_index` has shifted once
1673                ("$ev5", Some(2)),
1674                ("$ev6", None),
1675            ]
1676        );
1677
1678        // A timeline item has been removed at index 0, which maps to `$ev0`.
1679        events.timeline_item_has_been_removed_at(0);
1680
1681        assert_events!(
1682            events,
1683            [
1684                // `timeline_item_index` has been updated
1685                ("$ev0", None),
1686                // `timeline_item_index` has shifted once
1687                ("$ev1", Some(0)),
1688                ("$ev2", None),
1689                ("$ev3", None),
1690                ("$ev4", None),
1691                // `timeline_item_index` has shifted once
1692                ("$ev5", Some(1)),
1693                ("$ev6", None),
1694            ]
1695        );
1696    }
1697}