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::{VecDeque, vec_deque::Iter},
18    iter::{Enumerate, Skip, Take},
19    ops::{Deref, RangeBounds},
20    sync::Arc,
21};
22
23use bitflags::bitflags;
24use eyeball_im::{
25    ObservableVector, ObservableVectorEntries, ObservableVectorEntry, ObservableVectorTransaction,
26    ObservableVectorTransactionEntry, VectorSubscriber,
27};
28use imbl::Vector;
29use ruma::EventId;
30
31use super::{TimelineItem, metadata::EventMeta};
32
33/// An `ObservableItems` is a type similar to
34/// [`ObservableVector<Arc<TimelineItem>>`] except the API is limited and,
35/// internally, maintains the mapping between remote events and timeline items.
36///
37/// # Regions
38///
39/// The `ObservableItems` holds all the invariants about the _position_ of the
40/// items. It defines three regions where items can live:
41///
42/// 1. the _start_ region, which can only contain a single [`TimelineStart`],
43/// 2. the _remotes_ region, which can only contain many [`Remote`] timeline
44///    items with their decorations (only [`DateDivider`]s and [`ReadMarker`]s),
45/// 3. the _locals_ region, which can only contain many [`Local`] timeline items
46///    with their decorations (only [`DateDivider`]s).
47///
48/// The [`iter_all_regions`] method allows to iterate over all regions.
49/// [`iter_remotes_region`] will restrict the iterator over the _remotes_
50/// region, and so on. These iterators provide the absolute indices of the
51/// items, so that it's harder to make mistakes when manipulating the indices of
52/// items with operations like [`insert`], [`remove`], [`replace`] etc.
53///
54/// Other methods like [`push_local`] or [`push_date_divider`] insert the items
55/// in the correct region, and check a couple of invariants.
56///
57/// [`TimelineStart`]: super::VirtualTimelineItem::TimelineStart
58/// [`DateDivider`]: super::VirtualTimelineItem::DateDivider
59/// [`ReadMarker`]: super::VirtualTimelineItem::ReadMarker
60/// [`Remote`]: super::EventTimelineItemKind::Remote
61/// [`Local`]: super::EventTimelineItemKind::Local
62/// [`iter_all_regions`]: ObservableItemsTransaction::iter_all_regions
63/// [`iter_remote_region`]: ObservableItemsTransaction::iter_remotes_region
64/// [`insert`]: ObservableItemsTransaction::insert
65/// [`remove`]: ObservableItemsTransaction::remove
66/// [`replace`]: ObservableItemsTransaction::replace
67/// [`push_local`]: ObservableItemsTransaction::push_local
68/// [`push_date_divider`]: ObservableItemsTransaction::push_date_divider
69#[derive(Debug)]
70pub struct ObservableItems {
71    /// All timeline items.
72    ///
73    /// Yeah, there are here! This [`ObservableVector`] contains all the
74    /// timeline items that are rendered in your magnificent Matrix client.
75    ///
76    /// These items are the _core_ of the timeline, see [`TimelineItem`] to
77    /// learn more.
78    items: ObservableVector<Arc<TimelineItem>>,
79
80    /// List of all the remote events as received in the timeline, even the ones
81    /// that are discarded in the timeline items.
82    ///
83    /// The list of all remote events is used to compute the read receipts and
84    /// read markers; additionally it's used to map events to timeline items,
85    /// for more info about that, take a look at the documentation for
86    /// [`EventMeta::timeline_item_index`].
87    all_remote_events: AllRemoteEvents,
88}
89
90impl ObservableItems {
91    /// Create an empty `ObservableItems`.
92    pub fn new() -> Self {
93        Self {
94            // Upstream default capacity is currently 16, which is making
95            // sliding-sync tests with 20 events lag. This should still be
96            // small enough.
97            items: ObservableVector::with_capacity(32),
98            all_remote_events: AllRemoteEvents::default(),
99        }
100    }
101
102    /// Get a reference to all remote events.
103    pub fn all_remote_events(&self) -> &AllRemoteEvents {
104        &self.all_remote_events
105    }
106
107    /// Check whether there is timeline items.
108    pub fn is_empty(&self) -> bool {
109        self.items.is_empty()
110    }
111
112    /// Subscribe to timeline item updates.
113    pub fn subscribe(&self) -> VectorSubscriber<Arc<TimelineItem>> {
114        self.items.subscribe()
115    }
116
117    /// Get a clone of all timeline items.
118    ///
119    /// Note that it doesn't clone `Self`, only the inner timeline items.
120    pub fn clone_items(&self) -> Vector<Arc<TimelineItem>> {
121        self.items.clone()
122    }
123
124    /// Start a new transaction to make multiple updates as one unit.
125    pub fn transaction(&mut self) -> ObservableItemsTransaction<'_> {
126        ObservableItemsTransaction {
127            items: self.items.transaction(),
128            all_remote_events: &mut self.all_remote_events,
129        }
130    }
131
132    /// Replace the timeline item at position `timeline_item_index` by
133    /// `timeline_item`.
134    ///
135    /// # Panics
136    ///
137    /// Panics if `timeline_item_index > total_number_of_timeline_items`.
138    pub fn replace(
139        &mut self,
140        timeline_item_index: usize,
141        timeline_item: Arc<TimelineItem>,
142    ) -> Arc<TimelineItem> {
143        self.items.set(timeline_item_index, timeline_item)
144    }
145
146    /// Get an iterator over all the entries in this `ObservableItems`.
147    pub fn entries(&mut self) -> ObservableItemsEntries<'_> {
148        ObservableItemsEntries(self.items.entries())
149    }
150
151    /// Call the given closure for every element in this `ObservableItems`,
152    /// with an entry struct that allows updating that element.
153    pub fn for_each<F>(&mut self, mut f: F)
154    where
155        F: FnMut(ObservableItemsEntry<'_>),
156    {
157        self.items.for_each(|entry| f(ObservableItemsEntry(entry)))
158    }
159}
160
161// It's fine to deref to an immutable reference to `Vector`.
162//
163// We don't want, however, to deref to a mutable reference: it should be done
164// via proper methods to control precisely the mapping between remote events and
165// timeline items.
166impl Deref for ObservableItems {
167    type Target = Vector<Arc<TimelineItem>>;
168
169    fn deref(&self) -> &Self::Target {
170        &self.items
171    }
172}
173
174/// An iterator that yields entries into an `ObservableItems`.
175///
176/// It doesn't implement [`Iterator`] though because of a lifetime conflict: the
177/// returned `Iterator::Item` could live longer than the `Iterator` itself.
178/// Ideally, `Iterator::next` should take a `&'a mut self`, but this is not
179/// possible.
180pub struct ObservableItemsEntries<'a>(ObservableVectorEntries<'a, Arc<TimelineItem>>);
181
182impl ObservableItemsEntries<'_> {
183    /// Advance this iterator, yielding an `ObservableItemsEntry` for the next
184    /// item in the timeline, or `None` if all items have been visited.
185    pub fn next(&mut self) -> Option<ObservableItemsEntry<'_>> {
186        self.0.next().map(ObservableItemsEntry)
187    }
188}
189
190/// A handle to a single timeline item in an `ObservableItems`.
191#[derive(Debug)]
192pub struct ObservableItemsEntry<'a>(ObservableVectorEntry<'a, Arc<TimelineItem>>);
193
194impl ObservableItemsEntry<'_> {
195    /// Replace the timeline item by `timeline_item`.
196    pub fn replace(this: &mut Self, timeline_item: Arc<TimelineItem>) -> Arc<TimelineItem> {
197        ObservableVectorEntry::set(&mut this.0, timeline_item)
198    }
199}
200
201// It's fine to deref to an immutable reference to `Arc<TimelineItem>`.
202//
203// We don't want, however, to deref to a mutable reference: it should be done
204// via proper methods to control precisely the mapping between remote events and
205// timeline items.
206impl Deref for ObservableItemsEntry<'_> {
207    type Target = Arc<TimelineItem>;
208
209    fn deref(&self) -> &Self::Target {
210        &self.0
211    }
212}
213
214/// A transaction that allows making multiple updates to an `ObservableItems` as
215/// an atomic unit.
216///
217/// For updates from the transaction to have affect, it has to be finalized with
218/// [`ObservableItemsTransaction::commit`]. If the transaction is dropped
219/// without that method being called, the updates will be discarded.
220#[derive(Debug)]
221pub struct ObservableItemsTransaction<'observable_items> {
222    items: ObservableVectorTransaction<'observable_items, Arc<TimelineItem>>,
223    all_remote_events: &'observable_items mut AllRemoteEvents,
224}
225
226impl<'observable_items> ObservableItemsTransaction<'observable_items> {
227    /// Get a reference to the timeline item at position `timeline_item_index`.
228    pub fn get(&self, timeline_item_index: usize) -> Option<&Arc<TimelineItem>> {
229        self.items.get(timeline_item_index)
230    }
231
232    /// Get a reference to all remote events.
233    pub fn all_remote_events(&self) -> &AllRemoteEvents {
234        self.all_remote_events
235    }
236
237    /// Remove a remote event at the `event_index` position.
238    ///
239    /// Not to be confused with removing a timeline item!
240    pub fn remove_remote_event(&mut self, event_index: usize) -> Option<EventMeta> {
241        self.all_remote_events.remove(event_index)
242    }
243
244    /// Push a new remote event at the front of all remote events.
245    ///
246    /// Not to be confused with pushing a timeline item to the front!
247    pub fn push_front_remote_event(&mut self, event_meta: EventMeta) {
248        self.all_remote_events.push_front(event_meta);
249    }
250
251    /// Push a new remote event at the back of all remote events.
252    ///
253    /// Not to be confused with pushing a timeline item to the back!
254    pub fn push_back_remote_event(&mut self, event_meta: EventMeta) {
255        self.all_remote_events.push_back(event_meta);
256    }
257
258    /// Insert a new remote event at a specific index.
259    ///
260    /// Not to be confused with inserting a timeline item!
261    pub fn insert_remote_event(&mut self, event_index: usize, event_meta: EventMeta) {
262        self.all_remote_events.insert(event_index, event_meta);
263    }
264
265    /// Get a remote event by using an event ID.
266    pub fn get_remote_event_by_event_id_mut(
267        &mut self,
268        event_id: &EventId,
269    ) -> Option<&mut EventMeta> {
270        self.all_remote_events.get_by_event_id_mut(event_id)
271    }
272
273    /// Get a remote event by using an event ID.
274    pub fn get_remote_event_by_event_id(&self, event_id: &EventId) -> Option<&EventMeta> {
275        self.all_remote_events.get_by_event_id(event_id)
276    }
277
278    /// Get the position of an event in the events array by its ID.
279    pub fn position_by_event_id(&self, event_id: &EventId) -> Option<usize> {
280        self.all_remote_events.position_by_event_id(event_id)
281    }
282
283    /// Replace a timeline item at position `timeline_item_index` by
284    /// `timeline_item`.
285    pub fn replace(
286        &mut self,
287        timeline_item_index: usize,
288        timeline_item: Arc<TimelineItem>,
289    ) -> Arc<TimelineItem> {
290        self.items.set(timeline_item_index, timeline_item)
291    }
292
293    /// Remove a timeline item at position `timeline_item_index`.
294    pub fn remove(&mut self, timeline_item_index: usize) -> Arc<TimelineItem> {
295        let removed_timeline_item = self.items.remove(timeline_item_index);
296        self.all_remote_events.timeline_item_has_been_removed_at(timeline_item_index);
297
298        removed_timeline_item
299    }
300
301    /// Insert a new `timeline_item` at position `timeline_item_index`, with an
302    /// optionally associated `event_index`.
303    ///
304    /// If `event_index` is `Some(_)`, it means `timeline_item_index` has an
305    /// associated remote event (at position `event_index`) that maps to it.
306    /// Otherwise, if it is `None`, it means there is no remote event associated
307    /// to it; that's the case for virtual timeline item for example. See
308    /// [`EventMeta::timeline_item_index`] to learn more.
309    pub fn insert(
310        &mut self,
311        timeline_item_index: usize,
312        timeline_item: Arc<TimelineItem>,
313        event_index: Option<usize>,
314    ) {
315        self.items.insert(timeline_item_index, timeline_item);
316        self.all_remote_events.timeline_item_has_been_inserted_at(timeline_item_index, event_index);
317    }
318
319    /// Push a new `timeline_item` at position 0, with an optionally associated
320    /// `event_index`.
321    ///
322    /// If `event_index` is `Some(_)`, it means `timeline_item_index` has an
323    /// associated remote event (at position `event_index`) that maps to it.
324    /// Otherwise, if it is `None`, it means there is no remote event associated
325    /// to it; that's the case for virtual timeline item for example. See
326    /// [`EventMeta::timeline_item_index`] to learn more.
327    pub fn push_front(&mut self, timeline_item: Arc<TimelineItem>, event_index: Option<usize>) {
328        self.items.push_front(timeline_item);
329        self.all_remote_events.timeline_item_has_been_inserted_at(0, event_index);
330    }
331
332    /// Push a new `timeline_item` at position `len() - 1`, with an optionally
333    /// associated `event_index`.
334    ///
335    /// If `event_index` is `Some(_)`, it means `timeline_item_index` has an
336    /// associated remote event (at position `event_index`) that maps to it.
337    /// Otherwise, if it is `None`, it means there is no remote event associated
338    /// to it; that's the case for virtual timeline item for example. See
339    /// [`EventMeta::timeline_item_index`] to learn more.
340    pub fn push_back(&mut self, timeline_item: Arc<TimelineItem>, event_index: Option<usize>) {
341        self.items.push_back(timeline_item);
342        self.all_remote_events
343            .timeline_item_has_been_inserted_at(self.items.len().saturating_sub(1), event_index);
344    }
345
346    /// Push a new [`Local`] timeline item.
347    ///
348    /// # Invariant
349    ///
350    /// A [`Local`] is always the last item.
351    ///
352    /// # Panics
353    ///
354    /// It panics if the provided `timeline_item` is not a [`Local`].
355    ///
356    /// [`Local`]: super::EventTimelineItemKind::Local
357    pub fn push_local(&mut self, timeline_item: Arc<TimelineItem>) {
358        assert!(timeline_item.is_local_echo(), "The provided `timeline_item` is not a `Local`");
359
360        self.push_back(timeline_item, None);
361    }
362
363    /// Push a new [`DateDivider`] virtual timeline item.
364    ///
365    /// # Panics
366    ///
367    /// It panics if the provided `timeline_item` is not a [`DateDivider`].
368    ///
369    /// It also panics if the `timeline_item_index` points inside the _start_
370    /// region.
371    ///
372    /// [`DateDivider`]: super::VirtualTimelineItem::DateDivider
373    /// [`TimelineStart`]: super::VirtualTimelineItem::TimelineStart
374    /// [`Local`]: super::EventTimelineItemKind::Local
375    pub fn push_date_divider(
376        &mut self,
377        timeline_item_index: usize,
378        timeline_item: Arc<TimelineItem>,
379    ) {
380        assert!(
381            timeline_item.is_date_divider(),
382            "The provided `timeline_item` is not a `DateDivider`"
383        );
384
385        // We are not inserting in the start region.
386        if timeline_item_index == 0 && !self.items.is_empty() {
387            assert!(
388                matches!(self.items.get(timeline_item_index), Some(timeline_item) if !timeline_item.is_timeline_start())
389            );
390        }
391
392        if timeline_item_index == self.len() {
393            self.push_back(timeline_item, None);
394        } else if timeline_item_index == 0 {
395            self.push_front(timeline_item, None);
396        } else {
397            self.insert(timeline_item_index, timeline_item, None);
398        }
399    }
400
401    /// Push a new [`TimelineStart`] virtual timeline item.
402    ///
403    /// # Invariant
404    ///
405    /// A [`TimelineStart`] is always the first item if present.
406    ///
407    /// # Panics
408    ///
409    /// It panics if the provided `timeline_item` is not a [`TimelineStart`].
410    ///
411    /// [`TimelineStart`]: super::VirtualTimelineItem::TimelineStart
412    pub fn push_timeline_start_if_missing(&mut self, timeline_item: Arc<TimelineItem>) {
413        assert!(
414            timeline_item.is_timeline_start(),
415            "The provided `timeline_item` is not a `TimelineStart`"
416        );
417
418        // The timeline start virtual item is necessarily the first item.
419        if self.get(0).is_some_and(|item| item.is_timeline_start()) {
420            return;
421        }
422
423        self.push_front(timeline_item, None);
424    }
425
426    /// Clear all timeline items and all remote events.
427    pub fn clear(&mut self) {
428        self.items.clear();
429        self.all_remote_events.clear();
430    }
431
432    /// Call the given closure for every element in this `ObservableItems`,
433    /// with an entry struct that allows updating that element.
434    pub fn for_each<F>(&mut self, mut f: F)
435    where
436        F: FnMut(ObservableItemsTransactionEntry<'_, 'observable_items>),
437    {
438        self.items.for_each(|entry| {
439            f(ObservableItemsTransactionEntry { entry, all_remote_events: self.all_remote_events })
440        })
441    }
442
443    /// Check whether there is at least one [`Local`] timeline item.
444    ///
445    /// [`Local`]: super::EventTimelineItemKind::Local
446    pub fn has_local(&self) -> bool {
447        matches!(self.items.last(), Some(timeline_item) if timeline_item.is_local_echo())
448    }
449
450    /// Return the index where to insert the first remote timeline
451    /// item.
452    pub fn first_remotes_region_index(&self) -> usize {
453        if self.items.get(0).is_some_and(|item| item.is_timeline_start()) { 1 } else { 0 }
454    }
455
456    /// Iterate over all timeline items in the _remotes_ region.
457    pub fn iter_remotes_region(&self) -> ObservableItemsTransactionIter<'_> {
458        ObservableItemsTransactionIterBuilder::new(&self.items).with_remotes().build()
459    }
460
461    /// Iterate over all timeline items in the _remotes_ and _locals_ regions.
462    pub fn iter_remotes_and_locals_regions(&self) -> ObservableItemsTransactionIter<'_> {
463        ObservableItemsTransactionIterBuilder::new(&self.items).with_remotes().with_locals().build()
464    }
465
466    /// Iterate over all timeline items in the _locals_ region.
467    pub fn iter_locals_region(&self) -> ObservableItemsTransactionIter<'_> {
468        ObservableItemsTransactionIterBuilder::new(&self.items).with_locals().build()
469    }
470
471    /// Iterate over all timeline items (in all regions).
472    pub fn iter_all_regions(&self) -> ObservableItemsTransactionIter<'_> {
473        ObservableItemsTransactionIterBuilder::new(&self.items)
474            .with_start()
475            .with_remotes()
476            .with_locals()
477            .build()
478    }
479
480    /// Alias to [`Self::iter_all_regions`].
481    ///
482    /// This type has a `Deref` implementation to `ObservableVectorTransaction`,
483    /// which has its own `iter` method. This method “overrides” it to ensure it
484    /// is consistent with other iterator methods of this type, by aliasing it
485    /// to [`Self::iter_all_regions`].
486    #[allow(unused)] // We really don't want anybody to use the `self.items.iter()` method.
487    #[deprecated = "This method is now aliased to `Self::iter_all_regions`"]
488    pub fn iter(&self) -> ObservableItemsTransactionIter<'_> {
489        self.iter_all_regions()
490    }
491
492    /// Commit this transaction, persisting the changes and notifying
493    /// subscribers.
494    pub fn commit(self) {
495        self.items.commit()
496    }
497}
498
499bitflags! {
500    struct Regions: u8 {
501        /// The _start_ region can only contain a single [`TimelineStart`].
502        ///
503        /// [`TimelineStart`]: super::VirtualTimelineItem::TimelineStart
504        const START = 0b0000_0001;
505
506        /// The _remotes_ region can only contain many [`Remote`] timeline items
507        /// with their decorations (only [`DateDivider`]s and [`ReadMarker`]s).
508        ///
509        /// [`DateDivider`]: super::VirtualTimelineItem::DateDivider
510        /// [`ReadMarker`]: super::VirtualTimelineItem::ReadMarker
511        /// [`Remote`]: super::EventTimelineItemKind::Remote
512        const REMOTES = 0b0000_0010;
513
514        /// The _locals_ region can only contain many [`Local`] timeline items
515        /// with their decorations (only [`DateDivider`]s).
516        ///
517        /// [`DateDivider`]: super::VirtualTimelineItem::DateDivider
518        /// [`Local`]: super::EventTimelineItemKind::Local
519        const LOCALS = 0b0000_0100;
520    }
521}
522
523/// A builder for the [`ObservableItemsTransactionIter`].
524struct ObservableItemsTransactionIterBuilder<'e> {
525    /// The original items.
526    items: &'e ObservableVectorTransaction<'e, Arc<TimelineItem>>,
527
528    /// The regions to cover.
529    regions: Regions,
530}
531
532impl<'e> ObservableItemsTransactionIterBuilder<'e> {
533    /// Build a new [`Self`].
534    fn new(items: &'e ObservableVectorTransaction<'e, Arc<TimelineItem>>) -> Self {
535        Self { items, regions: Regions::empty() }
536    }
537
538    /// Include the _start_ region in the iterator.
539    fn with_start(mut self) -> Self {
540        self.regions.insert(Regions::START);
541        self
542    }
543
544    /// Include the _remotes_ region in the iterator.
545    fn with_remotes(mut self) -> Self {
546        self.regions.insert(Regions::REMOTES);
547        self
548    }
549
550    /// Include the _locals_ region in the iterator.
551    fn with_locals(mut self) -> Self {
552        self.regions.insert(Regions::LOCALS);
553        self
554    }
555
556    /// Build the iterator.
557    #[allow(clippy::iter_skip_zero)]
558    fn build(self) -> ObservableItemsTransactionIter<'e> {
559        // Calculate the size of the _start_ region.
560        let size_of_start_region = if matches!(
561            self.items.get(0),
562            Some(first_timeline_item) if first_timeline_item.is_timeline_start()
563        ) {
564            1
565        } else {
566            0
567        };
568
569        // Calculate the size of the _locals_ region.
570        let size_of_locals_region = self
571            .items
572            .deref()
573            .iter()
574            .rev()
575            .take_while(|timeline_item| timeline_item.is_local_echo())
576            .count();
577
578        // Calculate the size of the _remotes_ region.
579        let size_of_remotes_region =
580            self.items.len() - size_of_start_region - size_of_locals_region;
581
582        let with_start = self.regions.contains(Regions::START);
583        let with_remotes = self.regions.contains(Regions::REMOTES);
584        let with_locals = self.regions.contains(Regions::LOCALS);
585
586        // Compute one iterator per combination of regions.
587        let iter = self.items.deref().iter().enumerate();
588        let inner = match (with_start, with_remotes, with_locals) {
589            // Nothing.
590            (false, false, false) => iter.skip(0).take(0),
591
592            // Only the start region.
593            (true, false, false) => iter.skip(0).take(size_of_start_region),
594
595            // Only the remotes region.
596            (false, true, false) => iter.skip(size_of_start_region).take(size_of_remotes_region),
597
598            // The start region and the remotes regions.
599            (true, true, false) => iter.skip(0).take(size_of_start_region + size_of_remotes_region),
600
601            // Only the locals region.
602            (false, false, true) => {
603                iter.skip(size_of_start_region + size_of_remotes_region).take(size_of_locals_region)
604            }
605
606            // The start region and the locals regions.
607            //
608            // This combination isn't implemented yet (because it contains a hole), but it's also
609            // not necessary in our current code base; it's fine to ignore it.
610            (true, false, true) => unimplemented!(
611                "Iterating over the start and the locals regions is not implemented yet"
612            ),
613
614            // The remotes and the locals regions.
615            (false, true, true) => {
616                iter.skip(size_of_start_region).take(size_of_remotes_region + size_of_locals_region)
617            }
618
619            // All regions.
620            (true, true, true) => iter
621                .skip(0)
622                .take(size_of_start_region + size_of_remotes_region + size_of_locals_region),
623        };
624
625        ObservableItemsTransactionIter { inner }
626    }
627}
628
629/// An iterator over timeline items.
630pub(crate) struct ObservableItemsTransactionIter<'observable_items_transaction> {
631    #[allow(clippy::type_complexity)]
632    inner: Take<
633        Skip<
634            Enumerate<
635                imbl::vector::Iter<
636                    'observable_items_transaction,
637                    Arc<TimelineItem>,
638                    imbl::shared_ptr::DefaultSharedPtr,
639                >,
640            >,
641        >,
642    >,
643}
644
645impl<'e> Iterator for ObservableItemsTransactionIter<'e> {
646    type Item = (usize, &'e Arc<TimelineItem>);
647
648    fn next(&mut self) -> Option<Self::Item> {
649        self.inner.next()
650    }
651}
652
653impl ExactSizeIterator for ObservableItemsTransactionIter<'_> {
654    fn len(&self) -> usize {
655        self.inner.len()
656    }
657}
658
659impl DoubleEndedIterator for ObservableItemsTransactionIter<'_> {
660    fn next_back(&mut self) -> Option<Self::Item> {
661        self.inner.next_back()
662    }
663}
664
665// It's fine to deref to an immutable reference to `Vector`.
666//
667// We don't want, however, to deref to a mutable reference: it should be done
668// via proper methods to control precisely the mapping between remote events and
669// timeline items.
670impl Deref for ObservableItemsTransaction<'_> {
671    type Target = Vector<Arc<TimelineItem>>;
672
673    fn deref(&self) -> &Self::Target {
674        &self.items
675    }
676}
677
678/// A handle to a single timeline item in an `ObservableItemsTransaction`.
679pub struct ObservableItemsTransactionEntry<'observable_transaction_items, 'observable_items> {
680    entry: ObservableVectorTransactionEntry<
681        'observable_transaction_items,
682        'observable_items,
683        Arc<TimelineItem>,
684    >,
685    all_remote_events: &'observable_transaction_items mut AllRemoteEvents,
686}
687
688impl ObservableItemsTransactionEntry<'_, '_> {
689    /// Remove this timeline item.
690    pub fn remove(this: Self) {
691        let entry_index = ObservableVectorTransactionEntry::index(&this.entry);
692
693        ObservableVectorTransactionEntry::remove(this.entry);
694        this.all_remote_events.timeline_item_has_been_removed_at(entry_index);
695    }
696}
697
698// It's fine to deref to an immutable reference to `Arc<TimelineItem>`.
699//
700// We don't want, however, to deref to a mutable reference: it should be done
701// via proper methods to control precisely the mapping between remote events and
702// timeline items.
703impl Deref for ObservableItemsTransactionEntry<'_, '_> {
704    type Target = Arc<TimelineItem>;
705
706    fn deref(&self) -> &Self::Target {
707        &self.entry
708    }
709}
710
711#[cfg(test)]
712mod observable_items_tests {
713    use std::ops::Not;
714
715    use assert_matches::assert_matches;
716    use eyeball_im::VectorDiff;
717    use ruma::{
718        MilliSecondsSinceUnixEpoch,
719        events::room::message::{MessageType, TextMessageEventContent},
720        owned_user_id, uint,
721    };
722    use stream_assert::{assert_next_matches, assert_pending};
723
724    use super::*;
725    use crate::timeline::{
726        EventSendState, EventTimelineItem, Message, MsgLikeContent, MsgLikeKind, TimelineDetails,
727        TimelineItemContent, TimelineItemKind, TimelineUniqueId, VirtualTimelineItem,
728        controller::RemoteEventOrigin,
729        event_item::{EventTimelineItemKind, LocalEventTimelineItem, RemoteEventTimelineItem},
730    };
731
732    fn item(event_id: &str) -> Arc<TimelineItem> {
733        TimelineItem::new(
734            EventTimelineItem::new(
735                owned_user_id!("@ivan:mnt.io"),
736                TimelineDetails::Unavailable,
737                MilliSecondsSinceUnixEpoch(0u32.into()),
738                TimelineItemContent::MsgLike(MsgLikeContent {
739                    kind: MsgLikeKind::Message(Message {
740                        msgtype: MessageType::Text(TextMessageEventContent::plain("hello")),
741                        edited: false,
742                        mentions: None,
743                    }),
744                    reactions: Default::default(),
745                    thread_root: None,
746                    in_reply_to: None,
747                    thread_summary: None,
748                }),
749                EventTimelineItemKind::Remote(RemoteEventTimelineItem {
750                    event_id: event_id.parse().unwrap(),
751                    transaction_id: None,
752                    read_receipts: Default::default(),
753                    is_own: false,
754                    is_highlighted: false,
755                    encryption_info: None,
756                    original_json: None,
757                    latest_edit_json: None,
758                    origin: RemoteEventOrigin::Sync,
759                }),
760                false,
761            ),
762            TimelineUniqueId(format!("__eid_{event_id}")),
763        )
764    }
765
766    fn local_item(transaction_id: &str) -> Arc<TimelineItem> {
767        TimelineItem::new(
768            EventTimelineItem::new(
769                owned_user_id!("@ivan:mnt.io"),
770                TimelineDetails::Unavailable,
771                MilliSecondsSinceUnixEpoch(0u32.into()),
772                TimelineItemContent::MsgLike(MsgLikeContent {
773                    kind: MsgLikeKind::Message(Message {
774                        msgtype: MessageType::Text(TextMessageEventContent::plain("hello")),
775                        edited: false,
776                        mentions: None,
777                    }),
778                    reactions: Default::default(),
779                    thread_root: None,
780                    in_reply_to: None,
781                    thread_summary: None,
782                }),
783                EventTimelineItemKind::Local(LocalEventTimelineItem {
784                    send_state: EventSendState::NotSentYet { progress: None },
785                    transaction_id: transaction_id.into(),
786                    send_handle: None,
787                }),
788                false,
789            ),
790            TimelineUniqueId(format!("__tid_{transaction_id}")),
791        )
792    }
793
794    fn read_marker() -> Arc<TimelineItem> {
795        TimelineItem::read_marker()
796    }
797
798    fn event_meta(event_id: &str) -> EventMeta {
799        EventMeta { event_id: event_id.parse().unwrap(), timeline_item_index: None, visible: false }
800    }
801
802    macro_rules! assert_event_id {
803        ( $timeline_item:expr, $event_id:literal $( , $message:expr )? $(,)? ) => {
804            assert_eq!($timeline_item.as_event().unwrap().event_id().unwrap().as_str(), $event_id $( , $message)? );
805        };
806    }
807
808    macro_rules! assert_transaction_id {
809        ( $timeline_item:expr, $transaction_id:literal $( , $message:expr )? $(,)? ) => {
810            assert_eq!($timeline_item.as_event().unwrap().transaction_id().unwrap().as_str(), $transaction_id $( , $message)? );
811        };
812    }
813
814    macro_rules! assert_mapping {
815        ( on $transaction:ident:
816          | event_id | event_index | timeline_item_index |
817          | $( - )+ | $( - )+ | $( - )+ |
818          $(
819            | $event_id:literal | $event_index:literal | $( $timeline_item_index:literal )? |
820          )+
821        ) => {
822            let all_remote_events = $transaction .all_remote_events();
823
824            $(
825                // Remote event exists at this index…
826                assert_matches!(all_remote_events.0.get( $event_index ), Some(EventMeta { event_id, timeline_item_index, .. }) => {
827                    // … this is the remote event with the expected event ID
828                    assert_eq!(
829                        event_id.as_str(),
830                        $event_id ,
831                        concat!("event #", $event_index, " should have ID ", $event_id)
832                    );
833
834
835                    // (tiny hack to handle the case where `$timeline_item_index` is absent)
836                    #[allow(unused_variables)]
837                    let timeline_item_index_is_expected = false;
838                    $(
839                        let timeline_item_index_is_expected = true;
840                        let _ = $timeline_item_index;
841                    )?
842
843                    if timeline_item_index_is_expected.not() {
844                        // … this remote event does NOT map to a timeline item index
845                        assert!(
846                            timeline_item_index.is_none(),
847                            concat!("event #", $event_index, " with ID ", $event_id, " should NOT map to a timeline item index" )
848                        );
849                    }
850
851                    $(
852                        // … this remote event maps to a timeline item index
853                        assert_eq!(
854                            *timeline_item_index,
855                            Some( $timeline_item_index ),
856                            concat!("event #", $event_index, " with ID ", $event_id, " should map to timeline item #", $timeline_item_index )
857                        );
858
859                        // … this timeline index exists
860                        assert_matches!( $transaction .get( $timeline_item_index ), Some(timeline_item) => {
861                            // … this timelime item has the expected event ID
862                            assert_event_id!(
863                                timeline_item,
864                                $event_id ,
865                                concat!("timeline item #", $timeline_item_index, " should map to event ID ", $event_id )
866                            );
867                        });
868                    )?
869                });
870            )*
871        }
872    }
873
874    #[test]
875    fn test_is_empty() {
876        let mut items = ObservableItems::new();
877
878        assert!(items.is_empty());
879
880        // Push one event to check if `is_empty` returns false.
881        let mut transaction = items.transaction();
882        transaction.push_back(item("$ev0"), Some(0));
883        transaction.commit();
884
885        assert!(items.is_empty().not());
886    }
887
888    #[test]
889    fn test_subscribe() {
890        let mut items = ObservableItems::new();
891        let mut subscriber = items.subscribe().into_stream();
892
893        // Push one event to check the subscriber is emitting something.
894        let mut transaction = items.transaction();
895        transaction.push_back(item("$ev0"), Some(0));
896        transaction.commit();
897
898        // It does!
899        assert_next_matches!(subscriber, VectorDiff::PushBack { value: event } => {
900            assert_event_id!(event, "$ev0");
901        });
902    }
903
904    #[test]
905    fn test_clone_items() {
906        let mut items = ObservableItems::new();
907
908        let mut transaction = items.transaction();
909        transaction.push_back(item("$ev0"), Some(0));
910        transaction.push_back(item("$ev1"), Some(1));
911        transaction.commit();
912
913        let items = items.clone_items();
914        assert_eq!(items.len(), 2);
915        assert_event_id!(items[0], "$ev0");
916        assert_event_id!(items[1], "$ev1");
917    }
918
919    #[test]
920    fn test_replace() {
921        let mut items = ObservableItems::new();
922
923        // Push one event that will be replaced.
924        let mut transaction = items.transaction();
925        transaction.push_back(item("$ev0"), Some(0));
926        transaction.commit();
927
928        // That's time to replace it!
929        items.replace(0, item("$ev1"));
930
931        let items = items.clone_items();
932        assert_eq!(items.len(), 1);
933        assert_event_id!(items[0], "$ev1");
934    }
935
936    #[test]
937    fn test_entries() {
938        let mut items = ObservableItems::new();
939
940        // Push events to iterate on.
941        let mut transaction = items.transaction();
942        transaction.push_back(item("$ev0"), Some(0));
943        transaction.push_back(item("$ev1"), Some(1));
944        transaction.push_back(item("$ev2"), Some(2));
945        transaction.commit();
946
947        let mut entries = items.entries();
948
949        assert_matches!(entries.next(), Some(entry) => {
950            assert_event_id!(entry, "$ev0");
951        });
952        assert_matches!(entries.next(), Some(entry) => {
953            assert_event_id!(entry, "$ev1");
954        });
955        assert_matches!(entries.next(), Some(entry) => {
956            assert_event_id!(entry, "$ev2");
957        });
958        assert_matches!(entries.next(), None);
959    }
960
961    #[test]
962    fn test_entry_replace() {
963        let mut items = ObservableItems::new();
964
965        // Push events to iterate on.
966        let mut transaction = items.transaction();
967        transaction.push_back(item("$ev0"), Some(0));
968        transaction.commit();
969
970        let mut entries = items.entries();
971
972        // Replace one event by another one.
973        assert_matches!(entries.next(), Some(mut entry) => {
974            assert_event_id!(entry, "$ev0");
975            ObservableItemsEntry::replace(&mut entry, item("$ev1"));
976        });
977        assert_matches!(entries.next(), None);
978
979        // Check the new event.
980        let mut entries = items.entries();
981
982        assert_matches!(entries.next(), Some(entry) => {
983            assert_event_id!(entry, "$ev1");
984        });
985        assert_matches!(entries.next(), None);
986    }
987
988    #[test]
989    fn test_for_each() {
990        let mut items = ObservableItems::new();
991
992        // Push events to iterate on.
993        let mut transaction = items.transaction();
994        transaction.push_back(item("$ev0"), Some(0));
995        transaction.push_back(item("$ev1"), Some(1));
996        transaction.push_back(item("$ev2"), Some(2));
997        transaction.commit();
998
999        let mut nth = 0;
1000
1001        // Iterate over events.
1002        items.for_each(|entry| {
1003            match nth {
1004                0 => {
1005                    assert_event_id!(entry, "$ev0");
1006                }
1007                1 => {
1008                    assert_event_id!(entry, "$ev1");
1009                }
1010                2 => {
1011                    assert_event_id!(entry, "$ev2");
1012                }
1013                _ => unreachable!(),
1014            }
1015
1016            nth += 1;
1017        });
1018    }
1019
1020    #[test]
1021    fn test_transaction_commit() {
1022        let mut items = ObservableItems::new();
1023
1024        // Don't commit the transaction.
1025        let mut transaction = items.transaction();
1026        transaction.push_back(item("$ev0"), Some(0));
1027        drop(transaction);
1028
1029        assert!(items.is_empty());
1030
1031        // Commit the transaction.
1032        let mut transaction = items.transaction();
1033        transaction.push_back(item("$ev0"), Some(0));
1034        transaction.commit();
1035
1036        assert!(items.is_empty().not());
1037    }
1038
1039    #[test]
1040    fn test_transaction_get() {
1041        let mut items = ObservableItems::new();
1042
1043        let mut transaction = items.transaction();
1044        transaction.push_back(item("$ev0"), Some(0));
1045
1046        assert_matches!(transaction.get(0), Some(event) => {
1047            assert_event_id!(event, "$ev0");
1048        });
1049    }
1050
1051    #[test]
1052    fn test_transaction_replace() {
1053        let mut items = ObservableItems::new();
1054
1055        let mut transaction = items.transaction();
1056        transaction.push_back(item("$ev0"), Some(0));
1057        transaction.replace(0, item("$ev1"));
1058
1059        assert_matches!(transaction.get(0), Some(event) => {
1060            assert_event_id!(event, "$ev1");
1061        });
1062    }
1063
1064    #[test]
1065    fn test_transaction_insert() {
1066        let mut items = ObservableItems::new();
1067
1068        let mut transaction = items.transaction();
1069
1070        // Remote event with its timeline item.
1071        transaction.push_back_remote_event(event_meta("$ev0"));
1072        transaction.insert(0, item("$ev0"), Some(0));
1073
1074        assert_mapping! {
1075            on transaction:
1076
1077            | event_id | event_index | timeline_item_index |
1078            |----------|-------------|---------------------|
1079            | "$ev0"   | 0           | 0                   | // new
1080        }
1081
1082        // Timeline item without a remote event (for example a read marker).
1083        transaction.insert(0, read_marker(), None);
1084
1085        assert_mapping! {
1086            on transaction:
1087
1088            | event_id | event_index | timeline_item_index |
1089            |----------|-------------|---------------------|
1090            | "$ev0"   | 0           | 1                   | // has shifted
1091        }
1092
1093        // Remote event with its timeline item.
1094        transaction.push_back_remote_event(event_meta("$ev1"));
1095        transaction.insert(2, item("$ev1"), Some(1));
1096
1097        assert_mapping! {
1098            on transaction:
1099
1100            | event_id | event_index | timeline_item_index |
1101            |----------|-------------|---------------------|
1102            | "$ev0"   | 0           | 1                   |
1103            | "$ev1"   | 1           | 2                   | // new
1104        }
1105
1106        // Remote event without a timeline item (for example a state event).
1107        transaction.push_back_remote_event(event_meta("$ev2"));
1108
1109        assert_mapping! {
1110            on transaction:
1111
1112            | event_id | event_index | timeline_item_index |
1113            |----------|-------------|---------------------|
1114            | "$ev0"   | 0           | 1                   |
1115            | "$ev1"   | 1           | 2                   |
1116            | "$ev2"   | 2           |                     | // new
1117        }
1118
1119        // Remote event with its timeline item.
1120        transaction.push_back_remote_event(event_meta("$ev3"));
1121        transaction.insert(3, item("$ev3"), Some(3));
1122
1123        assert_mapping! {
1124            on transaction:
1125
1126            | event_id | event_index | timeline_item_index |
1127            |----------|-------------|---------------------|
1128            | "$ev0"   | 0           | 1                   |
1129            | "$ev1"   | 1           | 2                   |
1130            | "$ev2"   | 2           |                     |
1131            | "$ev3"   | 3           | 3                   | // new
1132        }
1133
1134        // Timeline item with a remote event, but late.
1135        // I don't know if this case is possible in reality, but let's be robust.
1136        transaction.insert(3, item("$ev2"), Some(2));
1137
1138        assert_mapping! {
1139            on transaction:
1140
1141            | event_id | event_index | timeline_item_index |
1142            |----------|-------------|---------------------|
1143            | "$ev0"   | 0           | 1                   |
1144            | "$ev1"   | 1           | 2                   |
1145            | "$ev2"   | 2           | 3                   | // updated
1146            | "$ev3"   | 3           | 4                   | // has shifted
1147        }
1148
1149        // Let's move the read marker for the fun.
1150        transaction.remove(0);
1151        transaction.insert(2, read_marker(), None);
1152
1153        assert_mapping! {
1154            on transaction:
1155
1156            | event_id | event_index | timeline_item_index |
1157            |----------|-------------|---------------------|
1158            | "$ev0"   | 0           | 0                   | // has shifted
1159            | "$ev1"   | 1           | 1                   | // has shifted
1160            | "$ev2"   | 2           | 3                   |
1161            | "$ev3"   | 3           | 4                   |
1162        }
1163
1164        assert_eq!(transaction.len(), 5);
1165    }
1166
1167    #[test]
1168    fn test_transaction_push_front() {
1169        let mut items = ObservableItems::new();
1170
1171        let mut transaction = items.transaction();
1172
1173        // Remote event with its timeline item.
1174        transaction.push_front_remote_event(event_meta("$ev0"));
1175        transaction.push_front(item("$ev0"), Some(0));
1176
1177        assert_mapping! {
1178            on transaction:
1179
1180            | event_id | event_index | timeline_item_index |
1181            |----------|-------------|---------------------|
1182            | "$ev0"   | 0           | 0                   | // new
1183        }
1184
1185        // Timeline item without a remote event (for example a read marker).
1186        transaction.push_front(read_marker(), None);
1187
1188        assert_mapping! {
1189            on transaction:
1190
1191            | event_id | event_index | timeline_item_index |
1192            |----------|-------------|---------------------|
1193            | "$ev0"   | 0           | 1                   | // has shifted
1194        }
1195
1196        // Remote event with its timeline item.
1197        transaction.push_front_remote_event(event_meta("$ev1"));
1198        transaction.push_front(item("$ev1"), Some(0));
1199
1200        assert_mapping! {
1201            on transaction:
1202
1203            | event_id | event_index | timeline_item_index |
1204            |----------|-------------|---------------------|
1205            | "$ev1"   | 0           | 0                   | // new
1206            | "$ev0"   | 1           | 2                   | // has shifted
1207        }
1208
1209        // Remote event without a timeline item (for example a state event).
1210        transaction.push_front_remote_event(event_meta("$ev2"));
1211
1212        assert_mapping! {
1213            on transaction:
1214
1215            | event_id | event_index | timeline_item_index |
1216            |----------|-------------|---------------------|
1217            | "$ev2"   | 0           |                     |
1218            | "$ev1"   | 1           | 0                   | // has shifted
1219            | "$ev0"   | 2           | 2                   | // has shifted
1220        }
1221
1222        // Remote event with its timeline item.
1223        transaction.push_front_remote_event(event_meta("$ev3"));
1224        transaction.push_front(item("$ev3"), Some(0));
1225
1226        assert_mapping! {
1227            on transaction:
1228
1229            | event_id | event_index | timeline_item_index |
1230            |----------|-------------|---------------------|
1231            | "$ev3"   | 0           | 0                   | // new
1232            | "$ev2"   | 1           |                     |
1233            | "$ev1"   | 2           | 1                   | // has shifted
1234            | "$ev0"   | 3           | 3                   | // has shifted
1235        }
1236
1237        assert_eq!(transaction.len(), 4);
1238    }
1239
1240    #[test]
1241    fn test_transaction_push_back() {
1242        let mut items = ObservableItems::new();
1243
1244        let mut transaction = items.transaction();
1245
1246        // Remote event with its timeline item.
1247        transaction.push_back_remote_event(event_meta("$ev0"));
1248        transaction.push_back(item("$ev0"), Some(0));
1249
1250        assert_mapping! {
1251            on transaction:
1252
1253            | event_id | event_index | timeline_item_index |
1254            |----------|-------------|---------------------|
1255            | "$ev0"   | 0           | 0                   | // new
1256        }
1257
1258        // Timeline item without a remote event (for example a read marker).
1259        transaction.push_back(read_marker(), None);
1260
1261        assert_mapping! {
1262            on transaction:
1263
1264            | event_id | event_index | timeline_item_index |
1265            |----------|-------------|---------------------|
1266            | "$ev0"   | 0           | 0                   |
1267        }
1268
1269        // Remote event with its timeline item.
1270        transaction.push_back_remote_event(event_meta("$ev1"));
1271        transaction.push_back(item("$ev1"), Some(1));
1272
1273        assert_mapping! {
1274            on transaction:
1275
1276            | event_id | event_index | timeline_item_index |
1277            |----------|-------------|---------------------|
1278            | "$ev0"   | 0           | 0                   |
1279            | "$ev1"   | 1           | 2                   | // new
1280        }
1281
1282        // Remote event without a timeline item (for example a state event).
1283        transaction.push_back_remote_event(event_meta("$ev2"));
1284
1285        assert_mapping! {
1286            on transaction:
1287
1288            | event_id | event_index | timeline_item_index |
1289            |----------|-------------|---------------------|
1290            | "$ev0"   | 0           | 0                   |
1291            | "$ev1"   | 1           | 2                   |
1292            | "$ev2"   | 2           |                     | // new
1293        }
1294
1295        // Remote event with its timeline item.
1296        transaction.push_back_remote_event(event_meta("$ev3"));
1297        transaction.push_back(item("$ev3"), Some(3));
1298
1299        assert_mapping! {
1300            on transaction:
1301
1302            | event_id | event_index | timeline_item_index |
1303            |----------|-------------|---------------------|
1304            | "$ev0"   | 0           | 0                   |
1305            | "$ev1"   | 1           | 2                   |
1306            | "$ev2"   | 2           |                     |
1307            | "$ev3"   | 3           | 3                   | // new
1308        }
1309
1310        assert_eq!(transaction.len(), 4);
1311    }
1312
1313    #[test]
1314    fn test_transaction_remove() {
1315        let mut items = ObservableItems::new();
1316
1317        let mut transaction = items.transaction();
1318
1319        // Remote event with its timeline item.
1320        transaction.push_back_remote_event(event_meta("$ev0"));
1321        transaction.push_back(item("$ev0"), Some(0));
1322
1323        // Timeline item without a remote event (for example a read marker).
1324        transaction.push_back(read_marker(), None);
1325
1326        // Remote event with its timeline item.
1327        transaction.push_back_remote_event(event_meta("$ev1"));
1328        transaction.push_back(item("$ev1"), Some(1));
1329
1330        // Remote event without a timeline item (for example a state event).
1331        transaction.push_back_remote_event(event_meta("$ev2"));
1332
1333        // Remote event with its timeline item.
1334        transaction.push_back_remote_event(event_meta("$ev3"));
1335        transaction.push_back(item("$ev3"), Some(3));
1336
1337        assert_mapping! {
1338            on transaction:
1339
1340            | event_id | event_index | timeline_item_index |
1341            |----------|-------------|---------------------|
1342            | "$ev0"   | 0           | 0                   |
1343            | "$ev1"   | 1           | 2                   |
1344            | "$ev2"   | 2           |                     |
1345            | "$ev3"   | 3           | 3                   |
1346        }
1347
1348        // Remove the timeline item that has no event.
1349        transaction.remove(1);
1350
1351        assert_mapping! {
1352            on transaction:
1353
1354            | event_id | event_index | timeline_item_index |
1355            |----------|-------------|---------------------|
1356            | "$ev0"   | 0           | 0                   |
1357            | "$ev1"   | 1           | 1                   | // has shifted
1358            | "$ev2"   | 2           |                     |
1359            | "$ev3"   | 3           | 2                   | // has shifted
1360        }
1361
1362        // Remove an timeline item that has an event.
1363        transaction.remove(1);
1364
1365        assert_mapping! {
1366            on transaction:
1367
1368            | event_id | event_index | timeline_item_index |
1369            |----------|-------------|---------------------|
1370            | "$ev0"   | 0           | 0                   |
1371            | "$ev1"   | 1           |                     | // has been removed
1372            | "$ev2"   | 2           |                     |
1373            | "$ev3"   | 3           | 1                   | // has shifted
1374        }
1375
1376        // Remove the last timeline item to test off by 1 error.
1377        transaction.remove(1);
1378
1379        assert_mapping! {
1380            on transaction:
1381
1382            | event_id | event_index | timeline_item_index |
1383            |----------|-------------|---------------------|
1384            | "$ev0"   | 0           | 0                   |
1385            | "$ev1"   | 1           |                     |
1386            | "$ev2"   | 2           |                     |
1387            | "$ev3"   | 3           |                     | // has been removed
1388        }
1389
1390        // Remove all the items \o/
1391        transaction.remove(0);
1392
1393        assert_mapping! {
1394            on transaction:
1395
1396            | event_id | event_index | timeline_item_index |
1397            |----------|-------------|---------------------|
1398            | "$ev0"   | 0           |                     | // has been removed
1399            | "$ev1"   | 1           |                     |
1400            | "$ev2"   | 2           |                     |
1401            | "$ev3"   | 3           |                     |
1402        }
1403
1404        assert!(transaction.is_empty());
1405    }
1406
1407    #[test]
1408    fn test_transaction_clear() {
1409        let mut items = ObservableItems::new();
1410
1411        let mut transaction = items.transaction();
1412
1413        // Remote event with its timeline item.
1414        transaction.push_back_remote_event(event_meta("$ev0"));
1415        transaction.push_back(item("$ev0"), Some(0));
1416
1417        // Timeline item without a remote event (for example a read marker).
1418        transaction.push_back(read_marker(), None);
1419
1420        // Remote event with its timeline item.
1421        transaction.push_back_remote_event(event_meta("$ev1"));
1422        transaction.push_back(item("$ev1"), Some(1));
1423
1424        // Remote event without a timeline item (for example a state event).
1425        transaction.push_back_remote_event(event_meta("$ev2"));
1426
1427        // Remote event with its timeline item.
1428        transaction.push_back_remote_event(event_meta("$ev3"));
1429        transaction.push_back(item("$ev3"), Some(3));
1430
1431        assert_mapping! {
1432            on transaction:
1433
1434            | event_id | event_index | timeline_item_index |
1435            |----------|-------------|---------------------|
1436            | "$ev0"   | 0           | 0                   |
1437            | "$ev1"   | 1           | 2                   |
1438            | "$ev2"   | 2           |                     |
1439            | "$ev3"   | 3           | 3                   |
1440        }
1441
1442        assert_eq!(transaction.all_remote_events().0.len(), 4);
1443        assert_eq!(transaction.len(), 4);
1444
1445        // Let's clear everything.
1446        transaction.clear();
1447
1448        assert!(transaction.all_remote_events().0.is_empty());
1449        assert!(transaction.is_empty());
1450    }
1451
1452    #[test]
1453    fn test_transaction_for_each() {
1454        let mut items = ObservableItems::new();
1455
1456        // Push events to iterate on.
1457        let mut transaction = items.transaction();
1458        transaction.push_back(item("$ev0"), Some(0));
1459        transaction.push_back(item("$ev1"), Some(1));
1460        transaction.push_back(item("$ev2"), Some(2));
1461
1462        let mut nth = 0;
1463
1464        // Iterate over events.
1465        transaction.for_each(|entry| {
1466            match nth {
1467                0 => {
1468                    assert_event_id!(entry, "$ev0");
1469                }
1470                1 => {
1471                    assert_event_id!(entry, "$ev1");
1472                }
1473                2 => {
1474                    assert_event_id!(entry, "$ev2");
1475                }
1476                _ => unreachable!(),
1477            }
1478
1479            nth += 1;
1480        });
1481    }
1482
1483    #[test]
1484    fn test_transaction_for_each_remove() {
1485        let mut items = ObservableItems::new();
1486
1487        // Push events to iterate on.
1488        let mut transaction = items.transaction();
1489
1490        transaction.push_back_remote_event(event_meta("$ev0"));
1491        transaction.push_back(item("$ev0"), Some(0));
1492
1493        transaction.push_back_remote_event(event_meta("$ev1"));
1494        transaction.push_back(item("$ev1"), Some(1));
1495
1496        transaction.push_back_remote_event(event_meta("$ev2"));
1497        transaction.push_back(item("$ev2"), Some(2));
1498
1499        assert_mapping! {
1500            on transaction:
1501
1502            | event_id | event_index | timeline_item_index |
1503            |----------|-------------|---------------------|
1504            | "$ev0"   | 0           | 0                   |
1505            | "$ev1"   | 1           | 1                   |
1506            | "$ev2"   | 2           | 2                   |
1507        }
1508
1509        // Iterate over events, and remove one.
1510        transaction.for_each(|entry| {
1511            if entry.as_event().unwrap().event_id().unwrap().as_str() == "$ev1" {
1512                ObservableItemsTransactionEntry::remove(entry);
1513            }
1514        });
1515
1516        assert_mapping! {
1517            on transaction:
1518
1519            | event_id | event_index | timeline_item_index |
1520            |----------|-------------|---------------------|
1521            | "$ev0"   | 0           | 0                   |
1522            | "$ev2"   | 2           | 1                   | // has shifted
1523        }
1524
1525        assert_eq!(transaction.all_remote_events().0.len(), 3);
1526        assert_eq!(transaction.len(), 2);
1527    }
1528
1529    #[test]
1530    fn test_transaction_push_local() {
1531        let mut items = ObservableItems::new();
1532
1533        let mut transaction = items.transaction();
1534
1535        // Push a remote item.
1536        transaction.push_back(item("$ev0"), None);
1537
1538        // Push a local item.
1539        transaction.push_local(local_item("t0"));
1540
1541        // Push another local item.
1542        transaction.push_local(local_item("t1"));
1543
1544        transaction.commit();
1545
1546        let mut entries = items.entries();
1547
1548        assert_matches!(entries.next(), Some(entry) => {
1549            assert_event_id!(entry, "$ev0");
1550        });
1551        assert_matches!(entries.next(), Some(entry) => {
1552            assert_transaction_id!(entry, "t0");
1553        });
1554        assert_matches!(entries.next(), Some(entry) => {
1555            assert_transaction_id!(entry, "t1");
1556        });
1557        assert_matches!(entries.next(), None);
1558    }
1559
1560    #[test]
1561    #[should_panic]
1562    fn test_transaction_push_local_panic_not_a_local() {
1563        let mut items = ObservableItems::new();
1564        let mut transaction = items.transaction();
1565        transaction.push_local(item("$ev0"));
1566    }
1567
1568    #[test]
1569    fn test_transaction_push_date_divider() {
1570        let mut items = ObservableItems::new();
1571        let mut stream = items.subscribe().into_stream();
1572
1573        let mut transaction = items.transaction();
1574
1575        transaction.push_date_divider(
1576            0,
1577            TimelineItem::new(
1578                TimelineItemKind::Virtual(VirtualTimelineItem::DateDivider(
1579                    MilliSecondsSinceUnixEpoch(uint!(10)),
1580                )),
1581                TimelineUniqueId("__foo".to_owned()),
1582            ),
1583        );
1584        transaction.push_date_divider(
1585            0,
1586            TimelineItem::new(
1587                TimelineItemKind::Virtual(VirtualTimelineItem::DateDivider(
1588                    MilliSecondsSinceUnixEpoch(uint!(20)),
1589                )),
1590                TimelineUniqueId("__bar".to_owned()),
1591            ),
1592        );
1593        transaction.push_date_divider(
1594            1,
1595            TimelineItem::new(
1596                TimelineItemKind::Virtual(VirtualTimelineItem::DateDivider(
1597                    MilliSecondsSinceUnixEpoch(uint!(30)),
1598                )),
1599                TimelineUniqueId("__baz".to_owned()),
1600            ),
1601        );
1602        transaction.commit();
1603
1604        assert_next_matches!(stream, VectorDiff::PushBack { value: timeline_item } => {
1605            assert_matches!(timeline_item.as_virtual(), Some(VirtualTimelineItem::DateDivider(ms)) => {
1606                assert_eq!(u64::from(ms.0), 10);
1607            });
1608        });
1609        assert_next_matches!(stream, VectorDiff::PushFront { value: timeline_item } => {
1610            assert_matches!(timeline_item.as_virtual(), Some(VirtualTimelineItem::DateDivider(ms)) => {
1611                assert_eq!(u64::from(ms.0), 20);
1612            });
1613        });
1614        assert_next_matches!(stream, VectorDiff::Insert { index: 1, value: timeline_item } => {
1615            assert_matches!(timeline_item.as_virtual(), Some(VirtualTimelineItem::DateDivider(ms)) => {
1616                assert_eq!(u64::from(ms.0), 30);
1617            });
1618        });
1619        assert_pending!(stream);
1620    }
1621
1622    #[test]
1623    #[should_panic]
1624    fn test_transaction_push_date_divider_panic_not_a_date_divider() {
1625        let mut items = ObservableItems::new();
1626        let mut transaction = items.transaction();
1627
1628        transaction.push_date_divider(0, item("$ev0"));
1629    }
1630
1631    #[test]
1632    #[should_panic]
1633    fn test_transaction_push_date_divider_panic_not_in_remotes_region() {
1634        let mut items = ObservableItems::new();
1635        let mut transaction = items.transaction();
1636
1637        transaction.push_timeline_start_if_missing(TimelineItem::new(
1638            VirtualTimelineItem::TimelineStart,
1639            TimelineUniqueId("__id_start".to_owned()),
1640        ));
1641        transaction.push_date_divider(
1642            0,
1643            TimelineItem::new(
1644                VirtualTimelineItem::DateDivider(MilliSecondsSinceUnixEpoch(uint!(10))),
1645                TimelineUniqueId("__date_divider".to_owned()),
1646            ),
1647        );
1648    }
1649
1650    #[test]
1651    fn test_transaction_push_timeline_start_if_missing() {
1652        let mut items = ObservableItems::new();
1653
1654        let mut transaction = items.transaction();
1655
1656        // Push an item.
1657        transaction.push_back(item("$ev0"), None);
1658
1659        // Push the timeline start.
1660        transaction.push_timeline_start_if_missing(TimelineItem::new(
1661            VirtualTimelineItem::TimelineStart,
1662            TimelineUniqueId("__id_start".to_owned()),
1663        ));
1664
1665        // Push another item.
1666        transaction.push_back(item("$ev1"), None);
1667
1668        // Try to push the timeline start again.
1669        transaction.push_timeline_start_if_missing(TimelineItem::new(
1670            VirtualTimelineItem::TimelineStart,
1671            TimelineUniqueId("__id_start_again".to_owned()),
1672        ));
1673
1674        transaction.commit();
1675
1676        let mut entries = items.entries();
1677
1678        assert_matches!(entries.next(), Some(entry) => {
1679            assert!(entry.is_timeline_start());
1680        });
1681        assert_matches!(entries.next(), Some(entry) => {
1682            assert_event_id!(entry, "$ev0");
1683        });
1684        assert_matches!(entries.next(), Some(entry) => {
1685            assert_event_id!(entry, "$ev1");
1686        });
1687        assert_matches!(entries.next(), None);
1688    }
1689
1690    #[test]
1691    fn test_transaction_iter_all_regions() {
1692        let mut items = ObservableItems::new();
1693
1694        let mut transaction = items.transaction();
1695        transaction.push_timeline_start_if_missing(TimelineItem::new(
1696            VirtualTimelineItem::TimelineStart,
1697            TimelineUniqueId("__start".to_owned()),
1698        ));
1699        transaction.push_back(item("$ev0"), None);
1700        transaction.push_back(item("$ev1"), None);
1701        transaction.push_back(item("$ev2"), None);
1702        transaction.push_local(local_item("t0"));
1703        transaction.push_local(local_item("t1"));
1704        transaction.push_local(local_item("t2"));
1705
1706        // Iterate all regions.
1707        let mut iter = transaction.iter_all_regions();
1708        assert_matches!(iter.next(), Some((0, item)) => {
1709            assert!(item.is_timeline_start());
1710        });
1711        assert_matches!(iter.next(), Some((1, item)) => {
1712            assert_event_id!(item, "$ev0");
1713        });
1714        assert_matches!(iter.next(), Some((2, item)) => {
1715            assert_event_id!(item, "$ev1");
1716        });
1717        assert_matches!(iter.next(), Some((3, item)) => {
1718            assert_event_id!(item, "$ev2");
1719        });
1720        assert_matches!(iter.next(), Some((4, item)) => {
1721            assert_transaction_id!(item, "t0");
1722        });
1723        assert_matches!(iter.next(), Some((5, item)) => {
1724            assert_transaction_id!(item, "t1");
1725        });
1726        assert_matches!(iter.next(), Some((6, item)) => {
1727            assert_transaction_id!(item, "t2");
1728        });
1729        assert!(iter.next().is_none());
1730    }
1731
1732    #[test]
1733    fn test_transaction_iter_remotes_regions() {
1734        let mut items = ObservableItems::new();
1735
1736        let mut transaction = items.transaction();
1737        transaction.push_timeline_start_if_missing(TimelineItem::new(
1738            VirtualTimelineItem::TimelineStart,
1739            TimelineUniqueId("__start".to_owned()),
1740        ));
1741        transaction.push_back(item("$ev0"), None);
1742        transaction.push_back(item("$ev1"), None);
1743        transaction.push_back(item("$ev2"), None);
1744        transaction.push_local(local_item("t0"));
1745        transaction.push_local(local_item("t1"));
1746        transaction.push_local(local_item("t2"));
1747
1748        // Iterate the remotes region.
1749        let mut iter = transaction.iter_remotes_region();
1750        assert_matches!(iter.next(), Some((1, item)) => {
1751            assert_event_id!(item, "$ev0");
1752        });
1753        assert_matches!(iter.next(), Some((2, item)) => {
1754            assert_event_id!(item, "$ev1");
1755        });
1756        assert_matches!(iter.next(), Some((3, item)) => {
1757            assert_event_id!(item, "$ev2");
1758        });
1759        assert!(iter.next().is_none());
1760    }
1761
1762    #[test]
1763    fn test_transaction_iter_remotes_regions_with_no_start_region() {
1764        let mut items = ObservableItems::new();
1765
1766        let mut transaction = items.transaction();
1767        transaction.push_back(item("$ev0"), None);
1768        transaction.push_back(item("$ev1"), None);
1769        transaction.push_back(item("$ev2"), None);
1770        transaction.push_local(local_item("t0"));
1771        transaction.push_local(local_item("t1"));
1772        transaction.push_local(local_item("t2"));
1773
1774        // Iterate the remotes region.
1775        let mut iter = transaction.iter_remotes_region();
1776        assert_matches!(iter.next(), Some((0, item)) => {
1777            assert_event_id!(item, "$ev0");
1778        });
1779        assert_matches!(iter.next(), Some((1, item)) => {
1780            assert_event_id!(item, "$ev1");
1781        });
1782        assert_matches!(iter.next(), Some((2, item)) => {
1783            assert_event_id!(item, "$ev2");
1784        });
1785        assert!(iter.next().is_none());
1786    }
1787
1788    #[test]
1789    fn test_transaction_iter_remotes_regions_with_no_locals_region() {
1790        let mut items = ObservableItems::new();
1791
1792        let mut transaction = items.transaction();
1793        transaction.push_back(item("$ev0"), None);
1794        transaction.push_back(item("$ev1"), None);
1795        transaction.push_back(item("$ev2"), None);
1796
1797        // Iterate the remotes region.
1798        let mut iter = transaction.iter_remotes_region();
1799        assert_matches!(iter.next(), Some((0, item)) => {
1800            assert_event_id!(item, "$ev0");
1801        });
1802        assert_matches!(iter.next(), Some((1, item)) => {
1803            assert_event_id!(item, "$ev1");
1804        });
1805        assert_matches!(iter.next(), Some((2, item)) => {
1806            assert_event_id!(item, "$ev2");
1807        });
1808        assert!(iter.next().is_none());
1809    }
1810
1811    #[test]
1812    fn test_transaction_iter_locals_region() {
1813        let mut items = ObservableItems::new();
1814
1815        let mut transaction = items.transaction();
1816        transaction.push_timeline_start_if_missing(TimelineItem::new(
1817            VirtualTimelineItem::TimelineStart,
1818            TimelineUniqueId("__start".to_owned()),
1819        ));
1820        transaction.push_back(item("$ev0"), None);
1821        transaction.push_back(item("$ev1"), None);
1822        transaction.push_back(item("$ev2"), None);
1823        transaction.push_local(local_item("t0"));
1824        transaction.push_local(local_item("t1"));
1825        transaction.push_local(local_item("t2"));
1826
1827        // Iterate the locals region.
1828        let mut iter = transaction.iter_locals_region();
1829        assert_matches!(iter.next(), Some((4, item)) => {
1830            assert_transaction_id!(item, "t0");
1831        });
1832        assert_matches!(iter.next(), Some((5, item)) => {
1833            assert_transaction_id!(item, "t1");
1834        });
1835        assert_matches!(iter.next(), Some((6, item)) => {
1836            assert_transaction_id!(item, "t2");
1837        });
1838        assert!(iter.next().is_none());
1839    }
1840}
1841
1842/// A type for all remote events.
1843///
1844/// Having this type helps to know exactly which parts of the code and how they
1845/// use all remote events. It also helps to give a bit of semantics on top of
1846/// them.
1847#[derive(Clone, Debug, Default)]
1848pub struct AllRemoteEvents(VecDeque<EventMeta>);
1849
1850impl AllRemoteEvents {
1851    /// Return a reference to a remote event.
1852    pub fn get(&self, event_index: usize) -> Option<&EventMeta> {
1853        self.0.get(event_index)
1854    }
1855
1856    /// Return a front-to-back iterator over all remote events.
1857    pub fn iter(&self) -> Iter<'_, EventMeta> {
1858        self.0.iter()
1859    }
1860
1861    /// Return a front-to-back iterator covering ranges of all remote events
1862    /// described by `range`.
1863    pub fn range<R>(&self, range: R) -> Iter<'_, EventMeta>
1864    where
1865        R: RangeBounds<usize>,
1866    {
1867        self.0.range(range)
1868    }
1869
1870    /// Remove all remote events.
1871    fn clear(&mut self) {
1872        self.0.clear();
1873    }
1874
1875    /// Insert a new remote event at the front of all the others.
1876    fn push_front(&mut self, event_meta: EventMeta) {
1877        // If there is an associated `timeline_item_index`, shift all the
1878        // `timeline_item_index` that come after this one.
1879        if let Some(new_timeline_item_index) = event_meta.timeline_item_index {
1880            self.increment_all_timeline_item_index_after(new_timeline_item_index);
1881        }
1882
1883        // Push the event.
1884        self.0.push_front(event_meta)
1885    }
1886
1887    /// Insert a new remote event at the back of all the others.
1888    fn push_back(&mut self, event_meta: EventMeta) {
1889        // If there is an associated `timeline_item_index`, shift all the
1890        // `timeline_item_index` that come after this one.
1891        if let Some(new_timeline_item_index) = event_meta.timeline_item_index {
1892            self.increment_all_timeline_item_index_after(new_timeline_item_index);
1893        }
1894
1895        // Push the event.
1896        self.0.push_back(event_meta)
1897    }
1898
1899    /// Insert a new remote event at a specific index.
1900    fn insert(&mut self, event_index: usize, event_meta: EventMeta) {
1901        // If there is an associated `timeline_item_index`, shift all the
1902        // `timeline_item_index` that come after this one.
1903        if let Some(new_timeline_item_index) = event_meta.timeline_item_index {
1904            self.increment_all_timeline_item_index_after(new_timeline_item_index);
1905        }
1906
1907        // Insert the event.
1908        self.0.insert(event_index, event_meta)
1909    }
1910
1911    /// Remove one remote event at a specific index, and return it if it exists.
1912    fn remove(&mut self, event_index: usize) -> Option<EventMeta> {
1913        // Remove the event.
1914        let event_meta = self.0.remove(event_index)?;
1915
1916        // If there is an associated `timeline_item_index`, shift all the
1917        // `timeline_item_index` that come after this one.
1918        if let Some(removed_timeline_item_index) = event_meta.timeline_item_index {
1919            self.decrement_all_timeline_item_index_after(removed_timeline_item_index);
1920        }
1921
1922        Some(event_meta)
1923    }
1924
1925    /// Return a reference to the last remote event if it exists.
1926    pub fn last(&self) -> Option<&EventMeta> {
1927        self.0.back()
1928    }
1929
1930    /// Return the index of the last remote event if it exists.
1931    pub fn last_index(&self) -> Option<usize> {
1932        self.0.len().checked_sub(1)
1933    }
1934
1935    /// Get a mutable reference to a specific remote event by its ID.
1936    pub fn get_by_event_id_mut(&mut self, event_id: &EventId) -> Option<&mut EventMeta> {
1937        self.0.iter_mut().rev().find(|event_meta| event_meta.event_id == event_id)
1938    }
1939
1940    /// Get an immutable reference to a specific remote event by its ID.
1941    pub fn get_by_event_id(&self, event_id: &EventId) -> Option<&EventMeta> {
1942        self.0.iter().rev().find(|event_meta| event_meta.event_id == event_id)
1943    }
1944
1945    /// Get the position of an event in the events array by its ID.
1946    pub fn position_by_event_id(&self, event_id: &EventId) -> Option<usize> {
1947        // Reverse the iterator to start looking at the end. Since this will give us the
1948        // "reverse" position, reverse the index after finding the event.
1949        self.0
1950            .iter()
1951            .enumerate()
1952            .rev()
1953            .find_map(|(i, event_meta)| (event_meta.event_id == event_id).then_some(i))
1954    }
1955
1956    /// Shift to the right all timeline item indexes that are equal to or
1957    /// greater than `new_timeline_item_index`.
1958    fn increment_all_timeline_item_index_after(&mut self, new_timeline_item_index: usize) {
1959        // Traverse items from back to front because:
1960        // - if `new_timeline_item_index` is 0, we need to shift all items anyways, so
1961        //   all items must be traversed,
1962        // - otherwise, it's unlikely we want to traverse all items: the item has been
1963        //   either inserted or pushed back, so there is no need to traverse the first
1964        //   items; we can also break the iteration as soon as all timeline item index
1965        //   after `new_timeline_item_index` has been updated.
1966        for event_meta in self.0.iter_mut().rev() {
1967            if let Some(timeline_item_index) = event_meta.timeline_item_index.as_mut() {
1968                if *timeline_item_index >= new_timeline_item_index {
1969                    *timeline_item_index += 1;
1970                } else {
1971                    // Items are ordered.
1972                    break;
1973                }
1974            }
1975        }
1976    }
1977
1978    /// Shift to the left all timeline item indexes that are greater than
1979    /// `removed_wtimeline_item_index`.
1980    fn decrement_all_timeline_item_index_after(&mut self, removed_timeline_item_index: usize) {
1981        // Traverse items from back to front because:
1982        // - if `new_timeline_item_index` is 0, we need to shift all items anyways, so
1983        //   all items must be traversed,
1984        // - otherwise, it's unlikely we want to traverse all items: the item has been
1985        //   either inserted or pushed back, so there is no need to traverse the first
1986        //   items; we can also break the iteration as soon as all timeline item index
1987        //   after `new_timeline_item_index` has been updated.
1988        for event_meta in self.0.iter_mut().rev() {
1989            if let Some(timeline_item_index) = event_meta.timeline_item_index.as_mut() {
1990                if *timeline_item_index > removed_timeline_item_index {
1991                    *timeline_item_index -= 1;
1992                } else {
1993                    // Items are ordered.
1994                    break;
1995                }
1996            }
1997        }
1998    }
1999
2000    /// Notify that a timeline item has been inserted at
2001    /// `new_timeline_item_index`. If `event_index` is `Some(_)`, it means the
2002    /// remote event at `event_index` must be mapped to
2003    /// `new_timeline_item_index`.
2004    fn timeline_item_has_been_inserted_at(
2005        &mut self,
2006        new_timeline_item_index: usize,
2007        event_index: Option<usize>,
2008    ) {
2009        self.increment_all_timeline_item_index_after(new_timeline_item_index);
2010
2011        if let Some(event_index) = event_index
2012            && let Some(event_meta) = self.0.get_mut(event_index)
2013        {
2014            event_meta.timeline_item_index = Some(new_timeline_item_index);
2015        }
2016    }
2017
2018    /// Notify that a timeline item has been removed at
2019    /// `new_timeline_item_index`.
2020    fn timeline_item_has_been_removed_at(&mut self, timeline_item_index_to_remove: usize) {
2021        for event_meta in self.0.iter_mut() {
2022            let mut remove_timeline_item_index = false;
2023
2024            // A `timeline_item_index` is removed. Let's shift all indexes that come
2025            // after the removed one.
2026            if let Some(timeline_item_index) = event_meta.timeline_item_index.as_mut() {
2027                match (*timeline_item_index).cmp(&timeline_item_index_to_remove) {
2028                    Ordering::Equal => {
2029                        remove_timeline_item_index = true;
2030                    }
2031
2032                    Ordering::Greater => {
2033                        *timeline_item_index -= 1;
2034                    }
2035
2036                    Ordering::Less => {}
2037                }
2038            }
2039
2040            // This is the `event_meta` that holds the `timeline_item_index` that is being
2041            // removed. So let's clean it.
2042            if remove_timeline_item_index {
2043                event_meta.timeline_item_index = None;
2044            }
2045        }
2046    }
2047}
2048
2049#[cfg(test)]
2050mod all_remote_events_tests {
2051    use assert_matches::assert_matches;
2052    use ruma::event_id;
2053
2054    use super::{AllRemoteEvents, EventMeta};
2055
2056    fn event_meta(event_id: &str, timeline_item_index: Option<usize>) -> EventMeta {
2057        EventMeta { event_id: event_id.parse().unwrap(), timeline_item_index, visible: false }
2058    }
2059
2060    macro_rules! assert_events {
2061        ( $events:ident, [ $( ( $event_id:literal, $timeline_item_index:expr ) ),* $(,)? ] ) => {
2062            let mut iter = $events .iter();
2063
2064            $(
2065                assert_matches!(iter.next(), Some(EventMeta { event_id, timeline_item_index, .. }) => {
2066                    assert_eq!(event_id.as_str(), $event_id );
2067                    assert_eq!(*timeline_item_index, $timeline_item_index );
2068                });
2069            )*
2070
2071            assert!(iter.next().is_none(), "Not all events have been asserted");
2072        }
2073    }
2074
2075    #[test]
2076    fn test_range() {
2077        let mut events = AllRemoteEvents::default();
2078
2079        // Push some events.
2080        events.push_back(event_meta("$ev0", None));
2081        events.push_back(event_meta("$ev1", None));
2082        events.push_back(event_meta("$ev2", None));
2083
2084        assert_eq!(events.iter().count(), 3);
2085
2086        // Test a few combinations.
2087        assert_eq!(events.range(..).count(), 3);
2088        assert_eq!(events.range(1..).count(), 2);
2089        assert_eq!(events.range(0..=1).count(), 2);
2090
2091        // Iterate on some of them.
2092        let mut some_events = events.range(1..);
2093
2094        assert_matches!(some_events.next(), Some(EventMeta { event_id, .. }) => {
2095            assert_eq!(event_id.as_str(), "$ev1");
2096        });
2097        assert_matches!(some_events.next(), Some(EventMeta { event_id, .. }) => {
2098            assert_eq!(event_id.as_str(), "$ev2");
2099        });
2100        assert!(some_events.next().is_none());
2101    }
2102
2103    #[test]
2104    fn test_clear() {
2105        let mut events = AllRemoteEvents::default();
2106
2107        // Push some events.
2108        events.push_back(event_meta("$ev0", None));
2109        events.push_back(event_meta("$ev1", None));
2110        events.push_back(event_meta("$ev2", None));
2111
2112        assert_eq!(events.iter().count(), 3);
2113
2114        // And clear them!
2115        events.clear();
2116
2117        assert_eq!(events.iter().count(), 0);
2118    }
2119
2120    #[test]
2121    fn test_push_front() {
2122        let mut events = AllRemoteEvents::default();
2123
2124        // Push front on an empty set, nothing particular.
2125        events.push_front(event_meta("$ev0", Some(1)));
2126
2127        // Push front with no `timeline_item_index`.
2128        events.push_front(event_meta("$ev1", None));
2129
2130        // Push front with a `timeline_item_index`.
2131        events.push_front(event_meta("$ev2", Some(0)));
2132
2133        // Push front with the same `timeline_item_index`.
2134        events.push_front(event_meta("$ev3", Some(0)));
2135
2136        assert_events!(
2137            events,
2138            [
2139                // `timeline_item_index` is untouched
2140                ("$ev3", Some(0)),
2141                // `timeline_item_index` has been shifted once
2142                ("$ev2", Some(1)),
2143                // no `timeline_item_index`
2144                ("$ev1", None),
2145                // `timeline_item_index` has been shifted twice
2146                ("$ev0", Some(3)),
2147            ]
2148        );
2149    }
2150
2151    #[test]
2152    fn test_push_back() {
2153        let mut events = AllRemoteEvents::default();
2154
2155        // Push back on an empty set, nothing particular.
2156        events.push_back(event_meta("$ev0", Some(0)));
2157
2158        // Push back with no `timeline_item_index`.
2159        events.push_back(event_meta("$ev1", None));
2160
2161        // Push back with a `timeline_item_index`.
2162        events.push_back(event_meta("$ev2", Some(1)));
2163
2164        // Push back with a `timeline_item_index` pointing to a timeline item that is
2165        // not the last one. Is it possible in practise? Normally not, but let's test
2166        // it anyway.
2167        events.push_back(event_meta("$ev3", Some(1)));
2168
2169        assert_events!(
2170            events,
2171            [
2172                // `timeline_item_index` is untouched
2173                ("$ev0", Some(0)),
2174                // no `timeline_item_index`
2175                ("$ev1", None),
2176                // `timeline_item_index` has been shifted once
2177                ("$ev2", Some(2)),
2178                // `timeline_item_index` is untouched
2179                ("$ev3", Some(1)),
2180            ]
2181        );
2182    }
2183
2184    #[test]
2185    fn test_insert() {
2186        let mut events = AllRemoteEvents::default();
2187
2188        // Insert on an empty set, nothing particular.
2189        events.insert(0, event_meta("$ev0", Some(0)));
2190
2191        // Insert at the end with no `timeline_item_index`.
2192        events.insert(1, event_meta("$ev1", None));
2193
2194        // Insert at the end with a `timeline_item_index`.
2195        events.insert(2, event_meta("$ev2", Some(1)));
2196
2197        // Insert at the start, with a `timeline_item_index`.
2198        events.insert(0, event_meta("$ev3", Some(0)));
2199
2200        assert_events!(
2201            events,
2202            [
2203                // `timeline_item_index` is untouched
2204                ("$ev3", Some(0)),
2205                // `timeline_item_index` has been shifted once
2206                ("$ev0", Some(1)),
2207                // no `timeline_item_index`
2208                ("$ev1", None),
2209                // `timeline_item_index` has been shifted once
2210                ("$ev2", Some(2)),
2211            ]
2212        );
2213    }
2214
2215    #[test]
2216    fn test_remove() {
2217        let mut events = AllRemoteEvents::default();
2218
2219        // Push some events.
2220        events.push_back(event_meta("$ev0", Some(0)));
2221        events.push_back(event_meta("$ev1", Some(1)));
2222        events.push_back(event_meta("$ev2", None));
2223        events.push_back(event_meta("$ev3", Some(2)));
2224
2225        // Assert initial state.
2226        assert_events!(
2227            events,
2228            [("$ev0", Some(0)), ("$ev1", Some(1)), ("$ev2", None), ("$ev3", Some(2))]
2229        );
2230
2231        // Remove two events.
2232        events.remove(2); // $ev2 has no `timeline_item_index`
2233        events.remove(1); // $ev1 has a `timeline_item_index`
2234
2235        assert_events!(
2236            events,
2237            [
2238                ("$ev0", Some(0)),
2239                // `timeline_item_index` has shifted once
2240                ("$ev3", Some(1)),
2241            ]
2242        );
2243    }
2244
2245    #[test]
2246    fn test_last() {
2247        let mut events = AllRemoteEvents::default();
2248
2249        assert!(events.last().is_none());
2250        assert!(events.last_index().is_none());
2251
2252        // Push some events.
2253        events.push_back(event_meta("$ev0", Some(0)));
2254        events.push_back(event_meta("$ev1", Some(1)));
2255
2256        assert_matches!(events.last(), Some(EventMeta { event_id, .. }) => {
2257            assert_eq!(event_id.as_str(), "$ev1");
2258        });
2259        assert_eq!(events.last_index(), Some(1));
2260    }
2261
2262    #[test]
2263    fn test_get_by_event_by_mut() {
2264        let mut events = AllRemoteEvents::default();
2265
2266        // Push some events.
2267        events.push_back(event_meta("$ev0", Some(0)));
2268        events.push_back(event_meta("$ev1", Some(1)));
2269
2270        assert!(events.get_by_event_id_mut(event_id!("$ev0")).is_some());
2271        assert!(events.get_by_event_id_mut(event_id!("$ev42")).is_none());
2272    }
2273
2274    #[test]
2275    fn test_timeline_item_has_been_inserted_at() {
2276        let mut events = AllRemoteEvents::default();
2277
2278        // Push some events.
2279        events.push_back(event_meta("$ev0", Some(0)));
2280        events.push_back(event_meta("$ev1", Some(1)));
2281        events.push_back(event_meta("$ev2", None));
2282        events.push_back(event_meta("$ev3", None));
2283        events.push_back(event_meta("$ev4", Some(2)));
2284        events.push_back(event_meta("$ev5", Some(3)));
2285        events.push_back(event_meta("$ev6", None));
2286
2287        // A timeline item has been inserted at index 2, and maps to no event.
2288        events.timeline_item_has_been_inserted_at(2, None);
2289
2290        assert_events!(
2291            events,
2292            [
2293                ("$ev0", Some(0)),
2294                ("$ev1", Some(1)),
2295                ("$ev2", None),
2296                ("$ev3", None),
2297                // `timeline_item_index` is shifted once
2298                ("$ev4", Some(3)),
2299                // `timeline_item_index` is shifted once
2300                ("$ev5", Some(4)),
2301                ("$ev6", None),
2302            ]
2303        );
2304
2305        // A timeline item has been inserted at the back, and maps to `$ev6`.
2306        events.timeline_item_has_been_inserted_at(5, Some(6));
2307
2308        assert_events!(
2309            events,
2310            [
2311                ("$ev0", Some(0)),
2312                ("$ev1", Some(1)),
2313                ("$ev2", None),
2314                ("$ev3", None),
2315                ("$ev4", Some(3)),
2316                ("$ev5", Some(4)),
2317                // `timeline_item_index` has been updated
2318                ("$ev6", Some(5)),
2319            ]
2320        );
2321    }
2322
2323    #[test]
2324    fn test_timeline_item_has_been_removed_at() {
2325        let mut events = AllRemoteEvents::default();
2326
2327        // Push some events.
2328        events.push_back(event_meta("$ev0", Some(0)));
2329        events.push_back(event_meta("$ev1", Some(1)));
2330        events.push_back(event_meta("$ev2", None));
2331        events.push_back(event_meta("$ev3", None));
2332        events.push_back(event_meta("$ev4", Some(3)));
2333        events.push_back(event_meta("$ev5", Some(4)));
2334        events.push_back(event_meta("$ev6", None));
2335
2336        // A timeline item has been removed at index 2, which maps to no event.
2337        events.timeline_item_has_been_removed_at(2);
2338
2339        assert_events!(
2340            events,
2341            [
2342                ("$ev0", Some(0)),
2343                ("$ev1", Some(1)),
2344                ("$ev2", None),
2345                ("$ev3", None),
2346                // `timeline_item_index` is shifted once
2347                ("$ev4", Some(2)),
2348                // `timeline_item_index` is shifted once
2349                ("$ev5", Some(3)),
2350                ("$ev6", None),
2351            ]
2352        );
2353
2354        // A timeline item has been removed at index 2, which maps to `$ev4`.
2355        events.timeline_item_has_been_removed_at(2);
2356
2357        assert_events!(
2358            events,
2359            [
2360                ("$ev0", Some(0)),
2361                ("$ev1", Some(1)),
2362                ("$ev2", None),
2363                ("$ev3", None),
2364                // `timeline_item_index` has been updated
2365                ("$ev4", None),
2366                // `timeline_item_index` has shifted once
2367                ("$ev5", Some(2)),
2368                ("$ev6", None),
2369            ]
2370        );
2371
2372        // A timeline item has been removed at index 0, which maps to `$ev0`.
2373        events.timeline_item_has_been_removed_at(0);
2374
2375        assert_events!(
2376            events,
2377            [
2378                // `timeline_item_index` has been updated
2379                ("$ev0", None),
2380                // `timeline_item_index` has shifted once
2381                ("$ev1", Some(0)),
2382                ("$ev2", None),
2383                ("$ev3", None),
2384                ("$ev4", None),
2385                // `timeline_item_index` has shifted once
2386                ("$ev5", Some(1)),
2387                ("$ev6", None),
2388            ]
2389        );
2390    }
2391}