oficina / docs Public

Clone
git clone https://amadan.net/oficina/docs

Plain git — no account needed to clone.

Download

Download this file

1use crate::block::{ItemContent, ItemPtr};
2use crate::slice::ItemSlice;
3use crate::{Assoc, Out, ReadTxn, StickyIndex};
4use smallvec::{smallvec, SmallVec};
5use std::ops::Deref;
6
7pub(crate) trait BlockIterator: TxnIterator<Item = ItemPtr> + Sized {
8 #[inline]
9 fn slices(self) -> BlockSlices<Self> {
10 BlockSlices(self)
11 }
12
13 #[inline]
14 fn within_range(self, from: StickyIndex, to: StickyIndex) -> RangeIter<Self> {
15 RangeIter::new(self, from, to)
16 }
17}
18
19impl<T> BlockIterator for T where T: TxnIterator<Item = ItemPtr> + Sized {}
20
21pub(crate) trait BlockSliceIterator: TxnIterator<Item = ItemSlice> + Sized {
22 #[inline]
23 fn values(self) -> Values<Self> {
24 Values::new(self)
25 }
26}
27
28impl<T> BlockSliceIterator for T where T: TxnIterator<Item = ItemSlice> + Sized {}
29
30pub trait IntoBlockIter {
31 fn to_iter(self) -> BlockIter;
32}
33
34impl IntoBlockIter for Option<ItemPtr> {
35 #[inline]
36 fn to_iter(self) -> BlockIter {
37 BlockIter(self)
38 }
39}
40
41/// Iterator over [ItemPtr] references.
42/// By default it iterates to the right side.
43/// When reversed it iterates to the left side.
44#[repr(transparent)]
45#[derive(Debug, Clone)]
46pub struct BlockIter(Option<ItemPtr>);
47
48impl BlockIter {
49 #[inline]
50 fn new(ptr: Option<ItemPtr>) -> Self {
51 BlockIter(ptr)
52 }
53
54 pub fn moved(self) -> MoveIter {
55 MoveIter::new(self)
56 }
57}
58
59impl Iterator for BlockIter {
60 type Item = ItemPtr;
61
62 fn next(&mut self) -> Option<Self::Item> {
63 let curr = self.0.take();
64 if let Some(item) = curr.as_deref() {
65 self.0 = item.right;
66 }
67 curr
68 }
69}
70
71impl DoubleEndedIterator for BlockIter {
72 fn next_back(&mut self) -> Option<Self::Item> {
73 let curr = self.0.take();
74 if let Some(item) = curr.as_deref() {
75 self.0 = item.left;
76 }
77 curr
78 }
79}
80
81impl IntoIterator for ItemPtr {
82 type Item = ItemPtr;
83 type IntoIter = BlockIter;
84
85 fn into_iter(self) -> Self::IntoIter {
86 BlockIter::new(Some(self))
87 }
88}
89
90/// Iterator equivalent that can be supplied with transaction when iteration step may need it.
91pub trait TxnIterator {
92 type Item;
93 fn next<T: ReadTxn>(&mut self, txn: &T) -> Option<Self::Item>;
94
95 fn collect<T, B>(&mut self, txn: &T) -> B
96 where
97 T: ReadTxn,
98 B: Default + Extend<Self::Item>,
99 {
100 let mut buf = B::default();
101 while let Some(item) = self.next(txn) {
102 buf.extend([item]);
103 }
104 buf
105 }
106}
107
108/// DoubleEndedIterator equivalent that can be supplied with transaction when iteration step may need it.
109pub trait TxnDoubleEndedIterator: TxnIterator {
110 fn next_back<T: ReadTxn>(&mut self, txn: &T) -> Option<Self::Item>;
111}
112
113/// Block iterator which acknowledges context of move operation and iterates
114/// over blocks as they appear after move. It skips over the presence of move destination blocks.
115#[derive(Debug)]
116pub struct MoveIter {
117 iter: BlockIter,
118 stack: MoveStack,
119}
120
121impl MoveIter {
122 pub(crate) fn new(iter: BlockIter) -> Self {
123 MoveIter {
124 iter,
125 stack: MoveStack::default(),
126 }
127 }
128
129 /// Try to remove the latest move scope from the move stack.
130 /// If there was any active scope removed this way, we reset a current iterator position
131 /// to a scope destination (return address).
132 /// Returns `true` if this method call had any effect.
133 fn escape_current_scope(&mut self) -> bool {
134 if let Some(scope) = self.stack.pop() {
135 self.iter = scope.dest.into_iter();
136 true
137 } else {
138 false
139 }
140 }
141}
142
143impl TxnIterator for MoveIter {
144 type Item = ItemPtr;
145
146 fn next<T: ReadTxn>(&mut self, txn: &T) -> Option<Self::Item> {
147 while {
148 if let Some(curr) = self.iter.next() {
149 let scope = self.stack.current_scope();
150 let ctx = scope.map(|s| s.dest);
151 if curr.moved == ctx {
152 // current item exists in the right (possibly none) move scope
153 if let Some(scope) = scope {
154 if scope.end == Some(curr) {
155 // we're at the end of the current scope
156 // while we still need to return current block ptr
157 // we can already descent in the move stack
158 self.escape_current_scope();
159 // we just returned to last active moved block ptr, we need to
160 // skip over it
161 self.iter.next();
162 }
163 }
164 if let ItemContent::Move(m) = &curr.content {
165 // we need to move to a new scope and reposition iterator at the start of it
166 let (start, end) = m.get_moved_coords(txn);
167 self.stack.push(MoveScope::new(start, end, curr));
168 self.iter = BlockIter(start);
169 } else {
170 return Some(curr);
171 }
172 }
173
174 true // continue to the next loop iteration
175 } else {
176 // if current iterator reached the end of the block sequence,
177 // check if there are any remaining scopes on move stack and
178 // if so, reposition iterator to their return address and retry
179 let escaped = self.escape_current_scope();
180 self.iter.next();
181 escaped
182 }
183 } {}
184 None
185 }
186}
187
188impl TxnDoubleEndedIterator for MoveIter {
189 fn next_back<T: ReadTxn>(&mut self, txn: &T) -> Option<Self::Item> {
190 while {
191 if let Some(curr) = self.iter.next_back() {
192 let scope = self.stack.current_scope();
193 if curr.moved == scope.map(|s| s.dest) {
194 // current item exists in the right (possibly none) move scope
195 if let Some(scope) = scope {
196 if scope.start == Some(curr) {
197 // we're at the start of the current scope
198 // while we still need to return current block ptr
199 // we can already descent in the move stack
200 self.escape_current_scope();
201 // we just returned to last active moved block ptr, we need to
202 // skip over it
203 self.iter.next_back();
204 }
205 }
206 if let ItemContent::Move(m) = &curr.content {
207 // we need to move to a new scope and reposition iterator at the end of it
208 let (start, end) = m.get_moved_coords(txn);
209 self.stack.push(MoveScope::new(start, end, curr));
210 self.iter = BlockIter(end);
211 } else {
212 return Some(curr);
213 }
214 }
215
216 true // continue to the next loop iteration
217 } else {
218 // if current iterator reached the end of the block sequence,
219 // check if there are any remaining scopes on move stack and
220 // if so, reposition iterator to their return address and retry
221 let escaped = self.escape_current_scope();
222 self.iter.next_back();
223 escaped
224 }
225 } {}
226 None
227 }
228}
229
230#[derive(Debug, Default)]
231struct MoveStack(Option<Vec<MoveScope>>);
232
233impl MoveStack {
234 /// Returns a current scope of move operation.
235 /// If `None`, it means that currently iterated elements were not moved anywhere.
236 /// Otherwise, we are iterating over consecutive range of elements that have been
237 /// relocated.
238 fn current_scope(&self) -> Option<&MoveScope> {
239 if let Some(stack) = &self.0 {
240 stack.last()
241 } else {
242 None
243 }
244 }
245
246 /// Pushes a new scope on top of current move stack. This happens when we touched
247 /// a new block that contains a move content.
248 fn push(&mut self, scope: MoveScope) {
249 let stack = self.0.get_or_insert_with(Vec::default);
250 stack.push(scope);
251 }
252
253 /// Removes the latest scope from the move stack. Usually done when we detected that
254 /// iterator reached the boundary of a move scope and we need to go back to the
255 /// original destination.
256 fn pop(&mut self) -> Option<MoveScope> {
257 if let Some(stack) = &mut self.0 {
258 stack.pop()
259 } else {
260 None
261 }
262 }
263}
264
265#[derive(Debug)]
266struct MoveScope {
267 /// First block moved in this scope.
268 start: Option<ItemPtr>,
269 /// Last block moved in this scope.
270 end: Option<ItemPtr>,
271 /// A.k.a. return address for the move range. Block pointer where the (start, end)
272 /// range has been moved. It always contains an item with move content.
273 dest: ItemPtr,
274}
275
276impl MoveScope {
277 fn new(start: Option<ItemPtr>, end: Option<ItemPtr>, dest: ItemPtr) -> Self {
278 MoveScope { start, end, dest }
279 }
280}
281
282#[derive(Debug)]
283pub(crate) struct BlockSlices<I>(I)
284where
285 I: TxnIterator<Item = ItemPtr> + Sized;
286
287impl<I> TxnIterator for BlockSlices<I>
288where
289 I: TxnIterator<Item = ItemPtr> + Sized,
290{
291 type Item = ItemSlice;
292
293 fn next<T: ReadTxn>(&mut self, txn: &T) -> Option<Self::Item> {
294 let ptr = self.0.next(txn)?;
295 Some(ptr.into())
296 }
297}
298
299impl<I> TxnDoubleEndedIterator for BlockSlices<I>
300where
301 I: TxnDoubleEndedIterator<Item = ItemPtr>,
302{
303 fn next_back<T: ReadTxn>(&mut self, txn: &T) -> Option<Self::Item> {
304 let ptr = self.0.next_back(txn)?;
305 Some(ptr.into())
306 }
307}
308
309/// Iterator over a slice of a continuous sequence of blocks.
310#[derive(Debug)]
311pub(crate) struct RangeIter<I> {
312 iter: I,
313 start: StickyIndex,
314 end: StickyIndex,
315 state: RangeIterState,
316}
317
318impl<I> RangeIter<I>
319where
320 I: TxnIterator<Item = ItemPtr>,
321{
322 fn new(iter: I, start: StickyIndex, end: StickyIndex) -> Self {
323 RangeIter {
324 iter,
325 start,
326 end,
327 state: RangeIterState::Opened,
328 }
329 }
330
331 fn begin<T: ReadTxn>(&mut self, txn: &T, start_offset: &mut u32) -> Option<ItemPtr> {
332 let mut offset = 0;
333 let mut curr = self.iter.next(txn);
334 while let Some(ptr) = curr {
335 match self.start.id() {
336 None => {
337 self.state = RangeIterState::InRange;
338 break;
339 }
340 Some(start) if ptr.contains(start) => {
341 self.state = RangeIterState::InRange;
342 offset = start.clock - ptr.id().clock;
343 if self.start.assoc == Assoc::After {
344 // we need to skip first element in a block
345 offset += 1;
346 if offset == ptr.len() {
347 // we're at the last element in a block, move to next block
348 offset = 0;
349 curr = self.iter.next(txn);
350 }
351 }
352 break;
353 }
354 _ => curr = self.iter.next(txn),
355 }
356 }
357 *start_offset = offset;
358 curr
359 }
360}
361
362impl<I> TxnIterator for RangeIter<I>
363where
364 I: TxnIterator<Item = ItemPtr>,
365{
366 type Item = ItemSlice;
367
368 fn next<T: ReadTxn>(&mut self, txn: &T) -> Option<Self::Item> {
369 let mut start_offset = 0;
370 let ptr = match self.state {
371 RangeIterState::Opened => {
372 // we just opened an iterator, we might not yet be in range
373 self.begin(txn, &mut start_offset)
374 }
375 RangeIterState::InRange => self.iter.next(txn),
376 RangeIterState::Closed => return None,
377 }?;
378 let end_offset = match self.end.id() {
379 Some(end) if ptr.contains(end) => {
380 self.state = RangeIterState::Closed;
381 let mut offset = end.clock - ptr.id().clock;
382 if self.end.assoc == Assoc::Before {
383 // we need to exclude last element
384 if offset == start_offset {
385 // last slice is empty - has no elements
386 return None;
387 }
388 offset -= 1;
389 }
390 offset
391 }
392 _ => ptr.len() - 1,
393 };
394 Some(ItemSlice::new(ptr, start_offset, end_offset))
395 }
396}
397
398impl<I> TxnDoubleEndedIterator for RangeIter<I>
399where
400 I: TxnDoubleEndedIterator<Item = ItemPtr>,
401{
402 fn next_back<T: ReadTxn>(&mut self, txn: &T) -> Option<Self::Item> {
403 let mut end_offset = 0;
404 let ptr = match self.state {
405 RangeIterState::InRange => self.iter.next_back(txn),
406 RangeIterState::Opened => {
407 let mut curr = self.iter.next_back(txn);
408 while let Some(ptr) = curr {
409 end_offset = ptr.len();
410 match self.end.id() {
411 None => {
412 self.state = RangeIterState::InRange;
413 break;
414 }
415 Some(end) if ptr.contains(end) => {
416 self.state = RangeIterState::InRange;
417 end_offset = end.clock - ptr.id().clock;
418 break;
419 }
420 _ => curr = self.iter.next_back(txn),
421 }
422 }
423 curr
424 }
425 RangeIterState::Closed => return None,
426 }?;
427 let start_offset = match self.start.id() {
428 Some(start) if ptr.contains(start) => {
429 self.state = RangeIterState::Closed;
430 start.clock - ptr.id().clock
431 }
432 _ => 0,
433 };
434 Some(ItemSlice::new(ptr, start_offset, end_offset))
435 }
436}
437
438#[derive(Debug, Copy, Clone, Eq, PartialEq)]
439enum RangeIterState {
440 /// Ranged iterator position hasn't reach chosen ID range yet.
441 Opened,
442 /// Ranged iterator position is inside of a chosen ID range.
443 InRange,
444 /// Ranged iterator position moved beyond chosen ID range.
445 Closed,
446}
447
448/// Iterator over particular, non-deleted values of a block sequence.
449#[derive(Debug)]
450pub(crate) struct Values<I> {
451 iter: I,
452 current: Option<ItemSlice>,
453}
454
455impl<I> Values<I> {
456 fn new(iter: I) -> Self {
457 Values {
458 iter,
459 current: None,
460 }
461 }
462}
463
464impl<I> TxnIterator for Values<I>
465where
466 I: TxnIterator<Item = ItemSlice>,
467{
468 type Item = Out;
469
470 fn next<T: ReadTxn>(&mut self, txn: &T) -> Option<Self::Item> {
471 loop {
472 if let Some(slice) = &mut self.current {
473 if slice.start <= slice.end {
474 let item = slice.ptr.deref();
475 if !item.is_deleted() {
476 let mut buf = [Out::default()];
477 let read = item.content.read(slice.start as usize, &mut buf);
478 if read != 0 {
479 slice.start += read as u32;
480 return Some(std::mem::take(&mut buf[0]));
481 }
482 }
483 }
484 }
485 self.current = Some(self.iter.next(txn)?);
486 }
487 }
488
489 fn collect<T, B>(&mut self, txn: &T) -> B
490 where
491 T: ReadTxn,
492 B: Default + Extend<Self::Item>,
493 {
494 fn read_slice<B>(slice: ItemSlice, buf: &mut B)
495 where
496 B: Extend<Out>,
497 {
498 let item = slice.ptr.deref();
499 if !item.is_deleted() {
500 let size = slice.end - slice.start + 1;
501 let mut b: SmallVec<[Out; 2]> = smallvec![Out::default(); size as usize];
502 let _ = item.content.read(slice.start as usize, b.as_mut_slice());
503 buf.extend(b);
504 }
505 }
506
507 let mut buf = B::default();
508 if let Some(slice) = self.current.take() {
509 read_slice(slice, &mut buf);
510 }
511 while let Some(slice) = self.iter.next(txn) {
512 read_slice(slice, &mut buf);
513 }
514 buf
515 }
516}
517
518#[derive(Debug)]
519pub struct AsIter<'a, T, I> {
520 txn: &'a T,
521 iter: I,
522}
523
524impl<'a, T, I> AsIter<'a, T, I>
525where
526 T: ReadTxn,
527 I: TxnIterator,
528{
529 pub fn new(iter: I, txn: &'a T) -> Self {
530 AsIter { txn, iter }
531 }
532}
533
534impl<'a, T, I> Iterator for AsIter<'a, T, I>
535where
536 T: ReadTxn,
537 I: TxnIterator,
538{
539 type Item = I::Item;
540
541 fn next(&mut self) -> Option<Self::Item> {
542 self.iter.next(self.txn)
543 }
544}
545
546#[cfg(test)]
547mod test {
548 use crate::iter::{BlockIterator, BlockSliceIterator, IntoBlockIter, TxnIterator};
549 use crate::test_utils::exchange_updates;
550 use crate::{Array, Assoc, Doc, StickyIndex, Transact, ID};
551
552 #[test]
553 fn move_last_elem_iter() {
554 let doc = Doc::with_client_id(1);
555 let array = doc.get_or_insert_array("array");
556 let mut txn = doc.transact_mut();
557 array.insert_range(&mut txn, 0, [1, 2, 3]);
558 drop(txn);
559
560 let mut txn = doc.transact_mut();
561 array.move_to(&mut txn, 2, 0);
562
563 let start = array.as_ref().start;
564 let mut i = start.to_iter().moved().slices().values();
565 assert_eq!(i.next(&txn), Some(3.into()));
566 assert_eq!(i.next(&txn), Some(1.into()));
567 assert_eq!(i.next(&txn), Some(2.into()));
568 assert_eq!(i.next(&txn), None);
569 }
570
571 #[test]
572 fn move_1() {
573 let d1 = Doc::with_client_id(1);
574 let a1 = d1.get_or_insert_array("array");
575
576 let d2 = Doc::with_client_id(2);
577 let a2 = d2.get_or_insert_array("array");
578
579 {
580 let mut txn = d1.transact_mut();
581 a1.insert_range(&mut txn, 0, [1, 2, 3]);
582 a1.move_to(&mut txn, 1, 0);
583 }
584 {
585 let txn = d1.transact();
586 let mut i = a1.as_ref().start.to_iter().moved().slices().values();
587 assert_eq!(i.next(&txn), Some(2.into()));
588 assert_eq!(i.next(&txn), Some(1.into()));
589 assert_eq!(i.next(&txn), Some(3.into()));
590 assert_eq!(i.next(&txn), None);
591 }
592
593 exchange_updates(&[&d1, &d2]);
594 {
595 let txn = d2.transact();
596 let mut i = a2.as_ref().start.to_iter().moved().slices().values();
597 assert_eq!(i.next(&txn), Some(2.into()));
598 assert_eq!(i.next(&txn), Some(1.into()));
599 assert_eq!(i.next(&txn), Some(3.into()));
600 assert_eq!(i.next(&txn), None);
601 }
602
603 a1.move_to(&mut d1.transact_mut(), 0, 2);
604
605 {
606 let txn = d1.transact();
607 let mut i = a1.as_ref().start.to_iter().moved().slices().values();
608 assert_eq!(i.next(&txn), Some(1.into()));
609 assert_eq!(i.next(&txn), Some(2.into()));
610 assert_eq!(i.next(&txn), Some(3.into()));
611 assert_eq!(i.next(&txn), None);
612 }
613 }
614
615 #[test]
616 fn move_2() {
617 let d1 = Doc::with_client_id(1);
618 let a1 = d1.get_or_insert_array("array");
619
620 let d2 = Doc::with_client_id(2);
621 let a2 = d2.get_or_insert_array("array");
622
623 a1.insert_range(&mut d1.transact_mut(), 0, [1, 2]);
624 a1.move_to(&mut d1.transact_mut(), 1, 0);
625 {
626 let txn = d1.transact();
627 let mut i = a1.as_ref().start.to_iter().moved().slices().values();
628 assert_eq!(i.next(&txn), Some(2.into()));
629 assert_eq!(i.next(&txn), Some(1.into()));
630 assert_eq!(i.next(&txn), None);
631 }
632
633 exchange_updates(&[&d1, &d2]);
634
635 {
636 let txn = d2.transact();
637 let mut i = a2.as_ref().start.to_iter().moved().slices().values();
638 assert_eq!(i.next(&txn), Some(2.into()));
639 assert_eq!(i.next(&txn), Some(1.into()));
640 assert_eq!(i.next(&txn), None);
641 }
642
643 a1.move_to(&mut d1.transact_mut(), 0, 2);
644 {
645 let txn = d1.transact();
646 let mut i = a1.as_ref().start.to_iter().moved().slices().values();
647 assert_eq!(i.next(&txn), Some(1.into()));
648 assert_eq!(i.next(&txn), Some(2.into()));
649 assert_eq!(i.next(&txn), None);
650 }
651 }
652
653 #[test]
654 fn move_cycles() {
655 let d1 = Doc::with_client_id(1);
656 let a1 = d1.get_or_insert_array("array");
657
658 let d2 = Doc::with_client_id(2);
659 let a2 = d2.get_or_insert_array("array");
660
661 a1.insert_range(&mut d1.transact_mut(), 0, [1, 2, 3, 4]);
662 exchange_updates(&[&d1, &d2]);
663
664 a1.move_range_to(&mut d1.transact_mut(), 0, Assoc::After, 1, Assoc::Before, 3);
665 {
666 let txn = d1.transact();
667 let mut i = a1.as_ref().start.to_iter().moved().slices().values();
668 assert_eq!(i.next(&txn), Some(3.into()));
669 assert_eq!(i.next(&txn), Some(1.into()));
670 assert_eq!(i.next(&txn), Some(2.into()));
671 assert_eq!(i.next(&txn), Some(4.into()));
672 assert_eq!(i.next(&txn), None);
673 }
674
675 a2.move_range_to(&mut d2.transact_mut(), 2, Assoc::After, 3, Assoc::Before, 1);
676 {
677 let txn = d2.transact();
678 let mut i = a2.as_ref().start.to_iter().moved().slices().values();
679 assert_eq!(i.next(&txn), Some(1.into()));
680 assert_eq!(i.next(&txn), Some(3.into()));
681 assert_eq!(i.next(&txn), Some(4.into()));
682 assert_eq!(i.next(&txn), Some(2.into()));
683 assert_eq!(i.next(&txn), None);
684 }
685
686 exchange_updates(&[&d1, &d2]);
687 exchange_updates(&[&d1, &d2]); // move cycles may not be detected within a single update exchange
688
689 let t1 = d1.transact();
690 let v1: Vec<_> = a1
691 .as_ref()
692 .start
693 .to_iter()
694 .moved()
695 .slices()
696 .values()
697 .collect(&t1);
698 let t2 = d2.transact();
699 let v2: Vec<_> = a2
700 .as_ref()
701 .start
702 .to_iter()
703 .moved()
704 .slices()
705 .values()
706 .collect(&t2);
707
708 assert_eq!(v1, v2);
709 }
710
711 #[test]
712 fn range_bounded() {
713 let doc = Doc::with_client_id(1);
714 let array = doc.get_or_insert_array("array");
715
716 array.insert_range(&mut doc.transact_mut(), 0, [2, 3, 4]);
717 array.insert_range(&mut doc.transact_mut(), 0, [1]);
718 array.insert_range(&mut doc.transact_mut(), 4, [5, 6]);
719
720 let txn = doc.transact();
721 let from = StickyIndex::from_id(ID::new(1, 1), Assoc::Before);
722 let to = StickyIndex::from_id(ID::new(1, 4), Assoc::After);
723 let res: Vec<_> = array
724 .as_ref()
725 .start
726 .to_iter()
727 .moved()
728 .within_range(from, to)
729 .values()
730 .collect(&txn);
731 assert_eq!(res, vec![3.into(), 4.into(), 5.into()])
732 }
733
734 #[test]
735 fn range_left_exclusive() {
736 let doc = Doc::with_client_id(1);
737 let array = doc.get_or_insert_array("array");
738
739 array.insert_range(&mut doc.transact_mut(), 0, [2, 3, 4]);
740 array.insert_range(&mut doc.transact_mut(), 0, [1]);
741 array.insert_range(&mut doc.transact_mut(), 4, [5, 6]);
742
743 let txn = doc.transact();
744 let from = StickyIndex::from_id(ID::new(1, 1), Assoc::After);
745 let to = StickyIndex::from_id(ID::new(1, 4), Assoc::After);
746 let res: Vec<_> = array
747 .as_ref()
748 .start
749 .to_iter()
750 .moved()
751 .within_range(from, to)
752 .values()
753 .collect(&txn);
754 assert_eq!(res, vec![4.into(), 5.into()])
755 }
756
757 #[test]
758 fn range_left_exclusive_2() {
759 let doc = Doc::with_client_id(1);
760 let array = doc.get_or_insert_array("array");
761
762 array.insert_range(&mut doc.transact_mut(), 0, [2, 3, 4]);
763 array.insert_range(&mut doc.transact_mut(), 0, [1]);
764 array.insert_range(&mut doc.transact_mut(), 4, [5, 6]);
765
766 let txn = doc.transact();
767 let from = StickyIndex::from_id(ID::new(1, 2), Assoc::After);
768 let to = StickyIndex::from_id(ID::new(1, 4), Assoc::After);
769 let res: Vec<_> = array
770 .as_ref()
771 .start
772 .to_iter()
773 .moved()
774 .within_range(from, to)
775 .values()
776 .collect(&txn);
777 assert_eq!(res, vec![5.into()])
778 }
779
780 #[test]
781 fn range_right_exclusive() {
782 let doc = Doc::with_client_id(1);
783 let array = doc.get_or_insert_array("array");
784
785 array.insert_range(&mut doc.transact_mut(), 0, [2, 3, 4]);
786 array.insert_range(&mut doc.transact_mut(), 0, [1]);
787 array.insert_range(&mut doc.transact_mut(), 4, [5, 6]);
788
789 let txn = doc.transact();
790 let from = StickyIndex::from_id(ID::new(1, 1), Assoc::Before);
791 let to = StickyIndex::from_id(ID::new(1, 5), Assoc::Before);
792 let res: Vec<_> = array
793 .as_ref()
794 .start
795 .to_iter()
796 .moved()
797 .within_range(from, to)
798 .values()
799 .collect(&txn);
800 assert_eq!(res, vec![3.into(), 4.into(), 5.into()])
801 }
802
803 #[test]
804 fn range_right_exclusive_2() {
805 let doc = Doc::with_client_id(1);
806 let array = doc.get_or_insert_array("array");
807
808 array.insert_range(&mut doc.transact_mut(), 0, [2, 3, 4]);
809 array.insert_range(&mut doc.transact_mut(), 0, [1]);
810 array.insert_range(&mut doc.transact_mut(), 4, [5, 6]);
811
812 let txn = doc.transact();
813 let from = StickyIndex::from_id(ID::new(1, 1), Assoc::Before);
814 let to = StickyIndex::from_id(ID::new(1, 4), Assoc::Before);
815 let res: Vec<_> = array
816 .as_ref()
817 .start
818 .to_iter()
819 .moved()
820 .within_range(from, to)
821 .values()
822 .collect(&txn);
823 assert_eq!(res, vec![3.into(), 4.into()])
824 }
825
826 #[test]
827 fn range_unbounded() {
828 let doc = Doc::with_client_id(1);
829 let array = doc.get_or_insert_array("array");
830
831 array.insert_range(&mut doc.transact_mut(), 0, [2, 3, 4]);
832 array.insert_range(&mut doc.transact_mut(), 0, [1]);
833 array.insert_range(&mut doc.transact_mut(), 4, [5, 6]);
834
835 let txn = doc.transact();
836 let from = StickyIndex::from_type(&txn, &array, Assoc::Before);
837 let to = StickyIndex::from_type(&txn, &array, Assoc::After);
838 let res: Vec<_> = array
839 .as_ref()
840 .start
841 .to_iter()
842 .moved()
843 .within_range(from, to)
844 .values()
845 .collect(&txn);
846 assert_eq!(
847 res,
848 vec![1.into(), 2.into(), 3.into(), 4.into(), 5.into(), 6.into()]
849 )
850 }
851
852 #[test]
853 fn range_left_unbounded() {
854 let doc = Doc::with_client_id(1);
855 let array = doc.get_or_insert_array("array");
856
857 array.insert_range(&mut doc.transact_mut(), 0, [2, 3, 4]);
858 array.insert_range(&mut doc.transact_mut(), 0, [1]);
859 array.insert_range(&mut doc.transact_mut(), 4, [5, 6]);
860
861 let txn = doc.transact();
862 let from = StickyIndex::from_type(&txn, &array, Assoc::Before);
863 let to = StickyIndex::from_id(ID::new(1, 2), Assoc::After);
864 let res: Vec<_> = array
865 .as_ref()
866 .start
867 .to_iter()
868 .moved()
869 .within_range(from, to)
870 .values()
871 .collect(&txn);
872 assert_eq!(res, vec![1.into(), 2.into(), 3.into(), 4.into()])
873 }
874
875 #[test]
876 fn range_right_unbounded() {
877 let doc = Doc::with_client_id(1);
878 let array = doc.get_or_insert_array("array");
879
880 array.insert_range(&mut doc.transact_mut(), 0, [2, 3, 4]);
881 array.insert_range(&mut doc.transact_mut(), 0, [1]);
882 array.insert_range(&mut doc.transact_mut(), 4, [5, 6]);
883
884 let txn = doc.transact();
885 let from = StickyIndex::from_id(ID::new(1, 2), Assoc::Before);
886 let to = StickyIndex::from_type(&txn, &array, Assoc::After);
887 let res: Vec<_> = array
888 .as_ref()
889 .start
890 .to_iter()
891 .moved()
892 .within_range(from, to)
893 .values()
894 .collect(&txn);
895 assert_eq!(res, vec![4.into(), 5.into(), 6.into()])
896 }
897
898 #[test]
899 fn range_single_slice() {
900 let doc = Doc::with_client_id(1);
901 let array = doc.get_or_insert_array("array");
902
903 array.insert_range(&mut doc.transact_mut(), 0, [2, 3, 4]);
904 array.insert_range(&mut doc.transact_mut(), 0, [1]);
905 array.insert_range(&mut doc.transact_mut(), 4, [5, 6]);
906
907 let txn = doc.transact();
908 let from = StickyIndex::from_id(ID::new(1, 1), Assoc::Before);
909 let to = StickyIndex::from_id(ID::new(1, 1), Assoc::After);
910 let res: Vec<_> = array
911 .as_ref()
912 .start
913 .to_iter()
914 .moved()
915 .within_range(from, to)
916 .values()
917 .collect(&txn);
918 assert_eq!(res, vec![3.into()])
919 }
920}
921