matrix_sdk_ui/timeline/controller/
observable_items.rs

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