Skip to main content

matrix_sdk_ui/timeline/controller/
observable_items.rs

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