Skip to main content

im_rope/
accessor.rs

1//! Lending iterators over vectors, with flexible ownership.
2//!
3//! Accessors are what make it possible for all of [`Rope`](super::Rope)'s
4//! various iterators to implement [`IntoOwning`]. They are mostly an
5//! implementation detail, but they do show up as generic arguments in type
6//! signatures, and so this module is exposed and documented. You cannot
7//! directly construct or use an `Accessor` through any of `im-rope`'s public
8//! APIs, but you can tell whether an iterator borrows or owns its underlying
9//! rope based on whether it has a `BorrowingAccessor<'a>` or an
10//! `OwningAccessor` in its type.
11
12use im::vector;
13use im::vector::Vector;
14use sealed::sealed;
15use static_cow::{IntoOwning, ToOwning};
16use std::iter::FusedIterator;
17use std::mem::MaybeUninit;
18use std::ops::Range;
19
20/// Owns a `Vector<u8>` along with a `Focus` which references it.
21
22// SAFETY invariants:
23// 1. `vector` is valid.
24// 2. `focus` is initialized with something that can be
25//    safely transmuted into `Focus<'a, u8>` where `Self: 'a`.
26
27struct OwningFocus {
28    vector: *mut Vector<u8>,
29    focus: MaybeUninit<vector::Focus<'static, u8>>,
30}
31
32impl OwningFocus {
33    fn new(vector: Box<Vector<u8>>) -> OwningFocus {
34        let vector_ref = Box::leak(vector);
35        let vector_ptr = vector_ref as *mut Vector<u8>;
36        let focus = MaybeUninit::new(vector_ref.focus());
37
38        // SAFETY:
39        // 1. `vector` is valid.
40        // 2. `focus` is initialized with a focus borrowed from `vector`,
41        //    so it's safe to give it a lifetime bounded by self.
42        OwningFocus {
43            vector: vector_ptr,
44            focus,
45        }
46    }
47
48    /// Access the underlying vector.
49    fn as_vector(&self) -> &Vector<u8> {
50        // SAFETY: per the first invariant.
51        unsafe { &*self.vector }
52    }
53
54    fn as_focus(&mut self) -> &mut vector::Focus<'_, u8> {
55        // SAFETY: per the second invariant.
56        unsafe { std::mem::transmute(self.focus.assume_init_mut()) }
57    }
58
59    fn update<F, R>(&mut self, f: F) -> R
60    where
61        F: FnOnce(&mut Vector<u8>) -> R,
62    {
63        unsafe {
64            // SAFETY: the invariants assure that these two calls are safe, but
65            // afterward `focus` is uninitialized which breaks the second
66            // invariant. We need to make sure it gets reinitialized before we
67            // return.
68            let call_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
69                self.focus.assume_init_drop();
70                f(&mut *self.vector)
71            }));
72
73            // Here, whether or not there was a panic, `vector` is still in some
74            // valid (though perhaps weird) state, while `focus` presumptively
75            // needs to be reinitialized.
76            let focus_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
77                self.focus.write((*self.vector).focus());
78            }));
79
80            if focus_result.is_err() {
81                // Safety necessitates that `focus` be initialized when we exit
82                // from this method, so if we fail at initializing it then the
83                // only safe course is to abort.
84                std::process::abort();
85            };
86
87            // Now the invariant is restored and we can either return or resume
88            // panicking.
89            match call_result {
90                Ok(r) => r,
91                Err(payload) => std::panic::resume_unwind(payload),
92            }
93        }
94    }
95
96    /// Access the byte at `index`.
97    fn index(&mut self, index: usize) -> u8 {
98        *self.as_focus().index(index)
99    }
100
101    /// Access the chunk at `index`.
102    fn chunk_at(&mut self, index: usize) -> (Range<usize>, &[u8]) {
103        self.as_focus().chunk_at(index)
104    }
105}
106
107impl Clone for OwningFocus {
108    fn clone(&self) -> Self {
109        OwningFocus::new(Box::new(self.as_vector().clone()))
110    }
111}
112
113impl Drop for OwningFocus {
114    fn drop(&mut self) {
115        // SAFETY: `vector` is valid per the first invariant, and `focus` is
116        // initialized per the second invariant.
117        unsafe {
118            self.focus.assume_init_drop();
119            std::mem::drop(Box::from_raw(self.vector));
120        }
121    }
122}
123
124/// An [`Accessor`] which borrows its underlying `Vector<u8>`.
125#[allow(clippy::module_name_repetitions)]
126pub struct BorrowingAccessor<'a> {
127    vector: &'a Vector<u8>,
128    focus: vector::Focus<'a, u8>,
129    front_index: usize,
130    back_index: usize,
131}
132
133impl<'a> BorrowingAccessor<'a> {
134    pub(crate) fn new(vector: &'a Vector<u8>) -> BorrowingAccessor<'a> {
135        BorrowingAccessor {
136            vector,
137            focus: vector.focus(),
138            front_index: 0,
139            back_index: vector.len(),
140        }
141    }
142}
143
144impl<'a> ToOwning for BorrowingAccessor<'a> {
145    type Owning = OwningAccessor;
146
147    fn to_owning(&self) -> Self::Owning {
148        OwningAccessor::from_borrowed(self.vector, self.front_index, self.back_index)
149    }
150}
151
152impl<'a> IntoOwning for BorrowingAccessor<'a> {
153    fn into_owning(self) -> Self::Owning {
154        self.to_owning()
155    }
156}
157
158/// An [`Accessor`] which owns its underlying `Vector<u8>`.
159///
160/// An `OwningAccessor` will, at exponential intervals, "garbage collect" the
161/// portion of the vector which it has already returned. An `OwningAccessor`'s
162/// worst-case space consumption is therefore big-O linear in the unconsumed
163/// portion of the vector, rather than linear in the size of the entire vector.
164#[derive(Clone)]
165#[allow(clippy::module_name_repetitions)]
166pub struct OwningAccessor {
167    focus: OwningFocus,
168    /// The index of the next byte to be returned from the front, relative to
169    /// the original vector this accessor was constructed from.
170    proper_front_index: usize,
171    /// The index+1 of the next byte to be returned from the back, relative to
172    /// the *original* vector this accessor was constructed from.
173    proper_back_index: usize,
174    /// The index, relative to the original vector this accessor was constructed
175    /// from, of the first byte still held by `focus`.
176    focal_front_index: usize,
177    /// The index+1, relative to the original vector this accessor was constructed
178    /// from, of the last byte still held by `focus`.
179    focal_back_index: usize,
180}
181
182impl OwningAccessor {
183    pub(crate) fn new(vector: Vector<u8>) -> OwningAccessor {
184        let len = vector.len();
185        OwningAccessor {
186            focus: OwningFocus::new(Box::new(vector)),
187            proper_front_index: 0,
188            proper_back_index: len,
189            focal_front_index: 0,
190            focal_back_index: len,
191        }
192    }
193
194    fn from_borrowed(vector: &Vector<u8>, front_index: usize, back_index: usize) -> OwningAccessor {
195        let mut owning = OwningAccessor {
196            focus: OwningFocus::new(Box::new(vector.clone())),
197            proper_front_index: front_index,
198            proper_back_index: back_index,
199            focal_front_index: 0,
200            focal_back_index: vector.len(),
201        };
202
203        owning.gc();
204        owning
205    }
206
207    fn gc(&mut self) {
208        let cur_len = self.proper_back_index - self.proper_front_index;
209        let orig_len = self.focal_back_index - self.focal_front_index;
210
211        if orig_len > 256 && orig_len / 2 >= cur_len {
212            self.focus.update(|vector| {
213                *vector = vector.split_off(self.proper_front_index - self.focal_front_index);
214                vector.truncate(self.proper_back_index - self.proper_front_index);
215            });
216            self.focal_front_index = self.proper_front_index;
217            self.focal_back_index = self.proper_back_index;
218        }
219    }
220}
221
222/// An iterator over the bytes of an `Accessor`.
223pub struct ByteIter<'a, A>(&'a mut A);
224
225/// A double-ended lending iterator over a `Vector<u8>`.
226#[sealed]
227pub trait Accessor: IntoOwning<Owning = OwningAccessor> {
228    /// Consumes the frontmost byte and returns it along with its index.
229    fn front_byte(&mut self) -> Option<(usize, u8)>;
230    /// Consumes the backmost byte and returns it along with its index.
231    fn back_byte(&mut self) -> Option<(usize, u8)>;
232    /// Consumes the frontmost chunk and returns a reference to it along with
233    /// the range it covers.
234    fn front_chunk(&mut self) -> Option<(Range<usize>, &[u8])>;
235    /// Consumes the backmost chunk and returns a refernence to it along with
236    /// the range it covers.
237    fn back_chunk(&mut self) -> Option<(Range<usize>, &[u8])>;
238
239    /// Consumes everything from the first unconsumed byte up to `index` and returns
240    /// it as a new vector.
241    fn take_front(&mut self, index: usize) -> Vector<u8>;
242    /// Consumes everything from `index` to the backmost unconsumed byte and returns
243    /// it as a new vector.
244    fn take_back(&mut self, index: usize) -> Vector<u8>;
245
246    /// Returns the index of the frontmost unconsumed byte.
247    #[must_use]
248    fn front_index(&self) -> usize;
249    /// Returns the index+1 of the backmost unconsumed byte.
250    #[must_use]
251    fn back_index(&self) -> usize;
252
253    /// Returns a consuming iterator over the accessor's bytes.
254    fn byte_iter(&mut self) -> ByteIter<'_, Self> {
255        ByteIter(self)
256    }
257
258    /// Clones the accessor.
259    ///
260    /// This is really just `clone`. It's "shallow" in the sense that it just
261    /// won't turn a borrowing accessor into an owning one, and just copies the
262    /// reference. Due to a limitation of [`static_cow`] and Rust's coherence
263    /// rules, it isn't possible to have both a `Clone` implementation and a
264    /// non-trivial `IntoOwning` implementation.
265    #[must_use]
266    fn shallow_clone(&self) -> Self;
267}
268
269impl<'a, A> Iterator for ByteIter<'a, A>
270where
271    A: Accessor,
272{
273    type Item = u8;
274
275    fn next(&mut self) -> Option<Self::Item> {
276        Some(self.0.front_byte()?.1)
277    }
278
279    fn size_hint(&self) -> (usize, Option<usize>) {
280        let len = self.0.back_index() - self.0.front_index();
281        (len, Some(len))
282    }
283
284    fn last(mut self) -> Option<Self::Item> {
285        self.next_back()
286    }
287}
288
289impl<'a, A> DoubleEndedIterator for ByteIter<'a, A>
290where
291    A: Accessor,
292{
293    fn next_back(&mut self) -> Option<Self::Item> {
294        Some(self.0.back_byte()?.1)
295    }
296}
297
298impl<'a, A> FusedIterator for ByteIter<'a, A> where A: Accessor {}
299
300impl<'a, A> ExactSizeIterator for ByteIter<'a, A> where A: Accessor {}
301
302#[sealed]
303impl<'a> Accessor for BorrowingAccessor<'a> {
304    fn front_byte(&mut self) -> Option<(usize, u8)> {
305        if self.front_index == self.back_index {
306            None
307        } else {
308            let byte = *self.focus.index(self.front_index);
309            let index = self.front_index;
310            self.front_index += 1;
311            Some((index, byte))
312        }
313    }
314
315    fn back_byte(&mut self) -> Option<(usize, u8)> {
316        if self.front_index == self.back_index {
317            None
318        } else {
319            self.back_index -= 1;
320            Some((self.back_index, *self.focus.index(self.back_index)))
321        }
322    }
323
324    fn front_chunk(&mut self) -> Option<(Range<usize>, &[u8])> {
325        if self.front_index == self.back_index {
326            None
327        } else {
328            let (unclamped_range, unclamped_chunk) = self.focus.chunk_at(self.front_index);
329            let clamped_range = std::cmp::max(unclamped_range.start, self.front_index)
330                ..std::cmp::min(unclamped_range.end, self.back_index);
331            let cut_range = (clamped_range.start - unclamped_range.start)
332                ..(unclamped_chunk.len() - (unclamped_range.end - clamped_range.end));
333            self.front_index = clamped_range.end;
334            Some((clamped_range, &unclamped_chunk[cut_range]))
335        }
336    }
337
338    fn back_chunk(&mut self) -> Option<(Range<usize>, &[u8])> {
339        if self.front_index == self.back_index {
340            None
341        } else {
342            let (unclamped_range, unclamped_chunk) = self.focus.chunk_at(self.back_index - 1);
343            let clamped_range = std::cmp::max(unclamped_range.start, self.front_index)
344                ..std::cmp::min(unclamped_range.end, self.back_index);
345            let cut_range = (clamped_range.start - unclamped_range.start)
346                ..(unclamped_chunk.len() - (unclamped_range.end - clamped_range.end));
347            self.back_index = clamped_range.start;
348            Some((clamped_range, &unclamped_chunk[cut_range]))
349        }
350    }
351
352    fn take_front(&mut self, index: usize) -> Vector<u8> {
353        let mut vector = self.vector.skip(self.front_index);
354        vector.truncate(index - self.front_index);
355        self.front_index = index;
356        vector
357    }
358
359    fn take_back(&mut self, index: usize) -> Vector<u8> {
360        let mut vector = self.vector.skip(index);
361        vector.truncate(self.back_index - index);
362        self.back_index = index;
363        vector
364    }
365
366    fn front_index(&self) -> usize {
367        self.front_index
368    }
369
370    fn back_index(&self) -> usize {
371        self.back_index
372    }
373
374    fn shallow_clone(&self) -> Self {
375        BorrowingAccessor {
376            vector: self.vector,
377            focus: self.focus.clone(),
378            front_index: self.front_index,
379            back_index: self.back_index,
380        }
381    }
382}
383
384#[sealed]
385impl Accessor for OwningAccessor {
386    fn front_byte(&mut self) -> Option<(usize, u8)> {
387        if self.proper_front_index == self.proper_back_index {
388            None
389        } else {
390            let byte = self
391                .focus
392                .index(self.proper_front_index - self.focal_front_index);
393            let index = self.proper_front_index;
394            self.proper_front_index += 1;
395            self.gc();
396            Some((index, byte))
397        }
398    }
399
400    fn back_byte(&mut self) -> Option<(usize, u8)> {
401        if self.proper_front_index == self.proper_back_index {
402            None
403        } else {
404            self.proper_back_index -= 1;
405            let byte = self
406                .focus
407                .index(self.proper_back_index - self.focal_front_index);
408            self.gc();
409            Some((self.proper_back_index, byte))
410        }
411    }
412
413    fn front_chunk(&mut self) -> Option<(Range<usize>, &[u8])> {
414        if self.proper_front_index == self.proper_back_index {
415            None
416        } else {
417            self.gc();
418            let (focal_range, chunk) = self
419                .focus
420                .chunk_at(self.proper_front_index - self.focal_front_index);
421            let unclamped_proper_range = focal_range.start + self.focal_front_index
422                ..focal_range.end + self.focal_front_index;
423            let clamped_proper_range =
424                std::cmp::max(unclamped_proper_range.start, self.proper_front_index)
425                    ..std::cmp::min(unclamped_proper_range.end, self.proper_back_index);
426            let cut_range = (clamped_proper_range.start - unclamped_proper_range.start)
427                ..(focal_range.len() - (unclamped_proper_range.end - clamped_proper_range.end));
428
429            self.proper_front_index = clamped_proper_range.end;
430            Some((clamped_proper_range, &chunk[cut_range]))
431        }
432    }
433
434    fn back_chunk(&mut self) -> Option<(Range<usize>, &[u8])> {
435        if self.proper_front_index == self.proper_back_index {
436            None
437        } else {
438            self.gc();
439            let (focal_range, chunk) = self
440                .focus
441                .chunk_at(self.proper_back_index - self.focal_front_index - 1);
442            let unclamped_proper_range = focal_range.start + self.focal_front_index
443                ..focal_range.end + self.focal_front_index;
444            let clamped_proper_range =
445                std::cmp::max(unclamped_proper_range.start, self.proper_front_index)
446                    ..std::cmp::min(unclamped_proper_range.end, self.proper_back_index);
447            let cut_range = (clamped_proper_range.start - unclamped_proper_range.start)
448                ..(focal_range.len() - (unclamped_proper_range.end - clamped_proper_range.end));
449
450            self.proper_back_index = clamped_proper_range.start;
451            Some((clamped_proper_range, &chunk[cut_range]))
452        }
453    }
454
455    fn take_front(&mut self, index: usize) -> Vector<u8> {
456        let mut vector = self
457            .focus
458            .as_vector()
459            .skip(self.proper_front_index - self.focal_front_index);
460        vector.truncate(index - self.proper_front_index);
461        self.proper_front_index = index;
462        self.gc();
463        vector
464    }
465
466    fn take_back(&mut self, index: usize) -> Vector<u8> {
467        let mut vector = self.focus.as_vector().skip(index - self.focal_front_index);
468        vector.truncate(self.proper_back_index - index);
469        self.proper_back_index = index;
470        self.gc();
471        vector
472    }
473
474    fn front_index(&self) -> usize {
475        self.proper_front_index
476    }
477
478    fn back_index(&self) -> usize {
479        self.proper_back_index
480    }
481
482    fn shallow_clone(&self) -> Self {
483        self.clone()
484    }
485}
486
487pub(crate) struct PopVecBytes<'a>(pub(crate) &'a mut Vector<u8>);
488
489impl<'a> Iterator for PopVecBytes<'a> {
490    type Item = u8;
491
492    fn next(&mut self) -> Option<Self::Item> {
493        self.0.pop_front()
494    }
495
496    fn size_hint(&self) -> (usize, Option<usize>) {
497        (self.0.len(), Some(self.0.len()))
498    }
499
500    fn last(mut self) -> Option<Self::Item> {
501        self.next_back()
502    }
503}
504
505impl<'a> DoubleEndedIterator for PopVecBytes<'a> {
506    fn next_back(&mut self) -> Option<Self::Item> {
507        self.0.pop_back()
508    }
509}
510
511impl<'a> FusedIterator for PopVecBytes<'a> {}
512impl<'a> ExactSizeIterator for PopVecBytes<'a> {}
513
514#[cfg(test)]
515mod tests {
516    use super::*;
517    use crate::test_utils::StreamStrategy;
518    use proptest::prelude::*;
519    use proptest_derive::Arbitrary;
520
521    #[derive(Debug, Copy, Clone, Arbitrary)]
522    enum Instruction {
523        FrontByte,
524        BackByte,
525        FrontChunk,
526        BackChunk,
527        TakeFront,
528        TakeBack,
529    }
530
531    proptest! {
532        #[test]
533        fn accessors_agree(
534            vec in prop::collection::vec(u8::arbitrary(), 0..1024),
535            ratio in 0.0f64 .. 1.0,
536            mut stream in StreamStrategy(Instruction::arbitrary()))
537        {
538            let start_size = vec.len();
539            #[allow(clippy::cast_possible_truncation,clippy::cast_precision_loss,clippy::cast_sign_loss)]
540            let end_size = (ratio * (start_size as f64)).round() as usize;
541            assert!(end_size <= start_size);
542
543            let v = Vector::from(vec);
544
545            let mut borrowing = BorrowingAccessor::new(&v);
546            while borrowing.back_index() - borrowing.front_index() > end_size {
547                match stream.gen() {
548                    Instruction::FrontByte => {
549                        borrowing.front_byte();
550                    }
551                    Instruction::BackByte => {
552                        borrowing.back_byte();
553                    }
554                    Instruction::FrontChunk => {
555                        borrowing.front_chunk();
556                    }
557                    Instruction::BackChunk => {
558                        borrowing.back_chunk();
559                    }
560                    Instruction::TakeFront => {
561                        let i = std::cmp::min(borrowing.front_index() + 32, borrowing.back_index());
562                        borrowing.take_front(i);
563                    }
564                    Instruction::TakeBack => {
565                        let i = std::cmp::max(
566                            borrowing.back_index().saturating_sub(32),
567                            borrowing.front_index());
568
569                        borrowing.take_back(i);
570                    }
571                }
572            }
573
574            let mut owning = borrowing.to_owning();
575
576            while borrowing.front_index() != borrowing.back_index() {
577                prop_assert_eq!(borrowing.front_index(), owning.front_index());
578                prop_assert_eq!(borrowing.back_index(), owning.back_index());
579
580                match stream.gen() {
581                    Instruction::FrontByte => {
582                        prop_assert_eq!(borrowing.front_byte(), owning.front_byte());
583                    }
584                    Instruction::BackByte => {
585                        prop_assert_eq!(borrowing.back_byte(), owning.back_byte());
586                    }
587                    Instruction::FrontChunk => {
588                        prop_assert_eq!(borrowing.front_chunk(), owning.front_chunk());
589                    }
590                    Instruction::BackChunk => {
591                        prop_assert_eq!(borrowing.back_chunk(), owning.back_chunk());
592                    }
593                    Instruction::TakeFront => {
594                        let i = std::cmp::min(borrowing.front_index() + 32, borrowing.back_index());
595                        prop_assert_eq!(borrowing.take_front(i), owning.take_front(i));
596                    }
597                    Instruction::TakeBack => {
598                        let i = std::cmp::max(
599                            borrowing.back_index().saturating_sub(32),
600                            borrowing.front_index(),
601                        );
602                        prop_assert_eq!(borrowing.take_back(i), owning.take_back(i));
603                    }
604                }
605            }
606        }
607    }
608}