1#![allow(rustdoc::private_intra_doc_links)]
16
17#[cfg(test)]
32macro_rules! assert_items_eq {
33 ( @_ [ $iterator:ident ] { [-] $( $rest:tt )* } { $( $accumulator:tt )* } ) => {
34 assert_items_eq!(
35 @_
36 [ $iterator ]
37 { $( $rest )* }
38 {
39 $( $accumulator )*
40 {
41 let chunk = $iterator .next().expect("next chunk (expect gap)");
42 assert!(chunk.is_gap(), "chunk should be a gap");
43 }
44 }
45 )
46 };
47
48 ( @_ [ $iterator:ident ] { [ $( $item:expr ),* ] $( $rest:tt )* } { $( $accumulator:tt )* } ) => {
49 assert_items_eq!(
50 @_
51 [ $iterator ]
52 { $( $rest )* }
53 {
54 $( $accumulator )*
55 {
56 let chunk = $iterator .next().expect("next chunk (expect items)");
57 assert!(chunk.is_items(), "chunk should contain items");
58
59 let $crate::linked_chunk::ChunkContent::Items(items) = chunk.content() else {
60 unreachable!()
61 };
62
63 let mut items_iterator = items.iter();
64
65 $(
66 assert_eq!(items_iterator.next(), Some(& $item ));
67 )*
68
69 assert!(items_iterator.next().is_none(), "no more items");
70 }
71 }
72 )
73 };
74
75 ( @_ [ $iterator:ident ] {} { $( $accumulator:tt )* } ) => {
76 {
77 $( $accumulator )*
78 assert!( $iterator .next().is_none(), "no more chunks");
79 }
80 };
81
82 ( $linked_chunk:expr, $( $all:tt )* ) => {
83 assert_items_eq!(
84 @_
85 [ iterator ]
86 { $( $all )* }
87 {
88 let mut iterator = $linked_chunk.chunks();
89 }
90 )
91 }
92}
93
94mod as_vector;
95mod builder;
96pub mod relational;
97mod updates;
98
99use std::{
100 fmt,
101 marker::PhantomData,
102 ops::Not,
103 ptr::NonNull,
104 sync::atomic::{AtomicU64, Ordering},
105};
106
107pub use as_vector::*;
108pub use builder::*;
109pub use updates::*;
110
111#[derive(thiserror::Error, Debug)]
113pub enum Error {
114 #[error("The chunk identifier is invalid: `{identifier:?}`")]
116 InvalidChunkIdentifier {
117 identifier: ChunkIdentifier,
119 },
120
121 #[error("The chunk is a gap: `{identifier:?}`")]
123 ChunkIsAGap {
124 identifier: ChunkIdentifier,
126 },
127
128 #[error("The chunk is an item: `{identifier:?}`")]
130 ChunkIsItems {
131 identifier: ChunkIdentifier,
133 },
134
135 #[error("The item index is invalid: `{index}`")]
137 InvalidItemIndex {
138 index: usize,
140 },
141}
142
143struct Ends<const CHUNK_CAPACITY: usize, Item, Gap> {
148 first: NonNull<Chunk<CHUNK_CAPACITY, Item, Gap>>,
150 last: Option<NonNull<Chunk<CHUNK_CAPACITY, Item, Gap>>>,
152}
153
154impl<const CAP: usize, Item, Gap> Ends<CAP, Item, Gap> {
155 fn first_chunk(&self) -> &Chunk<CAP, Item, Gap> {
157 unsafe { self.first.as_ref() }
158 }
159
160 fn latest_chunk(&self) -> &Chunk<CAP, Item, Gap> {
162 unsafe { self.last.unwrap_or(self.first).as_ref() }
163 }
164
165 fn latest_chunk_mut(&mut self) -> &mut Chunk<CAP, Item, Gap> {
167 unsafe { self.last.as_mut().unwrap_or(&mut self.first).as_mut() }
168 }
169
170 fn chunk(&self, identifier: ChunkIdentifier) -> Option<&Chunk<CAP, Item, Gap>> {
172 let mut chunk = self.latest_chunk();
173
174 loop {
175 if chunk.identifier() == identifier {
176 return Some(chunk);
177 }
178
179 chunk = chunk.previous()?;
180 }
181 }
182
183 fn chunk_mut(&mut self, identifier: ChunkIdentifier) -> Option<&mut Chunk<CAP, Item, Gap>> {
185 let mut chunk = self.latest_chunk_mut();
186
187 loop {
188 if chunk.identifier() == identifier {
189 return Some(chunk);
190 }
191
192 chunk = chunk.previous_mut()?;
193 }
194 }
195
196 fn clear(&mut self) {
198 {
200 let mut current_chunk_ptr = self.last.or(Some(self.first));
202
203 while let Some(chunk_ptr) = current_chunk_ptr {
205 let previous_ptr = unsafe { chunk_ptr.as_ref() }.previous;
207
208 let _chunk_boxed = unsafe { Box::from_raw(chunk_ptr.as_ptr()) };
210
211 current_chunk_ptr = previous_ptr;
213 }
214
215 }
218
219 self.first = Chunk::new_items_leaked(ChunkIdentifierGenerator::FIRST_IDENTIFIER);
221
222 self.last = None;
224 }
225}
226
227pub struct LinkedChunk<const CHUNK_CAPACITY: usize, Item, Gap> {
234 links: Ends<CHUNK_CAPACITY, Item, Gap>,
236
237 chunk_identifier_generator: ChunkIdentifierGenerator,
239
240 updates: Option<ObservableUpdates<Item, Gap>>,
244
245 marker: PhantomData<Box<Chunk<CHUNK_CAPACITY, Item, Gap>>>,
247}
248
249impl<const CAP: usize, Item, Gap> Default for LinkedChunk<CAP, Item, Gap> {
250 fn default() -> Self {
251 Self::new()
252 }
253}
254
255impl<const CAP: usize, Item, Gap> LinkedChunk<CAP, Item, Gap> {
256 pub fn new() -> Self {
258 Self {
259 links: Ends {
260 first: Chunk::new_items_leaked(ChunkIdentifierGenerator::FIRST_IDENTIFIER),
262 last: None,
263 },
264 chunk_identifier_generator: ChunkIdentifierGenerator::new_from_scratch(),
265 updates: None,
266 marker: PhantomData,
267 }
268 }
269
270 pub fn new_with_update_history() -> Self {
276 let first_chunk_identifier = ChunkIdentifierGenerator::FIRST_IDENTIFIER;
277
278 let mut updates = ObservableUpdates::new();
279 updates.push(Update::NewItemsChunk {
280 previous: None,
281 new: first_chunk_identifier,
282 next: None,
283 });
284
285 Self {
286 links: Ends {
287 first: Chunk::new_items_leaked(first_chunk_identifier),
289 last: None,
290 },
291 chunk_identifier_generator: ChunkIdentifierGenerator::new_from_scratch(),
292 updates: Some(updates),
293 marker: PhantomData,
294 }
295 }
296
297 pub fn clear(&mut self) {
299 self.links.clear();
301
302 self.chunk_identifier_generator = ChunkIdentifierGenerator::new_from_scratch();
304
305 if let Some(updates) = self.updates.as_mut() {
307 updates.push(Update::Clear);
309 updates.push(Update::NewItemsChunk {
310 previous: None,
311 new: ChunkIdentifierGenerator::FIRST_IDENTIFIER,
312 next: None,
313 })
314 }
315 }
316
317 pub fn push_items_back<I>(&mut self, items: I)
323 where
324 Item: Clone,
325 Gap: Clone,
326 I: IntoIterator<Item = Item>,
327 I::IntoIter: ExactSizeIterator,
328 {
329 let items = items.into_iter();
330
331 let last_chunk = self.links.latest_chunk_mut();
332
333 let last_chunk =
335 last_chunk.push_items(items, &self.chunk_identifier_generator, &mut self.updates);
336
337 debug_assert!(last_chunk.is_last_chunk(), "`last_chunk` must be… the last chunk");
338
339 if last_chunk.is_first_chunk().not() {
342 self.links.last = Some(last_chunk.as_ptr());
345 }
346 }
347
348 pub fn push_gap_back(&mut self, content: Gap)
351 where
352 Item: Clone,
353 Gap: Clone,
354 {
355 let last_chunk = self.links.latest_chunk_mut();
356 last_chunk.insert_next(
357 Chunk::new_gap_leaked(self.chunk_identifier_generator.next(), content),
358 &mut self.updates,
359 );
360
361 self.links.last = last_chunk.next;
362 }
363
364 pub fn insert_items_at<I>(&mut self, items: I, position: Position) -> Result<(), Error>
369 where
370 Item: Clone,
371 Gap: Clone,
372 I: IntoIterator<Item = Item>,
373 I::IntoIter: ExactSizeIterator,
374 {
375 let chunk_identifier = position.chunk_identifier();
376 let item_index = position.index();
377
378 let chunk = self
379 .links
380 .chunk_mut(chunk_identifier)
381 .ok_or(Error::InvalidChunkIdentifier { identifier: chunk_identifier })?;
382
383 let chunk = match &mut chunk.content {
384 ChunkContent::Gap(..) => {
385 return Err(Error::ChunkIsAGap { identifier: chunk_identifier })
386 }
387
388 ChunkContent::Items(current_items) => {
389 let current_items_length = current_items.len();
390
391 if item_index > current_items_length {
392 return Err(Error::InvalidItemIndex { index: item_index });
393 }
394
395 let items = items.into_iter();
397
398 if item_index == current_items_length {
400 chunk
401 .push_items(items, &self.chunk_identifier_generator, &mut self.updates)
403 }
404 else {
406 if let Some(updates) = self.updates.as_mut() {
407 updates.push(Update::DetachLastItems {
408 at: Position(chunk_identifier, item_index),
409 });
410 }
411
412 let detached_items = current_items.split_off(item_index);
414
415 let chunk = chunk
416 .push_items(items, &self.chunk_identifier_generator, &mut self.updates);
418
419 if let Some(updates) = self.updates.as_mut() {
420 updates.push(Update::StartReattachItems);
421 }
422
423 let chunk = chunk
424 .push_items(
426 detached_items.into_iter(),
427 &self.chunk_identifier_generator,
428 &mut self.updates,
429 );
430
431 if let Some(updates) = self.updates.as_mut() {
432 updates.push(Update::EndReattachItems);
433 }
434
435 chunk
436 }
437 }
438 };
439
440 if chunk.is_first_chunk().not() && chunk.is_last_chunk() {
443 self.links.last = Some(chunk.as_ptr());
446 }
447
448 Ok(())
449 }
450
451 pub fn remove_item_at(
461 &mut self,
462 position: Position,
463 empty_chunk: EmptyChunk,
464 ) -> Result<Item, Error> {
465 let chunk_identifier = position.chunk_identifier();
466 let item_index = position.index();
467
468 let mut chunk_ptr = None;
469 let removed_item;
470
471 {
472 let chunk = self
473 .links
474 .chunk_mut(chunk_identifier)
475 .ok_or(Error::InvalidChunkIdentifier { identifier: chunk_identifier })?;
476
477 let can_unlink_chunk = match &mut chunk.content {
478 ChunkContent::Gap(..) => {
479 return Err(Error::ChunkIsAGap { identifier: chunk_identifier })
480 }
481
482 ChunkContent::Items(current_items) => {
483 let current_items_length = current_items.len();
484
485 if item_index > current_items_length {
486 return Err(Error::InvalidItemIndex { index: item_index });
487 }
488
489 removed_item = current_items.remove(item_index);
490
491 if let Some(updates) = self.updates.as_mut() {
492 updates
493 .push(Update::RemoveItem { at: Position(chunk_identifier, item_index) })
494 }
495
496 current_items.is_empty()
497 }
498 };
499
500 if empty_chunk.remove() && can_unlink_chunk && chunk.is_first_chunk().not() {
503 chunk.unlink(&mut self.updates);
505
506 chunk_ptr = Some(chunk.as_ptr());
507
508 if chunk.is_last_chunk() {
511 self.links.last = chunk.previous;
512 }
513 }
514
515 }
517
518 if let Some(chunk_ptr) = chunk_ptr {
519 let _chunk_boxed = unsafe { Box::from_raw(chunk_ptr.as_ptr()) };
526 }
527
528 Ok(removed_item)
529 }
530
531 pub fn replace_item_at(&mut self, position: Position, item: Item) -> Result<(), Error>
536 where
537 Item: Clone,
538 {
539 let chunk_identifier = position.chunk_identifier();
540 let item_index = position.index();
541
542 let chunk = self
543 .links
544 .chunk_mut(chunk_identifier)
545 .ok_or(Error::InvalidChunkIdentifier { identifier: chunk_identifier })?;
546
547 match &mut chunk.content {
548 ChunkContent::Gap(..) => {
549 return Err(Error::ChunkIsAGap { identifier: chunk_identifier })
550 }
551
552 ChunkContent::Items(current_items) => {
553 if item_index >= current_items.len() {
554 return Err(Error::InvalidItemIndex { index: item_index });
555 }
556
557 if let Some(updates) = self.updates.as_mut() {
559 updates.push(Update::ReplaceItem {
560 at: Position(chunk_identifier, item_index),
561 item: item.clone(),
562 });
563 }
564
565 current_items[item_index] = item;
566 }
567 }
568
569 Ok(())
570 }
571
572 pub fn insert_gap_at(&mut self, content: Gap, position: Position) -> Result<(), Error>
577 where
578 Item: Clone,
579 Gap: Clone,
580 {
581 let chunk_identifier = position.chunk_identifier();
582 let item_index = position.index();
583
584 let chunk = self
585 .links
586 .chunk_mut(chunk_identifier)
587 .ok_or(Error::InvalidChunkIdentifier { identifier: chunk_identifier })?;
588
589 if item_index == 0 && chunk.is_items() && chunk.previous.is_some() {
596 let previous_chunk = chunk
597 .previous_mut()
598 .expect("Previous chunk must be present");
601
602 previous_chunk.insert_next(
603 Chunk::new_gap_leaked(self.chunk_identifier_generator.next(), content),
604 &mut self.updates,
605 );
606
607 return Ok(());
611 }
612
613 let chunk = match &mut chunk.content {
614 ChunkContent::Gap(..) => {
615 return Err(Error::ChunkIsAGap { identifier: chunk_identifier });
616 }
617
618 ChunkContent::Items(current_items) => {
619 let current_items_length = current_items.len();
620
621 if item_index >= current_items_length {
622 return Err(Error::InvalidItemIndex { index: item_index });
623 }
624
625 if let Some(updates) = self.updates.as_mut() {
626 updates.push(Update::DetachLastItems {
627 at: Position(chunk_identifier, item_index),
628 });
629 }
630
631 let detached_items = current_items.split_off(item_index);
633
634 let chunk = chunk
635 .insert_next(
637 Chunk::new_gap_leaked(self.chunk_identifier_generator.next(), content),
638 &mut self.updates,
639 );
640
641 if let Some(updates) = self.updates.as_mut() {
642 updates.push(Update::StartReattachItems);
643 }
644
645 let chunk = chunk
646 .insert_next(
648 Chunk::new_items_leaked(self.chunk_identifier_generator.next()),
649 &mut self.updates,
650 )
651 .push_items(
653 detached_items.into_iter(),
654 &self.chunk_identifier_generator,
655 &mut self.updates,
656 );
657
658 if let Some(updates) = self.updates.as_mut() {
659 updates.push(Update::EndReattachItems);
660 }
661
662 chunk
663 }
664 };
665
666 if chunk.is_first_chunk().not() && chunk.is_last_chunk() {
669 self.links.last = Some(chunk.as_ptr());
672 }
673
674 Ok(())
675 }
676
677 pub fn remove_gap_at(
682 &mut self,
683 chunk_identifier: ChunkIdentifier,
684 ) -> Result<Option<Position>, Error> {
685 let chunk = self
686 .links
687 .chunk_mut(chunk_identifier)
688 .ok_or(Error::InvalidChunkIdentifier { identifier: chunk_identifier })?;
689
690 if chunk.is_items() {
691 return Err(Error::ChunkIsItems { identifier: chunk_identifier });
692 };
693
694 let next = chunk.next;
695
696 chunk.unlink(&mut self.updates);
697
698 let chunk_ptr = chunk.as_ptr();
699
700 debug_assert!(chunk.is_first_chunk().not(), "A gap cannot be the first chunk");
702
703 if chunk.is_last_chunk() {
704 self.links.last = chunk.previous;
705 }
706
707 let _chunk_boxed = unsafe { Box::from_raw(chunk_ptr.as_ptr()) };
710
711 Ok(next.map(|next| {
713 let chunk = unsafe { next.as_ref() };
714 chunk.first_position()
715 }))
716 }
717
718 pub fn replace_gap_at<I>(
726 &mut self,
727 items: I,
728 chunk_identifier: ChunkIdentifier,
729 ) -> Result<&Chunk<CAP, Item, Gap>, Error>
730 where
731 Item: Clone,
732 Gap: Clone,
733 I: IntoIterator<Item = Item>,
734 I::IntoIter: ExactSizeIterator,
735 {
736 let chunk_ptr;
737 let new_chunk_ptr;
738
739 {
740 let chunk = self
741 .links
742 .chunk_mut(chunk_identifier)
743 .ok_or(Error::InvalidChunkIdentifier { identifier: chunk_identifier })?;
744
745 if chunk.is_items() {
746 return Err(Error::ChunkIsItems { identifier: chunk_identifier });
747 };
748
749 debug_assert!(chunk.is_first_chunk().not(), "A gap cannot be the first chunk");
750
751 let maybe_last_chunk_ptr = {
752 let items = items.into_iter();
753
754 let last_inserted_chunk = chunk
755 .insert_next(
757 Chunk::new_items_leaked(self.chunk_identifier_generator.next()),
758 &mut self.updates,
759 )
760 .push_items(items, &self.chunk_identifier_generator, &mut self.updates);
762
763 last_inserted_chunk.is_last_chunk().then(|| last_inserted_chunk.as_ptr())
764 };
765
766 new_chunk_ptr = chunk
767 .next
768 .unwrap();
770
771 chunk.unlink(&mut self.updates);
773
774 chunk_ptr = chunk.as_ptr();
776
777 if let Some(last_chunk_ptr) = maybe_last_chunk_ptr {
779 self.links.last = Some(last_chunk_ptr);
780 }
781
782 }
784
785 let _chunk_boxed = unsafe { Box::from_raw(chunk_ptr.as_ptr()) };
790
791 Ok(
792 unsafe { new_chunk_ptr.as_ref() },
796 )
797 }
798
799 pub fn chunk_identifier<'a, P>(&'a self, mut predicate: P) -> Option<ChunkIdentifier>
801 where
802 P: FnMut(&'a Chunk<CAP, Item, Gap>) -> bool,
803 {
804 self.rchunks().find_map(|chunk| predicate(chunk).then(|| chunk.identifier()))
805 }
806
807 pub fn item_position<'a, P>(&'a self, mut predicate: P) -> Option<Position>
809 where
810 P: FnMut(&'a Item) -> bool,
811 {
812 self.ritems().find_map(|(item_position, item)| predicate(item).then_some(item_position))
813 }
814
815 pub fn rchunks(&self) -> IterBackward<'_, CAP, Item, Gap> {
819 IterBackward::new(self.links.latest_chunk())
820 }
821
822 pub fn chunks(&self) -> Iter<'_, CAP, Item, Gap> {
826 Iter::new(self.links.first_chunk())
827 }
828
829 pub fn rchunks_from(
834 &self,
835 identifier: ChunkIdentifier,
836 ) -> Result<IterBackward<'_, CAP, Item, Gap>, Error> {
837 Ok(IterBackward::new(
838 self.links.chunk(identifier).ok_or(Error::InvalidChunkIdentifier { identifier })?,
839 ))
840 }
841
842 pub fn chunks_from(
847 &self,
848 identifier: ChunkIdentifier,
849 ) -> Result<Iter<'_, CAP, Item, Gap>, Error> {
850 Ok(Iter::new(
851 self.links.chunk(identifier).ok_or(Error::InvalidChunkIdentifier { identifier })?,
852 ))
853 }
854
855 pub fn ritems(&self) -> impl Iterator<Item = (Position, &Item)> {
859 self.ritems_from(self.links.latest_chunk().last_position())
860 .expect("`ritems_from` cannot fail because at least one empty chunk must exist")
861 }
862
863 pub fn items(&self) -> impl Iterator<Item = (Position, &Item)> {
867 let first_chunk = self.links.first_chunk();
868
869 self.items_from(first_chunk.first_position())
870 .expect("`items` cannot fail because at least one empty chunk must exist")
871 }
872
873 pub fn ritems_from(
877 &self,
878 position: Position,
879 ) -> Result<impl Iterator<Item = (Position, &Item)>, Error> {
880 Ok(self
881 .rchunks_from(position.chunk_identifier())?
882 .filter_map(|chunk| match &chunk.content {
883 ChunkContent::Gap(..) => None,
884 ChunkContent::Items(items) => {
885 let identifier = chunk.identifier();
886
887 Some(
888 items.iter().enumerate().rev().map(move |(item_index, item)| {
889 (Position(identifier, item_index), item)
890 }),
891 )
892 }
893 })
894 .flatten()
895 .skip_while({
896 let expected_index = position.index();
897
898 move |(Position(chunk_identifier, item_index), _item)| {
899 *chunk_identifier == position.chunk_identifier()
900 && *item_index != expected_index
901 }
902 }))
903 }
904
905 pub fn items_from(
909 &self,
910 position: Position,
911 ) -> Result<impl Iterator<Item = (Position, &Item)>, Error> {
912 Ok(self
913 .chunks_from(position.chunk_identifier())?
914 .filter_map(|chunk| match &chunk.content {
915 ChunkContent::Gap(..) => None,
916 ChunkContent::Items(items) => {
917 let identifier = chunk.identifier();
918
919 Some(
920 items.iter().enumerate().map(move |(item_index, item)| {
921 (Position(identifier, item_index), item)
922 }),
923 )
924 }
925 })
926 .flatten()
927 .skip(position.index()))
928 }
929
930 #[must_use]
942 pub fn updates(&mut self) -> Option<&mut ObservableUpdates<Item, Gap>> {
943 self.updates.as_mut()
944 }
945
946 pub fn as_vector(&mut self) -> Option<AsVector<Item, Gap>> {
953 let (updates, token) = self
954 .updates
955 .as_mut()
956 .map(|updates| (updates.inner.clone(), updates.new_reader_token()))?;
957 let chunk_iterator = self.chunks();
958
959 Some(AsVector::new(updates, token, chunk_iterator))
960 }
961
962 pub fn num_items(&self) -> usize {
964 self.items().count()
965 }
966}
967
968impl<const CAP: usize, Item, Gap> Drop for LinkedChunk<CAP, Item, Gap> {
969 fn drop(&mut self) {
970 self.links.clear();
975 }
976}
977
978unsafe impl<const CAP: usize, Item: Send, Gap: Send> Send for LinkedChunk<CAP, Item, Gap> {}
982
983unsafe impl<const CAP: usize, Item: Sync, Gap: Sync> Sync for LinkedChunk<CAP, Item, Gap> {}
987
988struct ChunkIdentifierGenerator {
998 next: AtomicU64,
999}
1000
1001impl ChunkIdentifierGenerator {
1002 const FIRST_IDENTIFIER: ChunkIdentifier = ChunkIdentifier(0);
1004
1005 pub fn new_from_scratch() -> Self {
1008 Self { next: AtomicU64::new(Self::FIRST_IDENTIFIER.0) }
1009 }
1010
1011 pub fn new_from_previous_chunk_identifier(last_chunk_identifier: ChunkIdentifier) -> Self {
1014 Self { next: AtomicU64::new(last_chunk_identifier.0) }
1015 }
1016
1017 pub fn next(&self) -> ChunkIdentifier {
1022 let previous = self.next.fetch_add(1, Ordering::Relaxed);
1023
1024 if previous == u64::MAX {
1027 panic!("No more chunk identifiers available. Congrats, you did it. 2^64 identifiers have been consumed.")
1028 }
1029
1030 ChunkIdentifier(previous + 1)
1031 }
1032}
1033
1034#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
1040#[repr(transparent)]
1041pub struct ChunkIdentifier(u64);
1042
1043impl ChunkIdentifier {
1044 pub fn new(identifier: u64) -> Self {
1046 Self(identifier)
1047 }
1048
1049 pub fn index(&self) -> u64 {
1051 self.0
1052 }
1053}
1054
1055impl PartialEq<u64> for ChunkIdentifier {
1056 fn eq(&self, other: &u64) -> bool {
1057 self.0 == *other
1058 }
1059}
1060
1061#[derive(Copy, Clone, Debug, PartialEq)]
1065pub struct Position(ChunkIdentifier, usize);
1066
1067impl Position {
1068 pub fn new(chunk_identifier: ChunkIdentifier, index: usize) -> Self {
1070 Self(chunk_identifier, index)
1071 }
1072
1073 pub fn chunk_identifier(&self) -> ChunkIdentifier {
1075 self.0
1076 }
1077
1078 pub fn index(&self) -> usize {
1080 self.1
1081 }
1082
1083 pub fn decrement_index(&mut self) {
1089 self.1 = self.1.checked_sub(1).expect("Cannot decrement the index because it's already 0");
1090 }
1091
1092 pub fn increment_index(&mut self) {
1099 self.1 = self.1.checked_add(1).expect("Cannot increment the index because it's too large");
1100 }
1101}
1102
1103#[derive(Debug)]
1106pub struct IterBackward<'a, const CAP: usize, Item, Gap> {
1107 chunk: Option<&'a Chunk<CAP, Item, Gap>>,
1108}
1109
1110impl<'a, const CAP: usize, Item, Gap> IterBackward<'a, CAP, Item, Gap> {
1111 fn new(from_chunk: &'a Chunk<CAP, Item, Gap>) -> Self {
1113 Self { chunk: Some(from_chunk) }
1114 }
1115}
1116
1117impl<'a, const CAP: usize, Item, Gap> Iterator for IterBackward<'a, CAP, Item, Gap> {
1118 type Item = &'a Chunk<CAP, Item, Gap>;
1119
1120 fn next(&mut self) -> Option<Self::Item> {
1121 self.chunk.inspect(|chunk| self.chunk = chunk.previous())
1122 }
1123}
1124
1125#[derive(Debug)]
1128pub struct Iter<'a, const CAP: usize, Item, Gap> {
1129 chunk: Option<&'a Chunk<CAP, Item, Gap>>,
1130}
1131
1132impl<'a, const CAP: usize, Item, Gap> Iter<'a, CAP, Item, Gap> {
1133 fn new(from_chunk: &'a Chunk<CAP, Item, Gap>) -> Self {
1135 Self { chunk: Some(from_chunk) }
1136 }
1137}
1138
1139impl<'a, const CAP: usize, Item, Gap> Iterator for Iter<'a, CAP, Item, Gap> {
1140 type Item = &'a Chunk<CAP, Item, Gap>;
1141
1142 fn next(&mut self) -> Option<Self::Item> {
1143 self.chunk.inspect(|chunk| self.chunk = chunk.next())
1144 }
1145}
1146
1147#[derive(Clone, Debug)]
1149pub enum ChunkContent<Item, Gap> {
1150 Gap(Gap),
1153
1154 Items(Vec<Item>),
1156}
1157
1158pub struct Chunk<const CAPACITY: usize, Item, Gap> {
1160 previous: Option<NonNull<Chunk<CAPACITY, Item, Gap>>>,
1162
1163 next: Option<NonNull<Chunk<CAPACITY, Item, Gap>>>,
1165
1166 identifier: ChunkIdentifier,
1168
1169 content: ChunkContent<Item, Gap>,
1171}
1172
1173impl<const CAPACITY: usize, Item, Gap> Chunk<CAPACITY, Item, Gap> {
1174 fn new_gap(identifier: ChunkIdentifier, content: Gap) -> Self {
1176 Self::new(identifier, ChunkContent::Gap(content))
1177 }
1178
1179 fn new_items(identifier: ChunkIdentifier) -> Self {
1181 Self::new(identifier, ChunkContent::Items(Vec::with_capacity(CAPACITY)))
1182 }
1183
1184 fn new(identifier: ChunkIdentifier, content: ChunkContent<Item, Gap>) -> Self {
1185 Self { previous: None, next: None, identifier, content }
1186 }
1187
1188 fn new_leaked(identifier: ChunkIdentifier, content: ChunkContent<Item, Gap>) -> NonNull<Self> {
1190 let chunk = Self::new(identifier, content);
1191 let chunk_box = Box::new(chunk);
1192
1193 NonNull::from(Box::leak(chunk_box))
1194 }
1195
1196 fn new_gap_leaked(identifier: ChunkIdentifier, content: Gap) -> NonNull<Self> {
1198 let chunk = Self::new_gap(identifier, content);
1199 let chunk_box = Box::new(chunk);
1200
1201 NonNull::from(Box::leak(chunk_box))
1202 }
1203
1204 fn new_items_leaked(identifier: ChunkIdentifier) -> NonNull<Self> {
1206 let chunk = Self::new_items(identifier);
1207 let chunk_box = Box::new(chunk);
1208
1209 NonNull::from(Box::leak(chunk_box))
1210 }
1211
1212 pub fn as_ptr(&self) -> NonNull<Self> {
1214 NonNull::from(self)
1215 }
1216
1217 pub fn is_gap(&self) -> bool {
1219 matches!(self.content, ChunkContent::Gap(..))
1220 }
1221
1222 pub fn is_items(&self) -> bool {
1224 !self.is_gap()
1225 }
1226
1227 fn is_first_chunk(&self) -> bool {
1229 self.previous.is_none()
1230 }
1231
1232 fn is_last_chunk(&self) -> bool {
1234 self.next.is_none()
1235 }
1236
1237 pub fn identifier(&self) -> ChunkIdentifier {
1239 self.identifier
1240 }
1241
1242 pub fn content(&self) -> &ChunkContent<Item, Gap> {
1244 &self.content
1245 }
1246
1247 pub fn first_position(&self) -> Position {
1251 Position(self.identifier(), 0)
1252 }
1253
1254 pub fn last_position(&self) -> Position {
1258 let identifier = self.identifier();
1259
1260 match &self.content {
1261 ChunkContent::Gap(..) => Position(identifier, 0),
1262 ChunkContent::Items(items) => Position(identifier, items.len().saturating_sub(1)),
1263 }
1264 }
1265
1266 fn len(&self) -> usize {
1270 match &self.content {
1271 ChunkContent::Gap(..) => 0,
1272 ChunkContent::Items(items) => items.len(),
1273 }
1274 }
1275
1276 fn push_items<I>(
1288 &mut self,
1289 mut new_items: I,
1290 chunk_identifier_generator: &ChunkIdentifierGenerator,
1291 updates: &mut Option<ObservableUpdates<Item, Gap>>,
1292 ) -> &mut Self
1293 where
1294 I: Iterator<Item = Item> + ExactSizeIterator,
1295 Item: Clone,
1296 Gap: Clone,
1297 {
1298 let number_of_new_items = new_items.len();
1299 let chunk_length = self.len();
1300
1301 if number_of_new_items == 0 {
1303 return self;
1304 }
1305
1306 let identifier = self.identifier();
1307
1308 match &mut self.content {
1309 ChunkContent::Gap(..) => {
1312 self
1313 .insert_next(Self::new_items_leaked(chunk_identifier_generator.next()), updates)
1315 .push_items(new_items, chunk_identifier_generator, updates)
1318 }
1319
1320 ChunkContent::Items(items) => {
1321 let free_space = CAPACITY.saturating_sub(chunk_length);
1323
1324 if number_of_new_items <= free_space {
1326 let start = items.len();
1327 items.extend(new_items);
1328
1329 if let Some(updates) = updates.as_mut() {
1330 updates.push(Update::PushItems {
1331 at: Position(identifier, start),
1332 items: items[start..].to_vec(),
1333 });
1334 }
1335
1336 self
1338 } else {
1339 if free_space > 0 {
1340 let start = items.len();
1342 items.extend(new_items.by_ref().take(free_space));
1343
1344 if let Some(updates) = updates.as_mut() {
1345 updates.push(Update::PushItems {
1346 at: Position(identifier, start),
1347 items: items[start..].to_vec(),
1348 });
1349 }
1350 }
1351
1352 self
1353 .insert_next(
1355 Self::new_items_leaked(chunk_identifier_generator.next()),
1356 updates,
1357 )
1358 .push_items(new_items, chunk_identifier_generator, updates)
1361 }
1362 }
1363 }
1364 }
1365
1366 fn insert_next(
1371 &mut self,
1372 mut new_chunk_ptr: NonNull<Self>,
1373 updates: &mut Option<ObservableUpdates<Item, Gap>>,
1374 ) -> &mut Self
1375 where
1376 Gap: Clone,
1377 {
1378 let new_chunk = unsafe { new_chunk_ptr.as_mut() };
1379
1380 if let Some(next_chunk) = self.next_mut() {
1382 next_chunk.previous = Some(new_chunk_ptr);
1384
1385 new_chunk.next = self.next;
1387 }
1388
1389 self.next = Some(new_chunk_ptr);
1391 new_chunk.previous = Some(self.as_ptr());
1393
1394 if let Some(updates) = updates.as_mut() {
1395 let previous = new_chunk.previous().map(Chunk::identifier);
1396 let new = new_chunk.identifier();
1397 let next = new_chunk.next().map(Chunk::identifier);
1398
1399 match new_chunk.content() {
1400 ChunkContent::Gap(gap) => {
1401 updates.push(Update::NewGapChunk { previous, new, next, gap: gap.clone() })
1402 }
1403
1404 ChunkContent::Items(..) => {
1405 updates.push(Update::NewItemsChunk { previous, new, next })
1406 }
1407 }
1408 }
1409
1410 new_chunk
1411 }
1412
1413 fn unlink(&mut self, updates: &mut Option<ObservableUpdates<Item, Gap>>) {
1418 let previous_ptr = self.previous;
1419 let next_ptr = self.next;
1420
1421 if let Some(previous) = self.previous_mut() {
1422 previous.next = next_ptr;
1423 }
1424
1425 if let Some(next) = self.next_mut() {
1426 next.previous = previous_ptr;
1427 }
1428
1429 if let Some(updates) = updates.as_mut() {
1430 updates.push(Update::RemoveChunk(self.identifier()));
1431 }
1432 }
1433
1434 fn previous(&self) -> Option<&Self> {
1436 self.previous.map(|non_null| unsafe { non_null.as_ref() })
1437 }
1438
1439 fn previous_mut(&mut self) -> Option<&mut Self> {
1441 self.previous.as_mut().map(|non_null| unsafe { non_null.as_mut() })
1442 }
1443
1444 fn next(&self) -> Option<&Self> {
1446 self.next.map(|non_null| unsafe { non_null.as_ref() })
1447 }
1448
1449 fn next_mut(&mut self) -> Option<&mut Self> {
1451 self.next.as_mut().map(|non_null| unsafe { non_null.as_mut() })
1452 }
1453}
1454
1455impl<const CAP: usize, Item, Gap> fmt::Debug for LinkedChunk<CAP, Item, Gap>
1456where
1457 Item: fmt::Debug,
1458 Gap: fmt::Debug,
1459{
1460 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1461 formatter
1462 .debug_struct("LinkedChunk")
1463 .field("first (deref)", unsafe { self.links.first.as_ref() })
1464 .field("last", &self.links.last)
1465 .finish_non_exhaustive()
1466 }
1467}
1468
1469impl<const CAP: usize, Item, Gap> fmt::Debug for Chunk<CAP, Item, Gap>
1470where
1471 Item: fmt::Debug,
1472 Gap: fmt::Debug,
1473{
1474 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1475 formatter
1476 .debug_struct("Chunk")
1477 .field("identifier", &self.identifier)
1478 .field("content", &self.content)
1479 .field("previous", &self.previous)
1480 .field("ptr", &std::ptr::from_ref(self))
1481 .field("next", &self.next)
1482 .field("next (deref)", &self.next.as_ref().map(|non_null| unsafe { non_null.as_ref() }))
1483 .finish()
1484 }
1485}
1486
1487#[derive(Debug)]
1489pub enum EmptyChunk {
1490 Keep,
1492
1493 Remove,
1495}
1496
1497impl EmptyChunk {
1498 fn remove(&self) -> bool {
1499 matches!(self, Self::Remove)
1500 }
1501}
1502
1503#[derive(Clone, Debug)]
1509pub struct RawChunk<Item, Gap> {
1510 pub content: ChunkContent<Item, Gap>,
1512
1513 pub previous: Option<ChunkIdentifier>,
1515
1516 pub identifier: ChunkIdentifier,
1518
1519 pub next: Option<ChunkIdentifier>,
1521}
1522
1523#[cfg(test)]
1524mod tests {
1525 use std::{
1526 ops::Not,
1527 sync::{atomic::Ordering, Arc},
1528 };
1529
1530 use assert_matches::assert_matches;
1531
1532 use super::{
1533 Chunk, ChunkContent, ChunkIdentifier, ChunkIdentifierGenerator, EmptyChunk, Error,
1534 LinkedChunk, Position,
1535 };
1536
1537 #[test]
1538 fn test_chunk_identifier_generator() {
1539 let generator = ChunkIdentifierGenerator::new_from_scratch();
1540
1541 assert_eq!(generator.next(), ChunkIdentifier(1));
1542 assert_eq!(generator.next(), ChunkIdentifier(2));
1543 assert_eq!(generator.next(), ChunkIdentifier(3));
1544 assert_eq!(generator.next(), ChunkIdentifier(4));
1545
1546 let generator =
1547 ChunkIdentifierGenerator::new_from_previous_chunk_identifier(ChunkIdentifier(42));
1548
1549 assert_eq!(generator.next(), ChunkIdentifier(43));
1550 assert_eq!(generator.next(), ChunkIdentifier(44));
1551 assert_eq!(generator.next(), ChunkIdentifier(45));
1552 assert_eq!(generator.next(), ChunkIdentifier(46));
1553 }
1554
1555 #[test]
1556 fn test_empty() {
1557 let items = LinkedChunk::<3, char, ()>::new();
1558
1559 assert_eq!(items.num_items(), 0);
1560
1561 }
1564
1565 #[test]
1566 fn test_updates() {
1567 assert!(LinkedChunk::<3, char, ()>::new().updates().is_none());
1568 assert!(LinkedChunk::<3, char, ()>::new_with_update_history().updates().is_some());
1569 }
1570
1571 #[test]
1572 fn test_new_with_initial_update() {
1573 use super::Update::*;
1574
1575 let mut linked_chunk = LinkedChunk::<3, char, ()>::new_with_update_history();
1576
1577 assert_eq!(
1578 linked_chunk.updates().unwrap().take(),
1579 &[NewItemsChunk { previous: None, new: ChunkIdentifier(0), next: None }]
1580 );
1581 }
1582
1583 #[test]
1584 fn test_push_items() {
1585 use super::Update::*;
1586
1587 let mut linked_chunk = LinkedChunk::<3, char, ()>::new_with_update_history();
1588
1589 let _ = linked_chunk.updates().unwrap().take();
1591
1592 linked_chunk.push_items_back(['a']);
1593
1594 assert_items_eq!(linked_chunk, ['a']);
1595 assert_eq!(
1596 linked_chunk.updates().unwrap().take(),
1597 &[PushItems { at: Position(ChunkIdentifier(0), 0), items: vec!['a'] }]
1598 );
1599
1600 linked_chunk.push_items_back(['b', 'c']);
1601 assert_items_eq!(linked_chunk, ['a', 'b', 'c']);
1602 assert_eq!(
1603 linked_chunk.updates().unwrap().take(),
1604 &[PushItems { at: Position(ChunkIdentifier(0), 1), items: vec!['b', 'c'] }]
1605 );
1606
1607 linked_chunk.push_items_back(['d', 'e']);
1608 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] ['d', 'e']);
1609 assert_eq!(
1610 linked_chunk.updates().unwrap().take(),
1611 &[
1612 NewItemsChunk {
1613 previous: Some(ChunkIdentifier(0)),
1614 new: ChunkIdentifier(1),
1615 next: None
1616 },
1617 PushItems { at: Position(ChunkIdentifier(1), 0), items: vec!['d', 'e'] }
1618 ]
1619 );
1620
1621 linked_chunk.push_items_back(['f', 'g', 'h', 'i', 'j']);
1622 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] ['d', 'e', 'f'] ['g', 'h', 'i'] ['j']);
1623 assert_eq!(
1624 linked_chunk.updates().unwrap().take(),
1625 &[
1626 PushItems { at: Position(ChunkIdentifier(1), 2), items: vec!['f'] },
1627 NewItemsChunk {
1628 previous: Some(ChunkIdentifier(1)),
1629 new: ChunkIdentifier(2),
1630 next: None,
1631 },
1632 PushItems { at: Position(ChunkIdentifier(2), 0), items: vec!['g', 'h', 'i'] },
1633 NewItemsChunk {
1634 previous: Some(ChunkIdentifier(2)),
1635 new: ChunkIdentifier(3),
1636 next: None,
1637 },
1638 PushItems { at: Position(ChunkIdentifier(3), 0), items: vec!['j'] },
1639 ]
1640 );
1641
1642 assert_eq!(linked_chunk.num_items(), 10);
1643 }
1644
1645 #[test]
1646 fn test_push_gap() {
1647 use super::Update::*;
1648
1649 let mut linked_chunk = LinkedChunk::<3, char, ()>::new_with_update_history();
1650
1651 let _ = linked_chunk.updates().unwrap().take();
1653
1654 linked_chunk.push_items_back(['a']);
1655 assert_items_eq!(linked_chunk, ['a']);
1656 assert_eq!(
1657 linked_chunk.updates().unwrap().take(),
1658 &[PushItems { at: Position(ChunkIdentifier(0), 0), items: vec!['a'] }]
1659 );
1660
1661 linked_chunk.push_gap_back(());
1662 assert_items_eq!(linked_chunk, ['a'] [-]);
1663 assert_eq!(
1664 linked_chunk.updates().unwrap().take(),
1665 &[NewGapChunk {
1666 previous: Some(ChunkIdentifier(0)),
1667 new: ChunkIdentifier(1),
1668 next: None,
1669 gap: (),
1670 }]
1671 );
1672
1673 linked_chunk.push_items_back(['b', 'c', 'd', 'e']);
1674 assert_items_eq!(linked_chunk, ['a'] [-] ['b', 'c', 'd'] ['e']);
1675 assert_eq!(
1676 linked_chunk.updates().unwrap().take(),
1677 &[
1678 NewItemsChunk {
1679 previous: Some(ChunkIdentifier(1)),
1680 new: ChunkIdentifier(2),
1681 next: None,
1682 },
1683 PushItems { at: Position(ChunkIdentifier(2), 0), items: vec!['b', 'c', 'd'] },
1684 NewItemsChunk {
1685 previous: Some(ChunkIdentifier(2)),
1686 new: ChunkIdentifier(3),
1687 next: None,
1688 },
1689 PushItems { at: Position(ChunkIdentifier(3), 0), items: vec!['e'] },
1690 ]
1691 );
1692
1693 linked_chunk.push_gap_back(());
1694 linked_chunk.push_gap_back(()); assert_items_eq!(linked_chunk, ['a'] [-] ['b', 'c', 'd'] ['e'] [-] [-]);
1696 assert_eq!(
1697 linked_chunk.updates().unwrap().take(),
1698 &[
1699 NewGapChunk {
1700 previous: Some(ChunkIdentifier(3)),
1701 new: ChunkIdentifier(4),
1702 next: None,
1703 gap: (),
1704 },
1705 NewGapChunk {
1706 previous: Some(ChunkIdentifier(4)),
1707 new: ChunkIdentifier(5),
1708 next: None,
1709 gap: (),
1710 }
1711 ]
1712 );
1713
1714 linked_chunk.push_items_back(['f', 'g', 'h', 'i']);
1715 assert_items_eq!(linked_chunk, ['a'] [-] ['b', 'c', 'd'] ['e'] [-] [-] ['f', 'g', 'h'] ['i']);
1716 assert_eq!(
1717 linked_chunk.updates().unwrap().take(),
1718 &[
1719 NewItemsChunk {
1720 previous: Some(ChunkIdentifier(5)),
1721 new: ChunkIdentifier(6),
1722 next: None,
1723 },
1724 PushItems { at: Position(ChunkIdentifier(6), 0), items: vec!['f', 'g', 'h'] },
1725 NewItemsChunk {
1726 previous: Some(ChunkIdentifier(6)),
1727 new: ChunkIdentifier(7),
1728 next: None,
1729 },
1730 PushItems { at: Position(ChunkIdentifier(7), 0), items: vec!['i'] },
1731 ]
1732 );
1733
1734 assert_eq!(linked_chunk.num_items(), 9);
1735 }
1736
1737 #[test]
1738 fn test_identifiers_and_positions() {
1739 let mut linked_chunk = LinkedChunk::<3, char, ()>::new();
1740 linked_chunk.push_items_back(['a', 'b', 'c', 'd', 'e', 'f']);
1741 linked_chunk.push_gap_back(());
1742 linked_chunk.push_items_back(['g', 'h', 'i', 'j']);
1743 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] ['d', 'e', 'f'] [-] ['g', 'h', 'i'] ['j']);
1744
1745 assert_eq!(linked_chunk.chunk_identifier(Chunk::is_gap), Some(ChunkIdentifier(2)));
1746 assert_eq!(
1747 linked_chunk.item_position(|item| *item == 'e'),
1748 Some(Position(ChunkIdentifier(1), 1))
1749 );
1750 }
1751
1752 #[test]
1753 fn test_rchunks() {
1754 let mut linked_chunk = LinkedChunk::<2, char, ()>::new();
1755 linked_chunk.push_items_back(['a', 'b']);
1756 linked_chunk.push_gap_back(());
1757 linked_chunk.push_items_back(['c', 'd', 'e']);
1758
1759 let mut iterator = linked_chunk.rchunks();
1760
1761 assert_matches!(
1762 iterator.next(),
1763 Some(Chunk { identifier: ChunkIdentifier(3), content: ChunkContent::Items(items), .. }) => {
1764 assert_eq!(items, &['e']);
1765 }
1766 );
1767 assert_matches!(
1768 iterator.next(),
1769 Some(Chunk { identifier: ChunkIdentifier(2), content: ChunkContent::Items(items), .. }) => {
1770 assert_eq!(items, &['c', 'd']);
1771 }
1772 );
1773 assert_matches!(
1774 iterator.next(),
1775 Some(Chunk { identifier: ChunkIdentifier(1), content: ChunkContent::Gap(..), .. })
1776 );
1777 assert_matches!(
1778 iterator.next(),
1779 Some(Chunk { identifier: ChunkIdentifier(0), content: ChunkContent::Items(items), .. }) => {
1780 assert_eq!(items, &['a', 'b']);
1781 }
1782 );
1783 assert_matches!(iterator.next(), None);
1784 }
1785
1786 #[test]
1787 fn test_chunks() {
1788 let mut linked_chunk = LinkedChunk::<2, char, ()>::new();
1789 linked_chunk.push_items_back(['a', 'b']);
1790 linked_chunk.push_gap_back(());
1791 linked_chunk.push_items_back(['c', 'd', 'e']);
1792
1793 let mut iterator = linked_chunk.chunks();
1794
1795 assert_matches!(
1796 iterator.next(),
1797 Some(Chunk { identifier: ChunkIdentifier(0), content: ChunkContent::Items(items), .. }) => {
1798 assert_eq!(items, &['a', 'b']);
1799 }
1800 );
1801 assert_matches!(
1802 iterator.next(),
1803 Some(Chunk { identifier: ChunkIdentifier(1), content: ChunkContent::Gap(..), .. })
1804 );
1805 assert_matches!(
1806 iterator.next(),
1807 Some(Chunk { identifier: ChunkIdentifier(2), content: ChunkContent::Items(items), .. }) => {
1808 assert_eq!(items, &['c', 'd']);
1809 }
1810 );
1811 assert_matches!(
1812 iterator.next(),
1813 Some(Chunk { identifier: ChunkIdentifier(3), content: ChunkContent::Items(items), .. }) => {
1814 assert_eq!(items, &['e']);
1815 }
1816 );
1817 assert_matches!(iterator.next(), None);
1818 }
1819
1820 #[test]
1821 fn test_rchunks_from() -> Result<(), Error> {
1822 let mut linked_chunk = LinkedChunk::<2, char, ()>::new();
1823 linked_chunk.push_items_back(['a', 'b']);
1824 linked_chunk.push_gap_back(());
1825 linked_chunk.push_items_back(['c', 'd', 'e']);
1826
1827 let mut iterator = linked_chunk.rchunks_from(
1828 linked_chunk.item_position(|item| *item == 'c').unwrap().chunk_identifier(),
1829 )?;
1830
1831 assert_matches!(
1832 iterator.next(),
1833 Some(Chunk { identifier: ChunkIdentifier(2), content: ChunkContent::Items(items), .. }) => {
1834 assert_eq!(items, &['c', 'd']);
1835 }
1836 );
1837 assert_matches!(
1838 iterator.next(),
1839 Some(Chunk { identifier: ChunkIdentifier(1), content: ChunkContent::Gap(..), .. })
1840 );
1841 assert_matches!(
1842 iterator.next(),
1843 Some(Chunk { identifier: ChunkIdentifier(0), content: ChunkContent::Items(items), .. }) => {
1844 assert_eq!(items, &['a', 'b']);
1845 }
1846 );
1847 assert_matches!(iterator.next(), None);
1848
1849 Ok(())
1850 }
1851
1852 #[test]
1853 fn test_chunks_from() -> Result<(), Error> {
1854 let mut linked_chunk = LinkedChunk::<2, char, ()>::new();
1855 linked_chunk.push_items_back(['a', 'b']);
1856 linked_chunk.push_gap_back(());
1857 linked_chunk.push_items_back(['c', 'd', 'e']);
1858
1859 let mut iterator = linked_chunk.chunks_from(
1860 linked_chunk.item_position(|item| *item == 'c').unwrap().chunk_identifier(),
1861 )?;
1862
1863 assert_matches!(
1864 iterator.next(),
1865 Some(Chunk { identifier: ChunkIdentifier(2), content: ChunkContent::Items(items), .. }) => {
1866 assert_eq!(items, &['c', 'd']);
1867 }
1868 );
1869 assert_matches!(
1870 iterator.next(),
1871 Some(Chunk { identifier: ChunkIdentifier(3), content: ChunkContent::Items(items), .. }) => {
1872 assert_eq!(items, &['e']);
1873 }
1874 );
1875 assert_matches!(iterator.next(), None);
1876
1877 Ok(())
1878 }
1879
1880 #[test]
1881 fn test_ritems() {
1882 let mut linked_chunk = LinkedChunk::<2, char, ()>::new();
1883 linked_chunk.push_items_back(['a', 'b']);
1884 linked_chunk.push_gap_back(());
1885 linked_chunk.push_items_back(['c', 'd', 'e']);
1886
1887 let mut iterator = linked_chunk.ritems();
1888
1889 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(3), 0), 'e')));
1890 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(2), 1), 'd')));
1891 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(2), 0), 'c')));
1892 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(0), 1), 'b')));
1893 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(0), 0), 'a')));
1894 assert_matches!(iterator.next(), None);
1895 }
1896
1897 #[test]
1898 fn test_ritems_with_final_gap() -> Result<(), Error> {
1899 let mut linked_chunk = LinkedChunk::<3, char, ()>::new();
1900 linked_chunk.push_items_back(['a', 'b']);
1901 linked_chunk.push_gap_back(());
1902 linked_chunk.push_items_back(['c', 'd', 'e']);
1903 linked_chunk.push_gap_back(());
1904
1905 let mut iterator = linked_chunk.ritems();
1906
1907 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(2), 2), 'e')));
1908 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(2), 1), 'd')));
1909 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(2), 0), 'c')));
1910 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(0), 1), 'b')));
1911 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(0), 0), 'a')));
1912 assert_matches!(iterator.next(), None);
1913
1914 Ok(())
1915 }
1916
1917 #[test]
1918 fn test_ritems_empty() {
1919 let linked_chunk = LinkedChunk::<2, char, ()>::new();
1920 let mut iterator = linked_chunk.ritems();
1921
1922 assert_matches!(iterator.next(), None);
1923 }
1924
1925 #[test]
1926 fn test_items() {
1927 let mut linked_chunk = LinkedChunk::<2, char, ()>::new();
1928 linked_chunk.push_items_back(['a', 'b']);
1929 linked_chunk.push_gap_back(());
1930 linked_chunk.push_items_back(['c', 'd', 'e']);
1931
1932 let mut iterator = linked_chunk.items();
1933
1934 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(0), 0), 'a')));
1935 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(0), 1), 'b')));
1936 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(2), 0), 'c')));
1937 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(2), 1), 'd')));
1938 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(3), 0), 'e')));
1939 assert_matches!(iterator.next(), None);
1940 }
1941
1942 #[test]
1943 fn test_items_empty() {
1944 let linked_chunk = LinkedChunk::<2, char, ()>::new();
1945 let mut iterator = linked_chunk.items();
1946
1947 assert_matches!(iterator.next(), None);
1948 }
1949
1950 #[test]
1951 fn test_ritems_from() -> Result<(), Error> {
1952 let mut linked_chunk = LinkedChunk::<2, char, ()>::new();
1953 linked_chunk.push_items_back(['a', 'b']);
1954 linked_chunk.push_gap_back(());
1955 linked_chunk.push_items_back(['c', 'd', 'e']);
1956
1957 let mut iterator =
1958 linked_chunk.ritems_from(linked_chunk.item_position(|item| *item == 'c').unwrap())?;
1959
1960 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(2), 0), 'c')));
1961 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(0), 1), 'b')));
1962 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(0), 0), 'a')));
1963 assert_matches!(iterator.next(), None);
1964
1965 Ok(())
1966 }
1967
1968 #[test]
1969 fn test_items_from() -> Result<(), Error> {
1970 let mut linked_chunk = LinkedChunk::<2, char, ()>::new();
1971 linked_chunk.push_items_back(['a', 'b']);
1972 linked_chunk.push_gap_back(());
1973 linked_chunk.push_items_back(['c', 'd', 'e']);
1974
1975 let mut iterator =
1976 linked_chunk.items_from(linked_chunk.item_position(|item| *item == 'c').unwrap())?;
1977
1978 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(2), 0), 'c')));
1979 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(2), 1), 'd')));
1980 assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(3), 0), 'e')));
1981 assert_matches!(iterator.next(), None);
1982
1983 Ok(())
1984 }
1985
1986 #[test]
1987 fn test_insert_items_at() -> Result<(), Error> {
1988 use super::Update::*;
1989
1990 let mut linked_chunk = LinkedChunk::<3, char, ()>::new_with_update_history();
1991
1992 let _ = linked_chunk.updates().unwrap().take();
1994
1995 linked_chunk.push_items_back(['a', 'b', 'c', 'd', 'e', 'f']);
1996 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] ['d', 'e', 'f']);
1997 assert_eq!(
1998 linked_chunk.updates().unwrap().take(),
1999 &[
2000 PushItems { at: Position(ChunkIdentifier(0), 0), items: vec!['a', 'b', 'c'] },
2001 NewItemsChunk {
2002 previous: Some(ChunkIdentifier(0)),
2003 new: ChunkIdentifier(1),
2004 next: None,
2005 },
2006 PushItems { at: Position(ChunkIdentifier(1), 0), items: vec!['d', 'e', 'f'] },
2007 ]
2008 );
2009
2010 {
2012 let position_of_e = linked_chunk.item_position(|item| *item == 'e').unwrap();
2013
2014 linked_chunk.insert_items_at(['w', 'x', 'y', 'z'], position_of_e)?;
2017
2018 assert_items_eq!(
2019 linked_chunk,
2020 ['a', 'b', 'c'] ['d', 'w', 'x'] ['y', 'z', 'e'] ['f']
2021 );
2022 assert_eq!(linked_chunk.num_items(), 10);
2023 assert_eq!(
2024 linked_chunk.updates().unwrap().take(),
2025 &[
2026 DetachLastItems { at: Position(ChunkIdentifier(1), 1) },
2027 PushItems { at: Position(ChunkIdentifier(1), 1), items: vec!['w', 'x'] },
2028 NewItemsChunk {
2029 previous: Some(ChunkIdentifier(1)),
2030 new: ChunkIdentifier(2),
2031 next: None,
2032 },
2033 PushItems { at: Position(ChunkIdentifier(2), 0), items: vec!['y', 'z'] },
2034 StartReattachItems,
2035 PushItems { at: Position(ChunkIdentifier(2), 2), items: vec!['e'] },
2036 NewItemsChunk {
2037 previous: Some(ChunkIdentifier(2)),
2038 new: ChunkIdentifier(3),
2039 next: None,
2040 },
2041 PushItems { at: Position(ChunkIdentifier(3), 0), items: vec!['f'] },
2042 EndReattachItems,
2043 ]
2044 );
2045 }
2046
2047 {
2049 let position_of_a = linked_chunk.item_position(|item| *item == 'a').unwrap();
2050 linked_chunk.insert_items_at(['l', 'm', 'n', 'o'], position_of_a)?;
2051
2052 assert_items_eq!(
2053 linked_chunk,
2054 ['l', 'm', 'n'] ['o', 'a', 'b'] ['c'] ['d', 'w', 'x'] ['y', 'z', 'e'] ['f']
2055 );
2056 assert_eq!(linked_chunk.num_items(), 14);
2057 assert_eq!(
2058 linked_chunk.updates().unwrap().take(),
2059 &[
2060 DetachLastItems { at: Position(ChunkIdentifier(0), 0) },
2061 PushItems { at: Position(ChunkIdentifier(0), 0), items: vec!['l', 'm', 'n'] },
2062 NewItemsChunk {
2063 previous: Some(ChunkIdentifier(0)),
2064 new: ChunkIdentifier(4),
2065 next: Some(ChunkIdentifier(1)),
2066 },
2067 PushItems { at: Position(ChunkIdentifier(4), 0), items: vec!['o'] },
2068 StartReattachItems,
2069 PushItems { at: Position(ChunkIdentifier(4), 1), items: vec!['a', 'b'] },
2070 NewItemsChunk {
2071 previous: Some(ChunkIdentifier(4)),
2072 new: ChunkIdentifier(5),
2073 next: Some(ChunkIdentifier(1)),
2074 },
2075 PushItems { at: Position(ChunkIdentifier(5), 0), items: vec!['c'] },
2076 EndReattachItems,
2077 ]
2078 );
2079 }
2080
2081 {
2083 let position_of_c = linked_chunk.item_position(|item| *item == 'c').unwrap();
2084 linked_chunk.insert_items_at(['r', 's'], position_of_c)?;
2085
2086 assert_items_eq!(
2087 linked_chunk,
2088 ['l', 'm', 'n'] ['o', 'a', 'b'] ['r', 's', 'c'] ['d', 'w', 'x'] ['y', 'z', 'e'] ['f']
2089 );
2090 assert_eq!(linked_chunk.num_items(), 16);
2091 assert_eq!(
2092 linked_chunk.updates().unwrap().take(),
2093 &[
2094 DetachLastItems { at: Position(ChunkIdentifier(5), 0) },
2095 PushItems { at: Position(ChunkIdentifier(5), 0), items: vec!['r', 's'] },
2096 StartReattachItems,
2097 PushItems { at: Position(ChunkIdentifier(5), 2), items: vec!['c'] },
2098 EndReattachItems,
2099 ]
2100 );
2101 }
2102
2103 {
2105 let position_of_f = linked_chunk.item_position(|item| *item == 'f').unwrap();
2106 let position_after_f =
2107 Position(position_of_f.chunk_identifier(), position_of_f.index() + 1);
2108
2109 linked_chunk.insert_items_at(['p', 'q'], position_after_f)?;
2110 assert_items_eq!(
2111 linked_chunk,
2112 ['l', 'm', 'n'] ['o', 'a', 'b'] ['r', 's', 'c'] ['d', 'w', 'x'] ['y', 'z', 'e'] ['f', 'p', 'q']
2113 );
2114 assert_eq!(
2115 linked_chunk.updates().unwrap().take(),
2116 &[PushItems { at: Position(ChunkIdentifier(3), 1), items: vec!['p', 'q'] }]
2117 );
2118 assert_eq!(linked_chunk.num_items(), 18);
2119 }
2120
2121 {
2123 assert_matches!(
2124 linked_chunk.insert_items_at(['u', 'v'], Position(ChunkIdentifier(128), 0)),
2125 Err(Error::InvalidChunkIdentifier { identifier: ChunkIdentifier(128) })
2126 );
2127 assert!(linked_chunk.updates().unwrap().take().is_empty());
2128 }
2129
2130 {
2132 assert_matches!(
2133 linked_chunk.insert_items_at(['u', 'v'], Position(ChunkIdentifier(0), 128)),
2134 Err(Error::InvalidItemIndex { index: 128 })
2135 );
2136 assert!(linked_chunk.updates().unwrap().take().is_empty());
2137 }
2138
2139 {
2141 linked_chunk.push_gap_back(());
2143 assert_items_eq!(
2144 linked_chunk,
2145 ['l', 'm', 'n'] ['o', 'a', 'b'] ['r', 's', 'c'] ['d', 'w', 'x'] ['y', 'z', 'e'] ['f', 'p', 'q'] [-]
2146 );
2147 assert_eq!(
2148 linked_chunk.updates().unwrap().take(),
2149 &[NewGapChunk {
2150 previous: Some(ChunkIdentifier(3)),
2151 new: ChunkIdentifier(6),
2152 next: None,
2153 gap: ()
2154 }]
2155 );
2156
2157 assert_matches!(
2158 linked_chunk.insert_items_at(['u', 'v'], Position(ChunkIdentifier(6), 0)),
2159 Err(Error::ChunkIsAGap { identifier: ChunkIdentifier(6) })
2160 );
2161 }
2162
2163 assert_eq!(linked_chunk.num_items(), 18);
2164
2165 Ok(())
2166 }
2167
2168 #[test]
2169 fn test_remove_item_at() -> Result<(), Error> {
2170 use super::Update::*;
2171
2172 let mut linked_chunk = LinkedChunk::<3, char, ()>::new_with_update_history();
2173
2174 let _ = linked_chunk.updates().unwrap().take();
2176
2177 linked_chunk.push_items_back(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']);
2178 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] ['d', 'e', 'f'] ['g', 'h', 'i'] ['j', 'k']);
2179 assert_eq!(linked_chunk.num_items(), 11);
2180
2181 let _ = linked_chunk.updates().unwrap().take();
2183
2184 {
2187 let position_of_f = linked_chunk.item_position(|item| *item == 'f').unwrap();
2188 let removed_item = linked_chunk.remove_item_at(position_of_f, EmptyChunk::Remove)?;
2189
2190 assert_eq!(removed_item, 'f');
2191 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] ['d', 'e'] ['g', 'h', 'i'] ['j', 'k']);
2192 assert_eq!(linked_chunk.num_items(), 10);
2193
2194 let position_of_e = linked_chunk.item_position(|item| *item == 'e').unwrap();
2195 let removed_item = linked_chunk.remove_item_at(position_of_e, EmptyChunk::Remove)?;
2196
2197 assert_eq!(removed_item, 'e');
2198 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] ['d'] ['g', 'h', 'i'] ['j', 'k']);
2199 assert_eq!(linked_chunk.num_items(), 9);
2200
2201 let position_of_d = linked_chunk.item_position(|item| *item == 'd').unwrap();
2202 let removed_item = linked_chunk.remove_item_at(position_of_d, EmptyChunk::Remove)?;
2203
2204 assert_eq!(removed_item, 'd');
2205 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] ['g', 'h', 'i'] ['j', 'k']);
2206 assert_eq!(linked_chunk.num_items(), 8);
2207
2208 assert_eq!(
2209 linked_chunk.updates().unwrap().take(),
2210 &[
2211 RemoveItem { at: Position(ChunkIdentifier(1), 2) },
2212 RemoveItem { at: Position(ChunkIdentifier(1), 1) },
2213 RemoveItem { at: Position(ChunkIdentifier(1), 0) },
2214 RemoveChunk(ChunkIdentifier(1)),
2215 ]
2216 );
2217 }
2218
2219 {
2222 let first_position = linked_chunk.item_position(|item| *item == 'a').unwrap();
2223 let removed_item = linked_chunk.remove_item_at(first_position, EmptyChunk::Remove)?;
2224
2225 assert_eq!(removed_item, 'a');
2226 assert_items_eq!(linked_chunk, ['b', 'c'] ['g', 'h', 'i'] ['j', 'k']);
2227 assert_eq!(linked_chunk.num_items(), 7);
2228
2229 let removed_item = linked_chunk.remove_item_at(first_position, EmptyChunk::Remove)?;
2230
2231 assert_eq!(removed_item, 'b');
2232 assert_items_eq!(linked_chunk, ['c'] ['g', 'h', 'i'] ['j', 'k']);
2233 assert_eq!(linked_chunk.num_items(), 6);
2234
2235 let removed_item = linked_chunk.remove_item_at(first_position, EmptyChunk::Remove)?;
2236
2237 assert_eq!(removed_item, 'c');
2238 assert_items_eq!(linked_chunk, [] ['g', 'h', 'i'] ['j', 'k']);
2239 assert_eq!(linked_chunk.num_items(), 5);
2240
2241 assert_eq!(
2242 linked_chunk.updates().unwrap().take(),
2243 &[
2244 RemoveItem { at: Position(ChunkIdentifier(0), 0) },
2245 RemoveItem { at: Position(ChunkIdentifier(0), 0) },
2246 RemoveItem { at: Position(ChunkIdentifier(0), 0) },
2247 ]
2248 );
2249 }
2250
2251 {
2254 let first_position = linked_chunk.item_position(|item| *item == 'g').unwrap();
2255 let removed_item = linked_chunk.remove_item_at(first_position, EmptyChunk::Remove)?;
2256
2257 assert_eq!(removed_item, 'g');
2258 assert_items_eq!(linked_chunk, [] ['h', 'i'] ['j', 'k']);
2259 assert_eq!(linked_chunk.num_items(), 4);
2260
2261 let removed_item = linked_chunk.remove_item_at(first_position, EmptyChunk::Remove)?;
2262
2263 assert_eq!(removed_item, 'h');
2264 assert_items_eq!(linked_chunk, [] ['i'] ['j', 'k']);
2265 assert_eq!(linked_chunk.num_items(), 3);
2266
2267 let removed_item = linked_chunk.remove_item_at(first_position, EmptyChunk::Remove)?;
2268
2269 assert_eq!(removed_item, 'i');
2270 assert_items_eq!(linked_chunk, [] ['j', 'k']);
2271 assert_eq!(linked_chunk.num_items(), 2);
2272
2273 assert_eq!(
2274 linked_chunk.updates().unwrap().take(),
2275 &[
2276 RemoveItem { at: Position(ChunkIdentifier(2), 0) },
2277 RemoveItem { at: Position(ChunkIdentifier(2), 0) },
2278 RemoveItem { at: Position(ChunkIdentifier(2), 0) },
2279 RemoveChunk(ChunkIdentifier(2)),
2280 ]
2281 );
2282 }
2283
2284 {
2287 let position_of_k = linked_chunk.item_position(|item| *item == 'k').unwrap();
2288 let removed_item = linked_chunk.remove_item_at(position_of_k, EmptyChunk::Remove)?;
2289
2290 assert_eq!(removed_item, 'k');
2291 #[rustfmt::skip]
2292 assert_items_eq!(linked_chunk, [] ['j']);
2293 assert_eq!(linked_chunk.num_items(), 1);
2294
2295 let position_of_j = linked_chunk.item_position(|item| *item == 'j').unwrap();
2296 let removed_item = linked_chunk.remove_item_at(position_of_j, EmptyChunk::Remove)?;
2297
2298 assert_eq!(removed_item, 'j');
2299 assert_items_eq!(linked_chunk, []);
2300 assert_eq!(linked_chunk.num_items(), 0);
2301
2302 assert_eq!(
2303 linked_chunk.updates().unwrap().take(),
2304 &[
2305 RemoveItem { at: Position(ChunkIdentifier(3), 1) },
2306 RemoveItem { at: Position(ChunkIdentifier(3), 0) },
2307 RemoveChunk(ChunkIdentifier(3)),
2308 ]
2309 );
2310 }
2311
2312 {
2314 linked_chunk.push_items_back(['a', 'b', 'c', 'd']);
2315
2316 #[rustfmt::skip]
2317 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] ['d']);
2318 assert_eq!(linked_chunk.num_items(), 4);
2319
2320 let position_of_c = linked_chunk.item_position(|item| *item == 'c').unwrap();
2321 linked_chunk.insert_gap_at((), position_of_c)?;
2322
2323 assert_items_eq!(linked_chunk, ['a', 'b'] [-] ['c'] ['d']);
2324 assert_eq!(linked_chunk.num_items(), 4);
2325
2326 let _ = linked_chunk.updates().unwrap().take();
2328
2329 let position_of_c = linked_chunk.item_position(|item| *item == 'c').unwrap();
2330 let removed_item = linked_chunk.remove_item_at(position_of_c, EmptyChunk::Remove)?;
2331
2332 assert_eq!(removed_item, 'c');
2333 assert_items_eq!(linked_chunk, ['a', 'b'] [-] ['d']);
2334 assert_eq!(linked_chunk.num_items(), 3);
2335
2336 let position_of_d = linked_chunk.item_position(|item| *item == 'd').unwrap();
2337 let removed_item = linked_chunk.remove_item_at(position_of_d, EmptyChunk::Remove)?;
2338
2339 assert_eq!(removed_item, 'd');
2340 assert_items_eq!(linked_chunk, ['a', 'b'] [-]);
2341 assert_eq!(linked_chunk.num_items(), 2);
2342
2343 let first_position = linked_chunk.item_position(|item| *item == 'a').unwrap();
2344 let removed_item = linked_chunk.remove_item_at(first_position, EmptyChunk::Remove)?;
2345
2346 assert_eq!(removed_item, 'a');
2347 assert_items_eq!(linked_chunk, ['b'] [-]);
2348 assert_eq!(linked_chunk.num_items(), 1);
2349
2350 let removed_item = linked_chunk.remove_item_at(first_position, EmptyChunk::Remove)?;
2351
2352 assert_eq!(removed_item, 'b');
2353 assert_items_eq!(linked_chunk, [] [-]);
2354 assert_eq!(linked_chunk.num_items(), 0);
2355
2356 assert_eq!(
2357 linked_chunk.updates().unwrap().take(),
2358 &[
2359 RemoveItem { at: Position(ChunkIdentifier(6), 0) },
2360 RemoveChunk(ChunkIdentifier(6)),
2361 RemoveItem { at: Position(ChunkIdentifier(4), 0) },
2362 RemoveChunk(ChunkIdentifier(4)),
2363 RemoveItem { at: Position(ChunkIdentifier(0), 0) },
2364 RemoveItem { at: Position(ChunkIdentifier(0), 0) },
2365 ]
2366 );
2367 }
2368
2369 Ok(())
2370 }
2371
2372 #[test]
2373 fn test_remove_item_at_and_keep_empty_chunks() -> Result<(), Error> {
2374 use super::Update::*;
2375
2376 let mut linked_chunk = LinkedChunk::<3, char, ()>::new_with_update_history();
2377
2378 let _ = linked_chunk.updates().unwrap().take();
2380
2381 linked_chunk.push_items_back(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
2382 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] ['d', 'e', 'f'] ['g', 'h']);
2383 assert_eq!(linked_chunk.num_items(), 8);
2384
2385 let _ = linked_chunk.updates().unwrap().take();
2387
2388 {
2391 let position = linked_chunk.item_position(|item| *item == 'd').unwrap();
2392 let removed_item = linked_chunk.remove_item_at(position, EmptyChunk::Keep)?;
2393
2394 assert_eq!(removed_item, 'd');
2395 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] ['e', 'f'] ['g', 'h']);
2396 assert_eq!(linked_chunk.num_items(), 7);
2397
2398 let removed_item = linked_chunk.remove_item_at(position, EmptyChunk::Keep)?;
2399
2400 assert_eq!(removed_item, 'e');
2401 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] ['f'] ['g', 'h']);
2402 assert_eq!(linked_chunk.num_items(), 6);
2403
2404 let removed_item = linked_chunk.remove_item_at(position, EmptyChunk::Keep)?;
2405
2406 assert_eq!(removed_item, 'f');
2407 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] [] ['g', 'h']);
2408 assert_eq!(linked_chunk.num_items(), 5);
2409
2410 assert_eq!(
2411 linked_chunk.updates().unwrap().take(),
2412 &[
2413 RemoveItem { at: Position(ChunkIdentifier(1), 0) },
2414 RemoveItem { at: Position(ChunkIdentifier(1), 0) },
2415 RemoveItem { at: Position(ChunkIdentifier(1), 0) },
2416 ]
2417 );
2418 }
2419
2420 {
2423 let position = linked_chunk.item_position(|item| *item == 'g').unwrap();
2424 let removed_item = linked_chunk.remove_item_at(position, EmptyChunk::Keep)?;
2425
2426 assert_eq!(removed_item, 'g');
2427 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] [] ['h']);
2428 assert_eq!(linked_chunk.num_items(), 4);
2429
2430 let removed_item = linked_chunk.remove_item_at(position, EmptyChunk::Keep)?;
2431
2432 assert_eq!(removed_item, 'h');
2433 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] [] []);
2434 assert_eq!(linked_chunk.num_items(), 3);
2435
2436 assert_eq!(
2437 linked_chunk.updates().unwrap().take(),
2438 &[
2439 RemoveItem { at: Position(ChunkIdentifier(2), 0) },
2440 RemoveItem { at: Position(ChunkIdentifier(2), 0) },
2441 ]
2442 );
2443 }
2444
2445 {
2448 let position = linked_chunk.item_position(|item| *item == 'a').unwrap();
2449 let removed_item = linked_chunk.remove_item_at(position, EmptyChunk::Keep)?;
2450
2451 assert_eq!(removed_item, 'a');
2452 assert_items_eq!(linked_chunk, ['b', 'c'] [] []);
2453 assert_eq!(linked_chunk.num_items(), 2);
2454
2455 let removed_item = linked_chunk.remove_item_at(position, EmptyChunk::Keep)?;
2456
2457 assert_eq!(removed_item, 'b');
2458 assert_items_eq!(linked_chunk, ['c'] [] []);
2459 assert_eq!(linked_chunk.num_items(), 1);
2460
2461 let removed_item = linked_chunk.remove_item_at(position, EmptyChunk::Keep)?;
2462
2463 assert_eq!(removed_item, 'c');
2464 assert_items_eq!(linked_chunk, [] [] []);
2465 assert_eq!(linked_chunk.num_items(), 0);
2466
2467 assert_eq!(
2468 linked_chunk.updates().unwrap().take(),
2469 &[
2470 RemoveItem { at: Position(ChunkIdentifier(0), 0) },
2471 RemoveItem { at: Position(ChunkIdentifier(0), 0) },
2472 RemoveItem { at: Position(ChunkIdentifier(0), 0) },
2473 ]
2474 );
2475 }
2476
2477 Ok(())
2478 }
2479
2480 #[test]
2481 fn test_insert_gap_at() -> Result<(), Error> {
2482 use super::Update::*;
2483
2484 let mut linked_chunk = LinkedChunk::<3, char, ()>::new_with_update_history();
2485
2486 let _ = linked_chunk.updates().unwrap().take();
2488
2489 linked_chunk.push_items_back(['a', 'b', 'c', 'd', 'e', 'f']);
2490 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] ['d', 'e', 'f']);
2491 assert_eq!(
2492 linked_chunk.updates().unwrap().take(),
2493 &[
2494 PushItems { at: Position(ChunkIdentifier(0), 0), items: vec!['a', 'b', 'c'] },
2495 NewItemsChunk {
2496 previous: Some(ChunkIdentifier(0)),
2497 new: ChunkIdentifier(1),
2498 next: None
2499 },
2500 PushItems { at: Position(ChunkIdentifier(1), 0), items: vec!['d', 'e', 'f'] },
2501 ]
2502 );
2503
2504 {
2506 let position_of_b = linked_chunk.item_position(|item| *item == 'b').unwrap();
2507 linked_chunk.insert_gap_at((), position_of_b)?;
2508
2509 assert_items_eq!(linked_chunk, ['a'] [-] ['b', 'c'] ['d', 'e', 'f']);
2510 assert_eq!(
2511 linked_chunk.updates().unwrap().take(),
2512 &[
2513 DetachLastItems { at: Position(ChunkIdentifier(0), 1) },
2514 NewGapChunk {
2515 previous: Some(ChunkIdentifier(0)),
2516 new: ChunkIdentifier(2),
2517 next: Some(ChunkIdentifier(1)),
2518 gap: (),
2519 },
2520 StartReattachItems,
2521 NewItemsChunk {
2522 previous: Some(ChunkIdentifier(2)),
2523 new: ChunkIdentifier(3),
2524 next: Some(ChunkIdentifier(1)),
2525 },
2526 PushItems { at: Position(ChunkIdentifier(3), 0), items: vec!['b', 'c'] },
2527 EndReattachItems,
2528 ]
2529 );
2530 }
2531
2532 {
2534 let position_of_a = linked_chunk.item_position(|item| *item == 'a').unwrap();
2535 linked_chunk.insert_gap_at((), position_of_a)?;
2536
2537 assert_items_eq!(linked_chunk, [] [-] ['a'] [-] ['b', 'c'] ['d', 'e', 'f']);
2539 assert_eq!(
2540 linked_chunk.updates().unwrap().take(),
2541 &[
2542 DetachLastItems { at: Position(ChunkIdentifier(0), 0) },
2543 NewGapChunk {
2544 previous: Some(ChunkIdentifier(0)),
2545 new: ChunkIdentifier(4),
2546 next: Some(ChunkIdentifier(2)),
2547 gap: (),
2548 },
2549 StartReattachItems,
2550 NewItemsChunk {
2551 previous: Some(ChunkIdentifier(4)),
2552 new: ChunkIdentifier(5),
2553 next: Some(ChunkIdentifier(2)),
2554 },
2555 PushItems { at: Position(ChunkIdentifier(5), 0), items: vec!['a'] },
2556 EndReattachItems,
2557 ]
2558 );
2559 }
2560
2561 {
2563 let position_of_d = linked_chunk.item_position(|item| *item == 'd').unwrap();
2564 linked_chunk.insert_gap_at((), position_of_d)?;
2565
2566 assert_items_eq!(linked_chunk, [] [-] ['a'] [-] ['b', 'c'] [-] ['d', 'e', 'f']);
2570 assert_eq!(
2571 linked_chunk.updates().unwrap().take(),
2572 &[NewGapChunk {
2573 previous: Some(ChunkIdentifier(3)),
2574 new: ChunkIdentifier(6),
2575 next: Some(ChunkIdentifier(1)),
2576 gap: (),
2577 }]
2578 );
2579 }
2580
2581 {
2583 let position_of_first_empty_chunk = Position(ChunkIdentifier(0), 0);
2584 assert_matches!(
2585 linked_chunk.insert_gap_at((), position_of_first_empty_chunk),
2586 Err(Error::InvalidItemIndex { index: 0 })
2587 );
2588 assert!(linked_chunk.updates().unwrap().take().is_empty());
2589 }
2590
2591 {
2593 let gap_identifier = linked_chunk.chunk_identifier(Chunk::is_gap).unwrap();
2595 let position = linked_chunk.replace_gap_at([], gap_identifier)?.first_position();
2596
2597 assert_items_eq!(linked_chunk, [] [-] ['a'] [-] ['b', 'c'] [] ['d', 'e', 'f']);
2598 assert_eq!(
2599 linked_chunk.updates().unwrap().take(),
2600 &[
2601 NewItemsChunk {
2602 previous: Some(ChunkIdentifier(6)),
2603 new: ChunkIdentifier(7),
2604 next: Some(ChunkIdentifier(1)),
2605 },
2606 RemoveChunk(ChunkIdentifier(6)),
2607 ]
2608 );
2609
2610 linked_chunk.insert_gap_at((), position)?;
2611
2612 assert_items_eq!(linked_chunk, [] [-] ['a'] [-] ['b', 'c'] [-] [] ['d', 'e', 'f']);
2613 assert_eq!(
2614 linked_chunk.updates().unwrap().take(),
2615 &[NewGapChunk {
2616 previous: Some(ChunkIdentifier(3)),
2617 new: ChunkIdentifier(8),
2618 next: Some(ChunkIdentifier(7)),
2619 gap: (),
2620 }]
2621 );
2622 }
2623
2624 {
2626 assert_matches!(
2627 linked_chunk.insert_items_at(['u', 'v'], Position(ChunkIdentifier(128), 0)),
2628 Err(Error::InvalidChunkIdentifier { identifier: ChunkIdentifier(128) })
2629 );
2630 assert!(linked_chunk.updates().unwrap().take().is_empty());
2631 }
2632
2633 {
2635 assert_matches!(
2636 linked_chunk.insert_items_at(['u', 'v'], Position(ChunkIdentifier(0), 128)),
2637 Err(Error::InvalidItemIndex { index: 128 })
2638 );
2639 assert!(linked_chunk.updates().unwrap().take().is_empty());
2640 }
2641
2642 {
2644 let position_of_a_gap = Position(ChunkIdentifier(4), 0);
2647 assert_matches!(
2648 linked_chunk.insert_gap_at((), position_of_a_gap),
2649 Err(Error::ChunkIsAGap { identifier: ChunkIdentifier(4) })
2650 );
2651 assert!(linked_chunk.updates().unwrap().take().is_empty());
2652 }
2653
2654 assert_eq!(linked_chunk.num_items(), 6);
2655
2656 Ok(())
2657 }
2658
2659 #[test]
2660 fn test_replace_gap_at() -> Result<(), Error> {
2661 use super::Update::*;
2662
2663 let mut linked_chunk = LinkedChunk::<3, char, ()>::new_with_update_history();
2664
2665 let _ = linked_chunk.updates().unwrap().take();
2667
2668 linked_chunk.push_items_back(['a', 'b']);
2669 linked_chunk.push_gap_back(());
2670 linked_chunk.push_items_back(['l', 'm']);
2671 assert_items_eq!(linked_chunk, ['a', 'b'] [-] ['l', 'm']);
2672 assert_eq!(
2673 linked_chunk.updates().unwrap().take(),
2674 &[
2675 PushItems { at: Position(ChunkIdentifier(0), 0), items: vec!['a', 'b'] },
2676 NewGapChunk {
2677 previous: Some(ChunkIdentifier(0)),
2678 new: ChunkIdentifier(1),
2679 next: None,
2680 gap: (),
2681 },
2682 NewItemsChunk {
2683 previous: Some(ChunkIdentifier(1)),
2684 new: ChunkIdentifier(2),
2685 next: None,
2686 },
2687 PushItems { at: Position(ChunkIdentifier(2), 0), items: vec!['l', 'm'] }
2688 ]
2689 );
2690
2691 {
2693 let gap_identifier = linked_chunk.chunk_identifier(Chunk::is_gap).unwrap();
2694 assert_eq!(gap_identifier, ChunkIdentifier(1));
2695
2696 let new_chunk =
2697 linked_chunk.replace_gap_at(['d', 'e', 'f', 'g', 'h'], gap_identifier)?;
2698 assert_eq!(new_chunk.identifier(), ChunkIdentifier(3));
2699 assert_items_eq!(
2700 linked_chunk,
2701 ['a', 'b'] ['d', 'e', 'f'] ['g', 'h'] ['l', 'm']
2702 );
2703 assert_eq!(
2704 linked_chunk.updates().unwrap().take(),
2705 &[
2706 NewItemsChunk {
2707 previous: Some(ChunkIdentifier(1)),
2708 new: ChunkIdentifier(3),
2709 next: Some(ChunkIdentifier(2)),
2710 },
2711 PushItems { at: Position(ChunkIdentifier(3), 0), items: vec!['d', 'e', 'f'] },
2712 NewItemsChunk {
2713 previous: Some(ChunkIdentifier(3)),
2714 new: ChunkIdentifier(4),
2715 next: Some(ChunkIdentifier(2)),
2716 },
2717 PushItems { at: Position(ChunkIdentifier(4), 0), items: vec!['g', 'h'] },
2718 RemoveChunk(ChunkIdentifier(1)),
2719 ]
2720 );
2721 }
2722
2723 {
2725 linked_chunk.push_gap_back(());
2726 assert_items_eq!(
2727 linked_chunk,
2728 ['a', 'b'] ['d', 'e', 'f'] ['g', 'h'] ['l', 'm'] [-]
2729 );
2730 assert_eq!(
2731 linked_chunk.updates().unwrap().take(),
2732 &[NewGapChunk {
2733 previous: Some(ChunkIdentifier(2)),
2734 new: ChunkIdentifier(5),
2735 next: None,
2736 gap: (),
2737 }]
2738 );
2739
2740 let gap_identifier = linked_chunk.chunk_identifier(Chunk::is_gap).unwrap();
2741 assert_eq!(gap_identifier, ChunkIdentifier(5));
2742
2743 let new_chunk = linked_chunk.replace_gap_at(['w', 'x', 'y', 'z'], gap_identifier)?;
2744 assert_eq!(new_chunk.identifier(), ChunkIdentifier(6));
2745 assert_items_eq!(
2746 linked_chunk,
2747 ['a', 'b'] ['d', 'e', 'f'] ['g', 'h'] ['l', 'm'] ['w', 'x', 'y'] ['z']
2748 );
2749 assert_eq!(
2750 linked_chunk.updates().unwrap().take(),
2751 &[
2752 NewItemsChunk {
2753 previous: Some(ChunkIdentifier(5)),
2754 new: ChunkIdentifier(6),
2755 next: None,
2756 },
2757 PushItems { at: Position(ChunkIdentifier(6), 0), items: vec!['w', 'x', 'y'] },
2758 NewItemsChunk {
2759 previous: Some(ChunkIdentifier(6)),
2760 new: ChunkIdentifier(7),
2761 next: None,
2762 },
2763 PushItems { at: Position(ChunkIdentifier(7), 0), items: vec!['z'] },
2764 RemoveChunk(ChunkIdentifier(5)),
2765 ]
2766 );
2767 }
2768
2769 assert_eq!(linked_chunk.num_items(), 13);
2770
2771 Ok(())
2772 }
2773
2774 #[test]
2775 fn test_remove_gap() -> Result<(), Error> {
2776 use super::Update::*;
2777
2778 let mut linked_chunk = LinkedChunk::<3, char, ()>::new_with_update_history();
2779
2780 let _ = linked_chunk.updates().unwrap().take();
2782
2783 linked_chunk.push_items_back(['a', 'b']);
2784 linked_chunk.push_gap_back(());
2785 linked_chunk.push_items_back(['l', 'm']);
2786 linked_chunk.push_gap_back(());
2787 assert_items_eq!(linked_chunk, ['a', 'b'] [-] ['l', 'm'] [-]);
2788 assert_eq!(
2789 linked_chunk.updates().unwrap().take(),
2790 &[
2791 PushItems { at: Position(ChunkIdentifier(0), 0), items: vec!['a', 'b'] },
2792 NewGapChunk {
2793 previous: Some(ChunkIdentifier(0)),
2794 new: ChunkIdentifier(1),
2795 next: None,
2796 gap: (),
2797 },
2798 NewItemsChunk {
2799 previous: Some(ChunkIdentifier(1)),
2800 new: ChunkIdentifier(2),
2801 next: None,
2802 },
2803 PushItems { at: Position(ChunkIdentifier(2), 0), items: vec!['l', 'm'] },
2804 NewGapChunk {
2805 previous: Some(ChunkIdentifier(2)),
2806 new: ChunkIdentifier(3),
2807 next: None,
2808 gap: (),
2809 },
2810 ]
2811 );
2812
2813 let err = linked_chunk.remove_gap_at(ChunkIdentifier(0)).unwrap_err();
2815 assert_matches!(err, Error::ChunkIsItems { .. });
2816
2817 let err = linked_chunk.remove_gap_at(ChunkIdentifier(42)).unwrap_err();
2819 assert_matches!(err, Error::InvalidChunkIdentifier { .. });
2820
2821 let maybe_next = linked_chunk.remove_gap_at(ChunkIdentifier(1)).unwrap();
2823 let next = maybe_next.unwrap();
2824 assert_eq!(next.chunk_identifier(), ChunkIdentifier(2));
2826 assert_eq!(next.index(), 0);
2827 assert_items_eq!(linked_chunk, ['a', 'b'] ['l', 'm'] [-]);
2828 assert_eq!(linked_chunk.updates().unwrap().take(), &[RemoveChunk(ChunkIdentifier(1))]);
2829
2830 let next = linked_chunk.remove_gap_at(ChunkIdentifier(3)).unwrap();
2832 assert!(next.is_none());
2834 assert_items_eq!(linked_chunk, ['a', 'b'] ['l', 'm']);
2835 assert_eq!(linked_chunk.updates().unwrap().take(), &[RemoveChunk(ChunkIdentifier(3))]);
2836
2837 Ok(())
2838 }
2839
2840 #[test]
2841 fn test_chunk_item_positions() {
2842 let mut linked_chunk = LinkedChunk::<3, char, ()>::new();
2843 linked_chunk.push_items_back(['a', 'b', 'c', 'd', 'e']);
2844 linked_chunk.push_gap_back(());
2845 linked_chunk.push_items_back(['f']);
2846
2847 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] ['d', 'e'] [-] ['f']);
2848
2849 let mut iterator = linked_chunk.chunks();
2850
2851 {
2853 let chunk = iterator.next().unwrap();
2854 assert_eq!(chunk.first_position(), Position(ChunkIdentifier(0), 0));
2855 assert_eq!(chunk.last_position(), Position(ChunkIdentifier(0), 2));
2856 }
2857
2858 {
2860 let chunk = iterator.next().unwrap();
2861 assert_eq!(chunk.first_position(), Position(ChunkIdentifier(1), 0));
2862 assert_eq!(chunk.last_position(), Position(ChunkIdentifier(1), 1));
2863 }
2864
2865 {
2867 let chunk = iterator.next().unwrap();
2868 assert_eq!(chunk.first_position(), Position(ChunkIdentifier(2), 0));
2869 assert_eq!(chunk.last_position(), Position(ChunkIdentifier(2), 0));
2870 }
2871
2872 {
2874 let chunk = iterator.next().unwrap();
2875 assert_eq!(chunk.first_position(), Position(ChunkIdentifier(3), 0));
2876 assert_eq!(chunk.last_position(), Position(ChunkIdentifier(3), 0));
2877 }
2878 }
2879
2880 #[test]
2881 fn test_is_first_and_last_chunk() {
2882 let mut linked_chunk = LinkedChunk::<3, char, ()>::new();
2883
2884 let mut chunks = linked_chunk.chunks().peekable();
2885 assert!(chunks.peek().unwrap().is_first_chunk());
2886 assert!(chunks.next().unwrap().is_last_chunk());
2887 assert!(chunks.next().is_none());
2888
2889 linked_chunk.push_items_back(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
2890
2891 let mut chunks = linked_chunk.chunks().peekable();
2892 assert!(chunks.next().unwrap().is_first_chunk());
2893 assert!(chunks.peek().unwrap().is_first_chunk().not());
2894 assert!(chunks.next().unwrap().is_last_chunk().not());
2895 assert!(chunks.next().unwrap().is_last_chunk());
2896 assert!(chunks.next().is_none());
2897 }
2898
2899 #[test]
2904 fn test_clear() {
2905 let mut linked_chunk = LinkedChunk::<3, Arc<char>, Arc<()>>::new();
2906
2907 let item = Arc::new('a');
2908 let gap = Arc::new(());
2909
2910 linked_chunk.push_items_back([
2911 item.clone(),
2912 item.clone(),
2913 item.clone(),
2914 item.clone(),
2915 item.clone(),
2916 ]);
2917 linked_chunk.push_gap_back(gap.clone());
2918 linked_chunk.push_items_back([item.clone()]);
2919
2920 assert_eq!(Arc::strong_count(&item), 7);
2921 assert_eq!(Arc::strong_count(&gap), 2);
2922 assert_eq!(linked_chunk.num_items(), 6);
2923 assert_eq!(linked_chunk.chunk_identifier_generator.next.load(Ordering::SeqCst), 3);
2924
2925 linked_chunk.clear();
2927
2928 assert_eq!(Arc::strong_count(&item), 1);
2929 assert_eq!(Arc::strong_count(&gap), 1);
2930 assert_eq!(linked_chunk.num_items(), 0);
2931 assert_eq!(linked_chunk.chunk_identifier_generator.next.load(Ordering::SeqCst), 0);
2932 }
2933
2934 #[test]
2935 fn test_clear_emit_an_update_clear() {
2936 use super::Update::*;
2937
2938 let mut linked_chunk = LinkedChunk::<3, char, ()>::new_with_update_history();
2939
2940 assert_eq!(
2941 linked_chunk.updates().unwrap().take(),
2942 &[NewItemsChunk {
2943 previous: None,
2944 new: ChunkIdentifierGenerator::FIRST_IDENTIFIER,
2945 next: None
2946 }]
2947 );
2948
2949 linked_chunk.clear();
2950
2951 assert_eq!(
2952 linked_chunk.updates().unwrap().take(),
2953 &[
2954 Clear,
2955 NewItemsChunk {
2956 previous: None,
2957 new: ChunkIdentifierGenerator::FIRST_IDENTIFIER,
2958 next: None
2959 }
2960 ]
2961 );
2962 }
2963
2964 #[test]
2965 fn test_replace_item() {
2966 let mut linked_chunk = LinkedChunk::<3, char, ()>::new();
2967
2968 linked_chunk.push_items_back(['a', 'b', 'c']);
2969 linked_chunk.push_gap_back(());
2970 assert_items_eq!(linked_chunk, ['a', 'b', 'c'] [-]);
2972
2973 linked_chunk.replace_item_at(Position(ChunkIdentifier::new(0), 1), 'B').unwrap();
2975 assert_items_eq!(linked_chunk, ['a', 'B', 'c'] [-]);
2976
2977 assert_matches!(
2979 linked_chunk.replace_item_at(Position(ChunkIdentifier::new(0), 3), 'Z'),
2980 Err(Error::InvalidItemIndex { index: 3 })
2981 );
2982
2983 assert_matches!(
2985 linked_chunk.replace_item_at(Position(ChunkIdentifier::new(1), 0), 'Z'),
2986 Err(Error::ChunkIsAGap { .. })
2987 );
2988 }
2989}