1use 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#[derive(Debug)]
70pub struct ObservableItems {
71 items: ObservableVector<Arc<TimelineItem>>,
79
80 all_remote_events: AllRemoteEvents,
88}
89
90impl ObservableItems {
91 pub fn new() -> Self {
93 Self {
94 items: ObservableVector::with_capacity(32),
98 all_remote_events: AllRemoteEvents::default(),
99 }
100 }
101
102 pub fn all_remote_events(&self) -> &AllRemoteEvents {
104 &self.all_remote_events
105 }
106
107 pub fn is_empty(&self) -> bool {
109 self.items.is_empty()
110 }
111
112 pub fn subscribe(&self) -> VectorSubscriber<Arc<TimelineItem>> {
114 self.items.subscribe()
115 }
116
117 pub fn clone_items(&self) -> Vector<Arc<TimelineItem>> {
121 self.items.clone()
122 }
123
124 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 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 pub fn entries(&mut self) -> ObservableItemsEntries<'_> {
148 ObservableItemsEntries(self.items.entries())
149 }
150
151 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
161impl Deref for ObservableItems {
167 type Target = Vector<Arc<TimelineItem>>;
168
169 fn deref(&self) -> &Self::Target {
170 &self.items
171 }
172}
173
174pub struct ObservableItemsEntries<'a>(ObservableVectorEntries<'a, Arc<TimelineItem>>);
181
182impl ObservableItemsEntries<'_> {
183 pub fn next(&mut self) -> Option<ObservableItemsEntry<'_>> {
186 self.0.next().map(ObservableItemsEntry)
187 }
188}
189
190#[derive(Debug)]
192pub struct ObservableItemsEntry<'a>(ObservableVectorEntry<'a, Arc<TimelineItem>>);
193
194impl ObservableItemsEntry<'_> {
195 pub fn replace(this: &mut Self, timeline_item: Arc<TimelineItem>) -> Arc<TimelineItem> {
197 ObservableVectorEntry::set(&mut this.0, timeline_item)
198 }
199}
200
201impl Deref for ObservableItemsEntry<'_> {
207 type Target = Arc<TimelineItem>;
208
209 fn deref(&self) -> &Self::Target {
210 &self.0
211 }
212}
213
214#[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 pub fn get(&self, timeline_item_index: usize) -> Option<&Arc<TimelineItem>> {
229 self.items.get(timeline_item_index)
230 }
231
232 pub fn all_remote_events(&self) -> &AllRemoteEvents {
234 self.all_remote_events
235 }
236
237 pub fn remove_remote_event(&mut self, event_index: usize) -> Option<EventMeta> {
241 self.all_remote_events.remove(event_index)
242 }
243
244 pub fn push_front_remote_event(&mut self, event_meta: EventMeta) {
248 self.all_remote_events.push_front(event_meta);
249 }
250
251 pub fn push_back_remote_event(&mut self, event_meta: EventMeta) {
255 self.all_remote_events.push_back(event_meta);
256 }
257
258 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 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 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 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 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 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 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 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 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 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 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 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 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 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 pub fn clear(&mut self) {
428 self.items.clear();
429 self.all_remote_events.clear();
430 }
431
432 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 pub fn has_local(&self) -> bool {
447 matches!(self.items.last(), Some(timeline_item) if timeline_item.is_local_echo())
448 }
449
450 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 pub fn iter_remotes_region(&self) -> ObservableItemsTransactionIter<'_> {
458 ObservableItemsTransactionIterBuilder::new(&self.items).with_remotes().build()
459 }
460
461 pub fn iter_remotes_and_locals_regions(&self) -> ObservableItemsTransactionIter<'_> {
463 ObservableItemsTransactionIterBuilder::new(&self.items).with_remotes().with_locals().build()
464 }
465
466 pub fn iter_locals_region(&self) -> ObservableItemsTransactionIter<'_> {
468 ObservableItemsTransactionIterBuilder::new(&self.items).with_locals().build()
469 }
470
471 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 #[allow(unused)] #[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 pub fn commit(self) {
495 self.items.commit()
496 }
497}
498
499bitflags! {
500 struct Regions: u8 {
501 const START = 0b0000_0001;
505
506 const REMOTES = 0b0000_0010;
513
514 const LOCALS = 0b0000_0100;
520 }
521}
522
523struct ObservableItemsTransactionIterBuilder<'e> {
525 items: &'e ObservableVectorTransaction<'e, Arc<TimelineItem>>,
527
528 regions: Regions,
530}
531
532impl<'e> ObservableItemsTransactionIterBuilder<'e> {
533 fn new(items: &'e ObservableVectorTransaction<'e, Arc<TimelineItem>>) -> Self {
535 Self { items, regions: Regions::empty() }
536 }
537
538 fn with_start(mut self) -> Self {
540 self.regions.insert(Regions::START);
541 self
542 }
543
544 fn with_remotes(mut self) -> Self {
546 self.regions.insert(Regions::REMOTES);
547 self
548 }
549
550 fn with_locals(mut self) -> Self {
552 self.regions.insert(Regions::LOCALS);
553 self
554 }
555
556 #[allow(clippy::iter_skip_zero)]
558 fn build(self) -> ObservableItemsTransactionIter<'e> {
559 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 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 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 let iter = self.items.deref().iter().enumerate();
588 let inner = match (with_start, with_remotes, with_locals) {
589 (false, false, false) => iter.skip(0).take(0),
591
592 (true, false, false) => iter.skip(0).take(size_of_start_region),
594
595 (false, true, false) => iter.skip(size_of_start_region).take(size_of_remotes_region),
597
598 (true, true, false) => iter.skip(0).take(size_of_start_region + size_of_remotes_region),
600
601 (false, false, true) => {
603 iter.skip(size_of_start_region + size_of_remotes_region).take(size_of_locals_region)
604 }
605
606 (true, false, true) => unimplemented!(
611 "Iterating over the start and the locals regions is not implemented yet"
612 ),
613
614 (false, true, true) => {
616 iter.skip(size_of_start_region).take(size_of_remotes_region + size_of_locals_region)
617 }
618
619 (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
629pub(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
665impl Deref for ObservableItemsTransaction<'_> {
671 type Target = Vector<Arc<TimelineItem>>;
672
673 fn deref(&self) -> &Self::Target {
674 &self.items
675 }
676}
677
678pub 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 pub fn remove_timeline_index_and_remote_event(this: Self) {
691 let timeline_item_index = ObservableVectorTransactionEntry::index(&this.entry);
692
693 ObservableVectorTransactionEntry::remove(this.entry);
694
695 if let Some(event_index) =
696 this.all_remote_events.timeline_item_has_been_removed_at(timeline_item_index)
697 {
698 this.all_remote_events.remove(event_index);
699 }
700 }
701}
702
703impl Deref for ObservableItemsTransactionEntry<'_, '_> {
709 type Target = Arc<TimelineItem>;
710
711 fn deref(&self) -> &Self::Target {
712 &self.entry
713 }
714}
715
716#[cfg(test)]
717mod observable_items_tests {
718 use std::ops::Not;
719
720 use assert_matches::assert_matches;
721 use eyeball_im::VectorDiff;
722 use ruma::{
723 MilliSecondsSinceUnixEpoch,
724 events::room::message::{MessageType, TextMessageEventContent},
725 owned_user_id, uint,
726 };
727 use stream_assert::{assert_next_matches, assert_pending};
728
729 use super::*;
730 use crate::timeline::{
731 EventSendState, EventTimelineItem, Message, MsgLikeContent, MsgLikeKind, TimelineDetails,
732 TimelineItemContent, TimelineItemKind, TimelineUniqueId, VirtualTimelineItem,
733 controller::RemoteEventOrigin,
734 event_item::{EventTimelineItemKind, LocalEventTimelineItem, RemoteEventTimelineItem},
735 };
736
737 fn item(event_id: &str) -> Arc<TimelineItem> {
738 TimelineItem::new(
739 EventTimelineItem::new(
740 owned_user_id!("@ivan:mnt.io"),
741 TimelineDetails::Unavailable,
742 None,
743 None,
744 MilliSecondsSinceUnixEpoch(0u32.into()),
745 TimelineItemContent::MsgLike(MsgLikeContent {
746 kind: MsgLikeKind::Message(Message {
747 msgtype: MessageType::Text(TextMessageEventContent::plain("hello")),
748 edited: false,
749 mentions: None,
750 }),
751 reactions: Default::default(),
752 thread_root: None,
753 in_reply_to: None,
754 thread_summary: None,
755 }),
756 EventTimelineItemKind::Remote(RemoteEventTimelineItem {
757 event_id: event_id.parse().unwrap(),
758 transaction_id: None,
759 read_receipts: Default::default(),
760 is_own: false,
761 is_highlighted: false,
762 encryption_info: None,
763 original_json: None,
764 latest_edit_json: None,
765 origin: RemoteEventOrigin::Sync,
766 }),
767 false,
768 ),
769 TimelineUniqueId(format!("__eid_{event_id}")),
770 )
771 }
772
773 fn local_item(transaction_id: &str) -> Arc<TimelineItem> {
774 TimelineItem::new(
775 EventTimelineItem::new(
776 owned_user_id!("@ivan:mnt.io"),
777 TimelineDetails::Unavailable,
778 None,
779 None,
780 MilliSecondsSinceUnixEpoch(0u32.into()),
781 TimelineItemContent::MsgLike(MsgLikeContent {
782 kind: MsgLikeKind::Message(Message {
783 msgtype: MessageType::Text(TextMessageEventContent::plain("hello")),
784 edited: false,
785 mentions: None,
786 }),
787 reactions: Default::default(),
788 thread_root: None,
789 in_reply_to: None,
790 thread_summary: None,
791 }),
792 EventTimelineItemKind::Local(LocalEventTimelineItem {
793 send_state: EventSendState::NotSentYet { progress: None },
794 transaction_id: transaction_id.into(),
795 send_handle: None,
796 }),
797 false,
798 ),
799 TimelineUniqueId(format!("__tid_{transaction_id}")),
800 )
801 }
802
803 fn read_marker() -> Arc<TimelineItem> {
804 TimelineItem::read_marker()
805 }
806
807 fn event_meta(event_id: &str) -> EventMeta {
808 EventMeta {
809 event_id: event_id.parse().unwrap(),
810 sender: None,
811 thread_root_id: None,
812 timeline_item_index: None,
813 visible: false,
814 can_show_read_receipts: false,
815 }
816 }
817
818 macro_rules! assert_event_id {
819 ( $timeline_item:expr, $event_id:literal $( , $message:expr )? $(,)? ) => {
820 assert_eq!($timeline_item.as_event().unwrap().event_id().unwrap().as_str(), $event_id $( , $message)? );
821 };
822 }
823
824 macro_rules! assert_transaction_id {
825 ( $timeline_item:expr, $transaction_id:literal $( , $message:expr )? $(,)? ) => {
826 assert_eq!($timeline_item.as_event().unwrap().transaction_id().unwrap().as_str(), $transaction_id $( , $message)? );
827 };
828 }
829
830 macro_rules! assert_mapping {
831 ( on $transaction:ident:
832 | event_id | event_index | timeline_item_index |
833 | $( - )+ | $( - )+ | $( - )+ |
834 $(
835 | $event_id:literal | $event_index:literal | $( $timeline_item_index:literal )? |
836 )+
837 ) => {
838 let all_remote_events = $transaction .all_remote_events();
839
840 $(
841 assert_matches!(all_remote_events.0.get( $event_index ), Some(EventMeta { event_id, timeline_item_index, .. }) => {
843 assert_eq!(
845 event_id.as_str(),
846 $event_id ,
847 concat!("event #", $event_index, " should have ID ", $event_id)
848 );
849
850
851 #[allow(unused_variables)]
853 let timeline_item_index_is_expected = false;
854 $(
855 let timeline_item_index_is_expected = true;
856 let _ = $timeline_item_index;
857 )?
858
859 if timeline_item_index_is_expected.not() {
860 assert!(
862 timeline_item_index.is_none(),
863 concat!("event #", $event_index, " with ID ", $event_id, " should NOT map to a timeline item index" )
864 );
865 }
866
867 $(
868 assert_eq!(
870 *timeline_item_index,
871 Some( $timeline_item_index ),
872 concat!("event #", $event_index, " with ID ", $event_id, " should map to timeline item #", $timeline_item_index )
873 );
874
875 assert_matches!( $transaction .get( $timeline_item_index ), Some(timeline_item) => {
877 assert_event_id!(
879 timeline_item,
880 $event_id ,
881 concat!("timeline item #", $timeline_item_index, " should map to event ID ", $event_id )
882 );
883 });
884 )?
885 });
886 )*
887 }
888 }
889
890 #[test]
891 fn test_is_empty() {
892 let mut items = ObservableItems::new();
893
894 assert!(items.is_empty());
895
896 let mut transaction = items.transaction();
898 transaction.push_back(item("$ev0"), Some(0));
899 transaction.commit();
900
901 assert!(items.is_empty().not());
902 }
903
904 #[test]
905 fn test_subscribe() {
906 let mut items = ObservableItems::new();
907 let mut subscriber = items.subscribe().into_stream();
908
909 let mut transaction = items.transaction();
911 transaction.push_back(item("$ev0"), Some(0));
912 transaction.commit();
913
914 assert_next_matches!(subscriber, VectorDiff::PushBack { value: event } => {
916 assert_event_id!(event, "$ev0");
917 });
918 }
919
920 #[test]
921 fn test_clone_items() {
922 let mut items = ObservableItems::new();
923
924 let mut transaction = items.transaction();
925 transaction.push_back(item("$ev0"), Some(0));
926 transaction.push_back(item("$ev1"), Some(1));
927 transaction.commit();
928
929 let items = items.clone_items();
930 assert_eq!(items.len(), 2);
931 assert_event_id!(items[0], "$ev0");
932 assert_event_id!(items[1], "$ev1");
933 }
934
935 #[test]
936 fn test_replace() {
937 let mut items = ObservableItems::new();
938
939 let mut transaction = items.transaction();
941 transaction.push_back(item("$ev0"), Some(0));
942 transaction.commit();
943
944 items.replace(0, item("$ev1"));
946
947 let items = items.clone_items();
948 assert_eq!(items.len(), 1);
949 assert_event_id!(items[0], "$ev1");
950 }
951
952 #[test]
953 fn test_entries() {
954 let mut items = ObservableItems::new();
955
956 let mut transaction = items.transaction();
958 transaction.push_back(item("$ev0"), Some(0));
959 transaction.push_back(item("$ev1"), Some(1));
960 transaction.push_back(item("$ev2"), Some(2));
961 transaction.commit();
962
963 let mut entries = items.entries();
964
965 assert_matches!(entries.next(), Some(entry) => {
966 assert_event_id!(entry, "$ev0");
967 });
968 assert_matches!(entries.next(), Some(entry) => {
969 assert_event_id!(entry, "$ev1");
970 });
971 assert_matches!(entries.next(), Some(entry) => {
972 assert_event_id!(entry, "$ev2");
973 });
974 assert_matches!(entries.next(), None);
975 }
976
977 #[test]
978 fn test_entry_replace() {
979 let mut items = ObservableItems::new();
980
981 let mut transaction = items.transaction();
983 transaction.push_back(item("$ev0"), Some(0));
984 transaction.commit();
985
986 let mut entries = items.entries();
987
988 assert_matches!(entries.next(), Some(mut entry) => {
990 assert_event_id!(entry, "$ev0");
991 ObservableItemsEntry::replace(&mut entry, item("$ev1"));
992 });
993 assert_matches!(entries.next(), None);
994
995 let mut entries = items.entries();
997
998 assert_matches!(entries.next(), Some(entry) => {
999 assert_event_id!(entry, "$ev1");
1000 });
1001 assert_matches!(entries.next(), None);
1002 }
1003
1004 #[test]
1005 fn test_for_each() {
1006 let mut items = ObservableItems::new();
1007
1008 let mut transaction = items.transaction();
1010 transaction.push_back(item("$ev0"), Some(0));
1011 transaction.push_back(item("$ev1"), Some(1));
1012 transaction.push_back(item("$ev2"), Some(2));
1013 transaction.commit();
1014
1015 let mut nth = 0;
1016
1017 items.for_each(|entry| {
1019 match nth {
1020 0 => {
1021 assert_event_id!(entry, "$ev0");
1022 }
1023 1 => {
1024 assert_event_id!(entry, "$ev1");
1025 }
1026 2 => {
1027 assert_event_id!(entry, "$ev2");
1028 }
1029 _ => unreachable!(),
1030 }
1031
1032 nth += 1;
1033 });
1034 }
1035
1036 #[test]
1037 fn test_transaction_commit() {
1038 let mut items = ObservableItems::new();
1039
1040 let mut transaction = items.transaction();
1042 transaction.push_back(item("$ev0"), Some(0));
1043 drop(transaction);
1044
1045 assert!(items.is_empty());
1046
1047 let mut transaction = items.transaction();
1049 transaction.push_back(item("$ev0"), Some(0));
1050 transaction.commit();
1051
1052 assert!(items.is_empty().not());
1053 }
1054
1055 #[test]
1056 fn test_transaction_get() {
1057 let mut items = ObservableItems::new();
1058
1059 let mut transaction = items.transaction();
1060 transaction.push_back(item("$ev0"), Some(0));
1061
1062 assert_matches!(transaction.get(0), Some(event) => {
1063 assert_event_id!(event, "$ev0");
1064 });
1065 }
1066
1067 #[test]
1068 fn test_transaction_replace() {
1069 let mut items = ObservableItems::new();
1070
1071 let mut transaction = items.transaction();
1072 transaction.push_back(item("$ev0"), Some(0));
1073 transaction.replace(0, item("$ev1"));
1074
1075 assert_matches!(transaction.get(0), Some(event) => {
1076 assert_event_id!(event, "$ev1");
1077 });
1078 }
1079
1080 #[test]
1081 fn test_transaction_insert() {
1082 let mut items = ObservableItems::new();
1083
1084 let mut transaction = items.transaction();
1085
1086 transaction.push_back_remote_event(event_meta("$ev0"));
1088 transaction.insert(0, item("$ev0"), Some(0));
1089
1090 assert_mapping! {
1091 on transaction:
1092
1093 | event_id | event_index | timeline_item_index |
1094 |----------|-------------|---------------------|
1095 | "$ev0" | 0 | 0 | }
1097
1098 transaction.insert(0, read_marker(), None);
1100
1101 assert_mapping! {
1102 on transaction:
1103
1104 | event_id | event_index | timeline_item_index |
1105 |----------|-------------|---------------------|
1106 | "$ev0" | 0 | 1 | }
1108
1109 transaction.push_back_remote_event(event_meta("$ev1"));
1111 transaction.insert(2, item("$ev1"), Some(1));
1112
1113 assert_mapping! {
1114 on transaction:
1115
1116 | event_id | event_index | timeline_item_index |
1117 |----------|-------------|---------------------|
1118 | "$ev0" | 0 | 1 |
1119 | "$ev1" | 1 | 2 | }
1121
1122 transaction.push_back_remote_event(event_meta("$ev2"));
1124
1125 assert_mapping! {
1126 on transaction:
1127
1128 | event_id | event_index | timeline_item_index |
1129 |----------|-------------|---------------------|
1130 | "$ev0" | 0 | 1 |
1131 | "$ev1" | 1 | 2 |
1132 | "$ev2" | 2 | | }
1134
1135 transaction.push_back_remote_event(event_meta("$ev3"));
1137 transaction.insert(3, item("$ev3"), Some(3));
1138
1139 assert_mapping! {
1140 on transaction:
1141
1142 | event_id | event_index | timeline_item_index |
1143 |----------|-------------|---------------------|
1144 | "$ev0" | 0 | 1 |
1145 | "$ev1" | 1 | 2 |
1146 | "$ev2" | 2 | |
1147 | "$ev3" | 3 | 3 | }
1149
1150 transaction.insert(3, item("$ev2"), Some(2));
1153
1154 assert_mapping! {
1155 on transaction:
1156
1157 | event_id | event_index | timeline_item_index |
1158 |----------|-------------|---------------------|
1159 | "$ev0" | 0 | 1 |
1160 | "$ev1" | 1 | 2 |
1161 | "$ev2" | 2 | 3 | | "$ev3" | 3 | 4 | }
1164
1165 transaction.remove(0);
1167 transaction.insert(2, read_marker(), None);
1168
1169 assert_mapping! {
1170 on transaction:
1171
1172 | event_id | event_index | timeline_item_index |
1173 |----------|-------------|---------------------|
1174 | "$ev0" | 0 | 0 | | "$ev1" | 1 | 1 | | "$ev2" | 2 | 3 |
1177 | "$ev3" | 3 | 4 |
1178 }
1179
1180 assert_eq!(transaction.len(), 5);
1181 }
1182
1183 #[test]
1184 fn test_transaction_push_front() {
1185 let mut items = ObservableItems::new();
1186
1187 let mut transaction = items.transaction();
1188
1189 transaction.push_front_remote_event(event_meta("$ev0"));
1191 transaction.push_front(item("$ev0"), Some(0));
1192
1193 assert_mapping! {
1194 on transaction:
1195
1196 | event_id | event_index | timeline_item_index |
1197 |----------|-------------|---------------------|
1198 | "$ev0" | 0 | 0 | }
1200
1201 transaction.push_front(read_marker(), None);
1203
1204 assert_mapping! {
1205 on transaction:
1206
1207 | event_id | event_index | timeline_item_index |
1208 |----------|-------------|---------------------|
1209 | "$ev0" | 0 | 1 | }
1211
1212 transaction.push_front_remote_event(event_meta("$ev1"));
1214 transaction.push_front(item("$ev1"), Some(0));
1215
1216 assert_mapping! {
1217 on transaction:
1218
1219 | event_id | event_index | timeline_item_index |
1220 |----------|-------------|---------------------|
1221 | "$ev1" | 0 | 0 | | "$ev0" | 1 | 2 | }
1224
1225 transaction.push_front_remote_event(event_meta("$ev2"));
1227
1228 assert_mapping! {
1229 on transaction:
1230
1231 | event_id | event_index | timeline_item_index |
1232 |----------|-------------|---------------------|
1233 | "$ev2" | 0 | |
1234 | "$ev1" | 1 | 0 | | "$ev0" | 2 | 2 | }
1237
1238 transaction.push_front_remote_event(event_meta("$ev3"));
1240 transaction.push_front(item("$ev3"), Some(0));
1241
1242 assert_mapping! {
1243 on transaction:
1244
1245 | event_id | event_index | timeline_item_index |
1246 |----------|-------------|---------------------|
1247 | "$ev3" | 0 | 0 | | "$ev2" | 1 | |
1249 | "$ev1" | 2 | 1 | | "$ev0" | 3 | 3 | }
1252
1253 assert_eq!(transaction.len(), 4);
1254 }
1255
1256 #[test]
1257 fn test_transaction_push_back() {
1258 let mut items = ObservableItems::new();
1259
1260 let mut transaction = items.transaction();
1261
1262 transaction.push_back_remote_event(event_meta("$ev0"));
1264 transaction.push_back(item("$ev0"), Some(0));
1265
1266 assert_mapping! {
1267 on transaction:
1268
1269 | event_id | event_index | timeline_item_index |
1270 |----------|-------------|---------------------|
1271 | "$ev0" | 0 | 0 | }
1273
1274 transaction.push_back(read_marker(), None);
1276
1277 assert_mapping! {
1278 on transaction:
1279
1280 | event_id | event_index | timeline_item_index |
1281 |----------|-------------|---------------------|
1282 | "$ev0" | 0 | 0 |
1283 }
1284
1285 transaction.push_back_remote_event(event_meta("$ev1"));
1287 transaction.push_back(item("$ev1"), Some(1));
1288
1289 assert_mapping! {
1290 on transaction:
1291
1292 | event_id | event_index | timeline_item_index |
1293 |----------|-------------|---------------------|
1294 | "$ev0" | 0 | 0 |
1295 | "$ev1" | 1 | 2 | }
1297
1298 transaction.push_back_remote_event(event_meta("$ev2"));
1300
1301 assert_mapping! {
1302 on transaction:
1303
1304 | event_id | event_index | timeline_item_index |
1305 |----------|-------------|---------------------|
1306 | "$ev0" | 0 | 0 |
1307 | "$ev1" | 1 | 2 |
1308 | "$ev2" | 2 | | }
1310
1311 transaction.push_back_remote_event(event_meta("$ev3"));
1313 transaction.push_back(item("$ev3"), Some(3));
1314
1315 assert_mapping! {
1316 on transaction:
1317
1318 | event_id | event_index | timeline_item_index |
1319 |----------|-------------|---------------------|
1320 | "$ev0" | 0 | 0 |
1321 | "$ev1" | 1 | 2 |
1322 | "$ev2" | 2 | |
1323 | "$ev3" | 3 | 3 | }
1325
1326 assert_eq!(transaction.len(), 4);
1327 }
1328
1329 #[test]
1330 fn test_transaction_remove() {
1331 let mut items = ObservableItems::new();
1332
1333 let mut transaction = items.transaction();
1334
1335 transaction.push_back_remote_event(event_meta("$ev0"));
1337 transaction.push_back(item("$ev0"), Some(0));
1338
1339 transaction.push_back(read_marker(), None);
1341
1342 transaction.push_back_remote_event(event_meta("$ev1"));
1344 transaction.push_back(item("$ev1"), Some(1));
1345
1346 transaction.push_back_remote_event(event_meta("$ev2"));
1348
1349 transaction.push_back_remote_event(event_meta("$ev3"));
1351 transaction.push_back(item("$ev3"), Some(3));
1352
1353 assert_mapping! {
1354 on transaction:
1355
1356 | event_id | event_index | timeline_item_index |
1357 |----------|-------------|---------------------|
1358 | "$ev0" | 0 | 0 |
1359 | "$ev1" | 1 | 2 |
1360 | "$ev2" | 2 | |
1361 | "$ev3" | 3 | 3 |
1362 }
1363
1364 transaction.remove(1);
1366
1367 assert_mapping! {
1368 on transaction:
1369
1370 | event_id | event_index | timeline_item_index |
1371 |----------|-------------|---------------------|
1372 | "$ev0" | 0 | 0 |
1373 | "$ev1" | 1 | 1 | | "$ev2" | 2 | |
1375 | "$ev3" | 3 | 2 | }
1377
1378 transaction.remove(1);
1380
1381 assert_mapping! {
1382 on transaction:
1383
1384 | event_id | event_index | timeline_item_index |
1385 |----------|-------------|---------------------|
1386 | "$ev0" | 0 | 0 |
1387 | "$ev1" | 1 | | | "$ev2" | 2 | |
1389 | "$ev3" | 3 | 1 | }
1391
1392 transaction.remove(1);
1394
1395 assert_mapping! {
1396 on transaction:
1397
1398 | event_id | event_index | timeline_item_index |
1399 |----------|-------------|---------------------|
1400 | "$ev0" | 0 | 0 |
1401 | "$ev1" | 1 | |
1402 | "$ev2" | 2 | |
1403 | "$ev3" | 3 | | }
1405
1406 transaction.remove(0);
1408
1409 assert_mapping! {
1410 on transaction:
1411
1412 | event_id | event_index | timeline_item_index |
1413 |----------|-------------|---------------------|
1414 | "$ev0" | 0 | | | "$ev1" | 1 | |
1416 | "$ev2" | 2 | |
1417 | "$ev3" | 3 | |
1418 }
1419
1420 assert!(transaction.is_empty());
1421 }
1422
1423 #[test]
1424 fn test_transaction_clear() {
1425 let mut items = ObservableItems::new();
1426
1427 let mut transaction = items.transaction();
1428
1429 transaction.push_back_remote_event(event_meta("$ev0"));
1431 transaction.push_back(item("$ev0"), Some(0));
1432
1433 transaction.push_back(read_marker(), None);
1435
1436 transaction.push_back_remote_event(event_meta("$ev1"));
1438 transaction.push_back(item("$ev1"), Some(1));
1439
1440 transaction.push_back_remote_event(event_meta("$ev2"));
1442
1443 transaction.push_back_remote_event(event_meta("$ev3"));
1445 transaction.push_back(item("$ev3"), Some(3));
1446
1447 assert_mapping! {
1448 on transaction:
1449
1450 | event_id | event_index | timeline_item_index |
1451 |----------|-------------|---------------------|
1452 | "$ev0" | 0 | 0 |
1453 | "$ev1" | 1 | 2 |
1454 | "$ev2" | 2 | |
1455 | "$ev3" | 3 | 3 |
1456 }
1457
1458 assert_eq!(transaction.all_remote_events().0.len(), 4);
1459 assert_eq!(transaction.len(), 4);
1460
1461 transaction.clear();
1463
1464 assert!(transaction.all_remote_events().0.is_empty());
1465 assert!(transaction.is_empty());
1466 }
1467
1468 #[test]
1469 fn test_transaction_for_each() {
1470 let mut items = ObservableItems::new();
1471
1472 let mut transaction = items.transaction();
1474 transaction.push_back(item("$ev0"), Some(0));
1475 transaction.push_back(item("$ev1"), Some(1));
1476 transaction.push_back(item("$ev2"), Some(2));
1477
1478 let mut nth = 0;
1479
1480 transaction.for_each(|entry| {
1482 match nth {
1483 0 => {
1484 assert_event_id!(entry, "$ev0");
1485 }
1486 1 => {
1487 assert_event_id!(entry, "$ev1");
1488 }
1489 2 => {
1490 assert_event_id!(entry, "$ev2");
1491 }
1492 _ => unreachable!(),
1493 }
1494
1495 nth += 1;
1496 });
1497 }
1498
1499 #[test]
1500 fn test_transaction_for_each_remove_timeline_item_and_remote_event() {
1501 let mut items = ObservableItems::new();
1502
1503 let mut transaction = items.transaction();
1505
1506 transaction.push_back_remote_event(event_meta("$ev0"));
1507 transaction.push_back(item("$ev0"), Some(0));
1508
1509 transaction.push_back_remote_event(event_meta("$ev1"));
1510 transaction.push_back(item("$ev1"), Some(1));
1511
1512 transaction.push_back_remote_event(event_meta("$ev2"));
1513 transaction.push_back(item("$ev2"), Some(2));
1514
1515 assert_mapping! {
1516 on transaction:
1517
1518 | event_id | event_index | timeline_item_index |
1519 |----------|-------------|---------------------|
1520 | "$ev0" | 0 | 0 |
1521 | "$ev1" | 1 | 1 |
1522 | "$ev2" | 2 | 2 |
1523 }
1524
1525 transaction.for_each(|entry| {
1527 if entry.as_event().unwrap().event_id().unwrap().as_str() == "$ev1" {
1528 ObservableItemsTransactionEntry::remove_timeline_index_and_remote_event(entry);
1529 }
1530 });
1531
1532 assert_mapping! {
1533 on transaction:
1534
1535 | event_id | event_index | timeline_item_index |
1536 |----------|-------------|---------------------|
1537 | "$ev0" | 0 | 0 |
1538 | "$ev2" | 1 | 1 | }
1540
1541 assert_eq!(transaction.all_remote_events().0.len(), 2);
1542 assert_eq!(transaction.len(), 2);
1543 }
1544
1545 #[test]
1546 fn test_transaction_push_local() {
1547 let mut items = ObservableItems::new();
1548
1549 let mut transaction = items.transaction();
1550
1551 transaction.push_back(item("$ev0"), None);
1553
1554 transaction.push_local(local_item("t0"));
1556
1557 transaction.push_local(local_item("t1"));
1559
1560 transaction.commit();
1561
1562 let mut entries = items.entries();
1563
1564 assert_matches!(entries.next(), Some(entry) => {
1565 assert_event_id!(entry, "$ev0");
1566 });
1567 assert_matches!(entries.next(), Some(entry) => {
1568 assert_transaction_id!(entry, "t0");
1569 });
1570 assert_matches!(entries.next(), Some(entry) => {
1571 assert_transaction_id!(entry, "t1");
1572 });
1573 assert_matches!(entries.next(), None);
1574 }
1575
1576 #[test]
1577 #[should_panic]
1578 fn test_transaction_push_local_panic_not_a_local() {
1579 let mut items = ObservableItems::new();
1580 let mut transaction = items.transaction();
1581 transaction.push_local(item("$ev0"));
1582 }
1583
1584 #[test]
1585 fn test_transaction_push_date_divider() {
1586 let mut items = ObservableItems::new();
1587 let mut stream = items.subscribe().into_stream();
1588
1589 let mut transaction = items.transaction();
1590
1591 transaction.push_date_divider(
1592 0,
1593 TimelineItem::new(
1594 TimelineItemKind::Virtual(VirtualTimelineItem::DateDivider(
1595 MilliSecondsSinceUnixEpoch(uint!(10)),
1596 )),
1597 TimelineUniqueId("__foo".to_owned()),
1598 ),
1599 );
1600 transaction.push_date_divider(
1601 0,
1602 TimelineItem::new(
1603 TimelineItemKind::Virtual(VirtualTimelineItem::DateDivider(
1604 MilliSecondsSinceUnixEpoch(uint!(20)),
1605 )),
1606 TimelineUniqueId("__bar".to_owned()),
1607 ),
1608 );
1609 transaction.push_date_divider(
1610 1,
1611 TimelineItem::new(
1612 TimelineItemKind::Virtual(VirtualTimelineItem::DateDivider(
1613 MilliSecondsSinceUnixEpoch(uint!(30)),
1614 )),
1615 TimelineUniqueId("__baz".to_owned()),
1616 ),
1617 );
1618 transaction.commit();
1619
1620 assert_next_matches!(stream, VectorDiff::PushBack { value: timeline_item } => {
1621 assert_matches!(timeline_item.as_virtual(), Some(VirtualTimelineItem::DateDivider(ms)) => {
1622 assert_eq!(u64::from(ms.0), 10);
1623 });
1624 });
1625 assert_next_matches!(stream, VectorDiff::PushFront { value: timeline_item } => {
1626 assert_matches!(timeline_item.as_virtual(), Some(VirtualTimelineItem::DateDivider(ms)) => {
1627 assert_eq!(u64::from(ms.0), 20);
1628 });
1629 });
1630 assert_next_matches!(stream, VectorDiff::Insert { index: 1, value: timeline_item } => {
1631 assert_matches!(timeline_item.as_virtual(), Some(VirtualTimelineItem::DateDivider(ms)) => {
1632 assert_eq!(u64::from(ms.0), 30);
1633 });
1634 });
1635 assert_pending!(stream);
1636 }
1637
1638 #[test]
1639 #[should_panic]
1640 fn test_transaction_push_date_divider_panic_not_a_date_divider() {
1641 let mut items = ObservableItems::new();
1642 let mut transaction = items.transaction();
1643
1644 transaction.push_date_divider(0, item("$ev0"));
1645 }
1646
1647 #[test]
1648 #[should_panic]
1649 fn test_transaction_push_date_divider_panic_not_in_remotes_region() {
1650 let mut items = ObservableItems::new();
1651 let mut transaction = items.transaction();
1652
1653 transaction.push_timeline_start_if_missing(TimelineItem::new(
1654 VirtualTimelineItem::TimelineStart,
1655 TimelineUniqueId("__id_start".to_owned()),
1656 ));
1657 transaction.push_date_divider(
1658 0,
1659 TimelineItem::new(
1660 VirtualTimelineItem::DateDivider(MilliSecondsSinceUnixEpoch(uint!(10))),
1661 TimelineUniqueId("__date_divider".to_owned()),
1662 ),
1663 );
1664 }
1665
1666 #[test]
1667 fn test_transaction_push_timeline_start_if_missing() {
1668 let mut items = ObservableItems::new();
1669
1670 let mut transaction = items.transaction();
1671
1672 transaction.push_back(item("$ev0"), None);
1674
1675 transaction.push_timeline_start_if_missing(TimelineItem::new(
1677 VirtualTimelineItem::TimelineStart,
1678 TimelineUniqueId("__id_start".to_owned()),
1679 ));
1680
1681 transaction.push_back(item("$ev1"), None);
1683
1684 transaction.push_timeline_start_if_missing(TimelineItem::new(
1686 VirtualTimelineItem::TimelineStart,
1687 TimelineUniqueId("__id_start_again".to_owned()),
1688 ));
1689
1690 transaction.commit();
1691
1692 let mut entries = items.entries();
1693
1694 assert_matches!(entries.next(), Some(entry) => {
1695 assert!(entry.is_timeline_start());
1696 });
1697 assert_matches!(entries.next(), Some(entry) => {
1698 assert_event_id!(entry, "$ev0");
1699 });
1700 assert_matches!(entries.next(), Some(entry) => {
1701 assert_event_id!(entry, "$ev1");
1702 });
1703 assert_matches!(entries.next(), None);
1704 }
1705
1706 #[test]
1707 fn test_transaction_iter_all_regions() {
1708 let mut items = ObservableItems::new();
1709
1710 let mut transaction = items.transaction();
1711 transaction.push_timeline_start_if_missing(TimelineItem::new(
1712 VirtualTimelineItem::TimelineStart,
1713 TimelineUniqueId("__start".to_owned()),
1714 ));
1715 transaction.push_back(item("$ev0"), None);
1716 transaction.push_back(item("$ev1"), None);
1717 transaction.push_back(item("$ev2"), None);
1718 transaction.push_local(local_item("t0"));
1719 transaction.push_local(local_item("t1"));
1720 transaction.push_local(local_item("t2"));
1721
1722 let mut iter = transaction.iter_all_regions();
1724 assert_matches!(iter.next(), Some((0, item)) => {
1725 assert!(item.is_timeline_start());
1726 });
1727 assert_matches!(iter.next(), Some((1, item)) => {
1728 assert_event_id!(item, "$ev0");
1729 });
1730 assert_matches!(iter.next(), Some((2, item)) => {
1731 assert_event_id!(item, "$ev1");
1732 });
1733 assert_matches!(iter.next(), Some((3, item)) => {
1734 assert_event_id!(item, "$ev2");
1735 });
1736 assert_matches!(iter.next(), Some((4, item)) => {
1737 assert_transaction_id!(item, "t0");
1738 });
1739 assert_matches!(iter.next(), Some((5, item)) => {
1740 assert_transaction_id!(item, "t1");
1741 });
1742 assert_matches!(iter.next(), Some((6, item)) => {
1743 assert_transaction_id!(item, "t2");
1744 });
1745 assert!(iter.next().is_none());
1746 }
1747
1748 #[test]
1749 fn test_transaction_iter_remotes_regions() {
1750 let mut items = ObservableItems::new();
1751
1752 let mut transaction = items.transaction();
1753 transaction.push_timeline_start_if_missing(TimelineItem::new(
1754 VirtualTimelineItem::TimelineStart,
1755 TimelineUniqueId("__start".to_owned()),
1756 ));
1757 transaction.push_back(item("$ev0"), None);
1758 transaction.push_back(item("$ev1"), None);
1759 transaction.push_back(item("$ev2"), None);
1760 transaction.push_local(local_item("t0"));
1761 transaction.push_local(local_item("t1"));
1762 transaction.push_local(local_item("t2"));
1763
1764 let mut iter = transaction.iter_remotes_region();
1766 assert_matches!(iter.next(), Some((1, item)) => {
1767 assert_event_id!(item, "$ev0");
1768 });
1769 assert_matches!(iter.next(), Some((2, item)) => {
1770 assert_event_id!(item, "$ev1");
1771 });
1772 assert_matches!(iter.next(), Some((3, item)) => {
1773 assert_event_id!(item, "$ev2");
1774 });
1775 assert!(iter.next().is_none());
1776 }
1777
1778 #[test]
1779 fn test_transaction_iter_remotes_regions_with_no_start_region() {
1780 let mut items = ObservableItems::new();
1781
1782 let mut transaction = items.transaction();
1783 transaction.push_back(item("$ev0"), None);
1784 transaction.push_back(item("$ev1"), None);
1785 transaction.push_back(item("$ev2"), None);
1786 transaction.push_local(local_item("t0"));
1787 transaction.push_local(local_item("t1"));
1788 transaction.push_local(local_item("t2"));
1789
1790 let mut iter = transaction.iter_remotes_region();
1792 assert_matches!(iter.next(), Some((0, item)) => {
1793 assert_event_id!(item, "$ev0");
1794 });
1795 assert_matches!(iter.next(), Some((1, item)) => {
1796 assert_event_id!(item, "$ev1");
1797 });
1798 assert_matches!(iter.next(), Some((2, item)) => {
1799 assert_event_id!(item, "$ev2");
1800 });
1801 assert!(iter.next().is_none());
1802 }
1803
1804 #[test]
1805 fn test_transaction_iter_remotes_regions_with_no_locals_region() {
1806 let mut items = ObservableItems::new();
1807
1808 let mut transaction = items.transaction();
1809 transaction.push_back(item("$ev0"), None);
1810 transaction.push_back(item("$ev1"), None);
1811 transaction.push_back(item("$ev2"), None);
1812
1813 let mut iter = transaction.iter_remotes_region();
1815 assert_matches!(iter.next(), Some((0, item)) => {
1816 assert_event_id!(item, "$ev0");
1817 });
1818 assert_matches!(iter.next(), Some((1, item)) => {
1819 assert_event_id!(item, "$ev1");
1820 });
1821 assert_matches!(iter.next(), Some((2, item)) => {
1822 assert_event_id!(item, "$ev2");
1823 });
1824 assert!(iter.next().is_none());
1825 }
1826
1827 #[test]
1828 fn test_transaction_iter_locals_region() {
1829 let mut items = ObservableItems::new();
1830
1831 let mut transaction = items.transaction();
1832 transaction.push_timeline_start_if_missing(TimelineItem::new(
1833 VirtualTimelineItem::TimelineStart,
1834 TimelineUniqueId("__start".to_owned()),
1835 ));
1836 transaction.push_back(item("$ev0"), None);
1837 transaction.push_back(item("$ev1"), None);
1838 transaction.push_back(item("$ev2"), None);
1839 transaction.push_local(local_item("t0"));
1840 transaction.push_local(local_item("t1"));
1841 transaction.push_local(local_item("t2"));
1842
1843 let mut iter = transaction.iter_locals_region();
1845 assert_matches!(iter.next(), Some((4, item)) => {
1846 assert_transaction_id!(item, "t0");
1847 });
1848 assert_matches!(iter.next(), Some((5, item)) => {
1849 assert_transaction_id!(item, "t1");
1850 });
1851 assert_matches!(iter.next(), Some((6, item)) => {
1852 assert_transaction_id!(item, "t2");
1853 });
1854 assert!(iter.next().is_none());
1855 }
1856}
1857
1858#[derive(Clone, Debug, Default)]
1864pub struct AllRemoteEvents(VecDeque<EventMeta>);
1865
1866impl AllRemoteEvents {
1867 pub fn get(&self, event_index: usize) -> Option<&EventMeta> {
1869 self.0.get(event_index)
1870 }
1871
1872 pub fn iter(&self) -> Iter<'_, EventMeta> {
1874 self.0.iter()
1875 }
1876
1877 pub fn range<R>(&self, range: R) -> Iter<'_, EventMeta>
1880 where
1881 R: RangeBounds<usize>,
1882 {
1883 self.0.range(range)
1884 }
1885
1886 fn clear(&mut self) {
1888 self.0.clear();
1889 }
1890
1891 fn push_front(&mut self, event_meta: EventMeta) {
1893 if let Some(new_timeline_item_index) = event_meta.timeline_item_index {
1896 self.increment_all_timeline_item_index_after(new_timeline_item_index);
1897 }
1898
1899 self.0.push_front(event_meta)
1901 }
1902
1903 fn push_back(&mut self, event_meta: EventMeta) {
1905 if let Some(new_timeline_item_index) = event_meta.timeline_item_index {
1908 self.increment_all_timeline_item_index_after(new_timeline_item_index);
1909 }
1910
1911 self.0.push_back(event_meta)
1913 }
1914
1915 fn insert(&mut self, event_index: usize, event_meta: EventMeta) {
1917 if let Some(new_timeline_item_index) = event_meta.timeline_item_index {
1920 self.increment_all_timeline_item_index_after(new_timeline_item_index);
1921 }
1922
1923 self.0.insert(event_index, event_meta)
1925 }
1926
1927 fn remove(&mut self, event_index: usize) -> Option<EventMeta> {
1929 let event_meta = self.0.remove(event_index)?;
1931
1932 if let Some(removed_timeline_item_index) = event_meta.timeline_item_index {
1935 self.decrement_all_timeline_item_index_after(removed_timeline_item_index);
1936 }
1937
1938 Some(event_meta)
1939 }
1940
1941 #[cfg(test)]
1943 pub fn last(&self) -> Option<&EventMeta> {
1944 self.0.back()
1945 }
1946
1947 pub fn last_index(&self) -> Option<usize> {
1949 self.0.len().checked_sub(1)
1950 }
1951
1952 pub fn get_by_event_id_mut(&mut self, event_id: &EventId) -> Option<&mut EventMeta> {
1954 self.0.iter_mut().rev().find(|event_meta| event_meta.event_id == event_id)
1955 }
1956
1957 pub fn get_by_event_id(&self, event_id: &EventId) -> Option<&EventMeta> {
1959 self.0.iter().rev().find(|event_meta| event_meta.event_id == event_id)
1960 }
1961
1962 pub fn position_by_event_id(&self, event_id: &EventId) -> Option<usize> {
1964 self.0
1967 .iter()
1968 .enumerate()
1969 .rev()
1970 .find_map(|(i, event_meta)| (event_meta.event_id == event_id).then_some(i))
1971 }
1972
1973 fn increment_all_timeline_item_index_after(&mut self, new_timeline_item_index: usize) {
1976 for event_meta in self.0.iter_mut().rev() {
1984 if let Some(timeline_item_index) = event_meta.timeline_item_index.as_mut() {
1985 if *timeline_item_index >= new_timeline_item_index {
1986 *timeline_item_index += 1;
1987 } else {
1988 break;
1990 }
1991 }
1992 }
1993 }
1994
1995 fn decrement_all_timeline_item_index_after(&mut self, removed_timeline_item_index: usize) {
1998 for event_meta in self.0.iter_mut().rev() {
2006 if let Some(timeline_item_index) = event_meta.timeline_item_index.as_mut() {
2007 if *timeline_item_index > removed_timeline_item_index {
2008 *timeline_item_index -= 1;
2009 } else {
2010 break;
2012 }
2013 }
2014 }
2015 }
2016
2017 fn timeline_item_has_been_inserted_at(
2022 &mut self,
2023 new_timeline_item_index: usize,
2024 event_index: Option<usize>,
2025 ) {
2026 self.increment_all_timeline_item_index_after(new_timeline_item_index);
2027
2028 if let Some(event_index) = event_index
2029 && let Some(event_meta) = self.0.get_mut(event_index)
2030 {
2031 event_meta.timeline_item_index = Some(new_timeline_item_index);
2032 }
2033 }
2034
2035 fn timeline_item_has_been_removed_at(
2041 &mut self,
2042 timeline_item_index_to_remove: usize,
2043 ) -> Option<usize> {
2044 let mut found_event_index = None;
2045
2046 for (event_index, event_meta) in self.0.iter_mut().enumerate().rev() {
2047 if let Some(timeline_item_index) = event_meta.timeline_item_index.as_mut() {
2050 match (*timeline_item_index).cmp(&timeline_item_index_to_remove) {
2051 Ordering::Equal => {
2052 event_meta.timeline_item_index = None;
2056 found_event_index = Some(event_index);
2057 }
2058
2059 Ordering::Greater => {
2060 *timeline_item_index -= 1;
2061 }
2062
2063 Ordering::Less => {
2064 break;
2069 }
2070 }
2071 }
2072 }
2073
2074 found_event_index
2075 }
2076}
2077
2078#[cfg(test)]
2079mod all_remote_events_tests {
2080 use assert_matches::assert_matches;
2081 use ruma::event_id;
2082
2083 use super::{AllRemoteEvents, EventMeta};
2084
2085 fn event_meta(event_id: &str, timeline_item_index: Option<usize>) -> EventMeta {
2086 EventMeta {
2087 event_id: event_id.parse().unwrap(),
2088 sender: None,
2089 thread_root_id: None,
2090 timeline_item_index,
2091 visible: false,
2092 can_show_read_receipts: false,
2093 }
2094 }
2095
2096 macro_rules! assert_events {
2097 ( $events:ident, [ $( ( $event_id:literal, $timeline_item_index:expr ) ),* $(,)? ] ) => {
2098 let mut iter = $events .iter();
2099
2100 $(
2101 assert_matches!(iter.next(), Some(EventMeta { event_id, timeline_item_index, .. }) => {
2102 assert_eq!(event_id.as_str(), $event_id );
2103 assert_eq!(*timeline_item_index, $timeline_item_index );
2104 });
2105 )*
2106
2107 assert!(iter.next().is_none(), "Not all events have been asserted");
2108 }
2109 }
2110
2111 #[test]
2112 fn test_range() {
2113 let mut events = AllRemoteEvents::default();
2114
2115 events.push_back(event_meta("$ev0", None));
2117 events.push_back(event_meta("$ev1", None));
2118 events.push_back(event_meta("$ev2", None));
2119
2120 assert_eq!(events.iter().count(), 3);
2121
2122 assert_eq!(events.range(..).count(), 3);
2124 assert_eq!(events.range(1..).count(), 2);
2125 assert_eq!(events.range(0..=1).count(), 2);
2126
2127 let mut some_events = events.range(1..);
2129
2130 assert_matches!(some_events.next(), Some(EventMeta { event_id, .. }) => {
2131 assert_eq!(event_id.as_str(), "$ev1");
2132 });
2133 assert_matches!(some_events.next(), Some(EventMeta { event_id, .. }) => {
2134 assert_eq!(event_id.as_str(), "$ev2");
2135 });
2136 assert!(some_events.next().is_none());
2137 }
2138
2139 #[test]
2140 fn test_clear() {
2141 let mut events = AllRemoteEvents::default();
2142
2143 events.push_back(event_meta("$ev0", None));
2145 events.push_back(event_meta("$ev1", None));
2146 events.push_back(event_meta("$ev2", None));
2147
2148 assert_eq!(events.iter().count(), 3);
2149
2150 events.clear();
2152
2153 assert_eq!(events.iter().count(), 0);
2154 }
2155
2156 #[test]
2157 fn test_push_front() {
2158 let mut events = AllRemoteEvents::default();
2159
2160 events.push_front(event_meta("$ev0", Some(1)));
2162
2163 events.push_front(event_meta("$ev1", None));
2165
2166 events.push_front(event_meta("$ev2", Some(0)));
2168
2169 events.push_front(event_meta("$ev3", Some(0)));
2171
2172 assert_events!(
2173 events,
2174 [
2175 ("$ev3", Some(0)),
2177 ("$ev2", Some(1)),
2179 ("$ev1", None),
2181 ("$ev0", Some(3)),
2183 ]
2184 );
2185 }
2186
2187 #[test]
2188 fn test_push_back() {
2189 let mut events = AllRemoteEvents::default();
2190
2191 events.push_back(event_meta("$ev0", Some(0)));
2193
2194 events.push_back(event_meta("$ev1", None));
2196
2197 events.push_back(event_meta("$ev2", Some(1)));
2199
2200 events.push_back(event_meta("$ev3", Some(1)));
2204
2205 assert_events!(
2206 events,
2207 [
2208 ("$ev0", Some(0)),
2210 ("$ev1", None),
2212 ("$ev2", Some(2)),
2214 ("$ev3", Some(1)),
2216 ]
2217 );
2218 }
2219
2220 #[test]
2221 fn test_insert() {
2222 let mut events = AllRemoteEvents::default();
2223
2224 events.insert(0, event_meta("$ev0", Some(0)));
2226
2227 events.insert(1, event_meta("$ev1", None));
2229
2230 events.insert(2, event_meta("$ev2", Some(1)));
2232
2233 events.insert(0, event_meta("$ev3", Some(0)));
2235
2236 assert_events!(
2237 events,
2238 [
2239 ("$ev3", Some(0)),
2241 ("$ev0", Some(1)),
2243 ("$ev1", None),
2245 ("$ev2", Some(2)),
2247 ]
2248 );
2249 }
2250
2251 #[test]
2252 fn test_remove() {
2253 let mut events = AllRemoteEvents::default();
2254
2255 events.push_back(event_meta("$ev0", Some(0)));
2257 events.push_back(event_meta("$ev1", Some(1)));
2258 events.push_back(event_meta("$ev2", None));
2259 events.push_back(event_meta("$ev3", Some(2)));
2260
2261 assert_events!(
2263 events,
2264 [("$ev0", Some(0)), ("$ev1", Some(1)), ("$ev2", None), ("$ev3", Some(2))]
2265 );
2266
2267 events.remove(2); events.remove(1); assert_events!(
2272 events,
2273 [
2274 ("$ev0", Some(0)),
2275 ("$ev3", Some(1)),
2277 ]
2278 );
2279 }
2280
2281 #[test]
2282 fn test_last() {
2283 let mut events = AllRemoteEvents::default();
2284
2285 assert!(events.last().is_none());
2286 assert!(events.last_index().is_none());
2287
2288 events.push_back(event_meta("$ev0", Some(0)));
2290 events.push_back(event_meta("$ev1", Some(1)));
2291
2292 assert_matches!(events.last(), Some(EventMeta { event_id, .. }) => {
2293 assert_eq!(event_id.as_str(), "$ev1");
2294 });
2295 assert_eq!(events.last_index(), Some(1));
2296 }
2297
2298 #[test]
2299 fn test_get_by_event_by_mut() {
2300 let mut events = AllRemoteEvents::default();
2301
2302 events.push_back(event_meta("$ev0", Some(0)));
2304 events.push_back(event_meta("$ev1", Some(1)));
2305
2306 assert!(events.get_by_event_id_mut(event_id!("$ev0")).is_some());
2307 assert!(events.get_by_event_id_mut(event_id!("$ev42")).is_none());
2308 }
2309
2310 #[test]
2311 fn test_timeline_item_has_been_inserted_at() {
2312 let mut events = AllRemoteEvents::default();
2313
2314 events.push_back(event_meta("$ev0", Some(0)));
2316 events.push_back(event_meta("$ev1", Some(1)));
2317 events.push_back(event_meta("$ev2", None));
2318 events.push_back(event_meta("$ev3", None));
2319 events.push_back(event_meta("$ev4", Some(2)));
2320 events.push_back(event_meta("$ev5", Some(3)));
2321 events.push_back(event_meta("$ev6", None));
2322
2323 events.timeline_item_has_been_inserted_at(2, None);
2325
2326 assert_events!(
2327 events,
2328 [
2329 ("$ev0", Some(0)),
2330 ("$ev1", Some(1)),
2331 ("$ev2", None),
2332 ("$ev3", None),
2333 ("$ev4", Some(3)),
2335 ("$ev5", Some(4)),
2337 ("$ev6", None),
2338 ]
2339 );
2340
2341 events.timeline_item_has_been_inserted_at(5, Some(6));
2343
2344 assert_events!(
2345 events,
2346 [
2347 ("$ev0", Some(0)),
2348 ("$ev1", Some(1)),
2349 ("$ev2", None),
2350 ("$ev3", None),
2351 ("$ev4", Some(3)),
2352 ("$ev5", Some(4)),
2353 ("$ev6", Some(5)),
2355 ]
2356 );
2357 }
2358
2359 #[test]
2360 fn test_timeline_item_has_been_removed_at() {
2361 let mut events = AllRemoteEvents::default();
2362
2363 events.push_back(event_meta("$ev0", Some(0)));
2365 events.push_back(event_meta("$ev1", Some(1)));
2366 events.push_back(event_meta("$ev2", None));
2367 events.push_back(event_meta("$ev3", None));
2368 events.push_back(event_meta("$ev4", Some(3)));
2369 events.push_back(event_meta("$ev5", Some(4)));
2370 events.push_back(event_meta("$ev6", None));
2371
2372 events.timeline_item_has_been_removed_at(2);
2374
2375 assert_events!(
2376 events,
2377 [
2378 ("$ev0", Some(0)),
2379 ("$ev1", Some(1)),
2380 ("$ev2", None),
2381 ("$ev3", None),
2382 ("$ev4", Some(2)),
2384 ("$ev5", Some(3)),
2386 ("$ev6", None),
2387 ]
2388 );
2389
2390 events.timeline_item_has_been_removed_at(2);
2392
2393 assert_events!(
2394 events,
2395 [
2396 ("$ev0", Some(0)),
2397 ("$ev1", Some(1)),
2398 ("$ev2", None),
2399 ("$ev3", None),
2400 ("$ev4", None),
2402 ("$ev5", Some(2)),
2404 ("$ev6", None),
2405 ]
2406 );
2407
2408 events.timeline_item_has_been_removed_at(0);
2410
2411 assert_events!(
2412 events,
2413 [
2414 ("$ev0", None),
2416 ("$ev1", Some(0)),
2418 ("$ev2", None),
2419 ("$ev3", None),
2420 ("$ev4", None),
2421 ("$ev5", Some(1)),
2423 ("$ev6", None),
2424 ]
2425 );
2426 }
2427}