matrix_sdk_ui/timeline/controller/
observable_items.rs

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