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