term_model/grid/
storage.rs

1use std::cmp::max;
2use std::ops::{Index, IndexMut};
3use std::vec::Drain;
4
5use serde::{Deserialize, Serialize};
6
7use super::Row;
8use crate::grid::GridCell;
9use crate::index::{Column, Line};
10
11/// Maximum number of buffered lines outside of the grid for performance optimization.
12const MAX_CACHE_SIZE: usize = 1_000;
13
14/// A ring buffer for optimizing indexing and rotation.
15///
16/// The [`Storage::rotate`] and [`Storage::rotate_up`] functions are fast modular additions on the
17/// internal [`zero`] field. As compared with [`slice::rotate_left`] which must rearrange items in
18/// memory.
19///
20/// As a consequence, both [`Index`] and [`IndexMut`] are reimplemented for this type to account
21/// for the zeroth element not always being at the start of the allocation.
22///
23/// Because certain [`Vec`] operations are no longer valid on this type, no [`Deref`]
24/// implementation is provided. Anything from [`Vec`] that should be exposed must be done so
25/// manually.
26///
27/// [`slice::rotate_left`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rotate_left
28/// [`Deref`]: std::ops::Deref
29/// [`zero`]: #structfield.zero
30#[derive(Clone, Debug, Deserialize, Serialize)]
31pub struct Storage<T> {
32    inner: Vec<Row<T>>,
33
34    /// Starting point for the storage of rows.
35    ///
36    /// This value represents the starting line offset within the ring buffer. The value of this
37    /// offset may be larger than the `len` itself, and will wrap around to the start to form the
38    /// ring buffer. It represents the bottommost line of the terminal.
39    zero: usize,
40
41    /// Number of visible lines.
42    visible_lines: Line,
43
44    /// Total number of lines currently active in the terminal (scrollback + visible)
45    ///
46    /// Shrinking this length allows reducing the number of lines in the scrollback buffer without
47    /// having to truncate the raw `inner` buffer.
48    /// As long as `len` is bigger than `inner`, it is also possible to grow the scrollback buffer
49    /// without any additional insertions.
50    len: usize,
51}
52
53impl<T: PartialEq> PartialEq for Storage<T> {
54    fn eq(&self, other: &Self) -> bool {
55        // Both storage buffers need to be truncated and zeroed
56        assert_eq!(self.zero, 0);
57        assert_eq!(other.zero, 0);
58
59        self.inner == other.inner && self.len == other.len
60    }
61}
62
63impl<T> Storage<T> {
64    #[inline]
65    pub fn with_capacity(visible_lines: Line, template: Row<T>) -> Storage<T>
66    where
67        T: Clone,
68    {
69        // Initialize visible lines, the scrollback buffer is initialized dynamically
70        let inner = vec![template; visible_lines.0];
71
72        Storage { inner, zero: 0, visible_lines, len: visible_lines.0 }
73    }
74
75    /// Increase the number of lines in the buffer.
76    pub fn grow_visible_lines(&mut self, next: Line, template_row: Row<T>)
77    where
78        T: Clone,
79    {
80        // Number of lines the buffer needs to grow
81        let growage = next - self.visible_lines;
82        self.grow_lines(growage.0, template_row);
83
84        // Update visible lines
85        self.visible_lines = next;
86    }
87
88    /// Grow the number of lines in the buffer, filling new lines with the template.
89    fn grow_lines(&mut self, growage: usize, template_row: Row<T>)
90    where
91        T: Clone,
92    {
93        // Only grow if there are not enough lines still hidden
94        let mut new_growage = 0;
95        if growage > (self.inner.len() - self.len) {
96            // Lines to grow additionally to invisible lines
97            new_growage = growage - (self.inner.len() - self.len);
98
99            // Split off the beginning of the raw inner buffer
100            let mut start_buffer = self.inner.split_off(self.zero);
101
102            // Insert new template rows at the end of the raw inner buffer
103            let mut new_lines = vec![template_row; new_growage];
104            self.inner.append(&mut new_lines);
105
106            // Add the start to the raw inner buffer again
107            self.inner.append(&mut start_buffer);
108        }
109
110        // Update raw buffer length and zero offset
111        self.zero += new_growage;
112        self.len += growage;
113    }
114
115    /// Decrease the number of lines in the buffer.
116    pub fn shrink_visible_lines(&mut self, next: Line) {
117        // Shrink the size without removing any lines
118        let shrinkage = self.visible_lines - next;
119        self.shrink_lines(shrinkage.0);
120
121        // Update visible lines
122        self.visible_lines = next;
123    }
124
125    // Shrink the number of lines in the buffer
126    pub fn shrink_lines(&mut self, shrinkage: usize) {
127        self.len -= shrinkage;
128
129        // Free memory
130        if self.inner.len() > self.len + MAX_CACHE_SIZE {
131            self.truncate();
132        }
133    }
134
135    /// Truncate the invisible elements from the raw buffer.
136    pub fn truncate(&mut self) {
137        self.inner.rotate_left(self.zero);
138        self.inner.truncate(self.len);
139
140        self.zero = 0;
141    }
142
143    /// Dynamically grow the storage buffer at runtime.
144    #[inline]
145    pub fn initialize(&mut self, additional_rows: usize, template: &T, cols: Column)
146    where
147        T: GridCell + Copy,
148    {
149        if self.len + additional_rows > self.inner.len() {
150            let realloc_size = max(additional_rows, MAX_CACHE_SIZE);
151            let mut new = vec![Row::new(cols, template); realloc_size];
152            let mut split = self.inner.split_off(self.zero);
153            self.inner.append(&mut new);
154            self.inner.append(&mut split);
155            self.zero += realloc_size;
156        }
157
158        self.len += additional_rows;
159    }
160
161    #[inline]
162    pub fn len(&self) -> usize {
163        self.len
164    }
165
166    /// Compute actual index in underlying storage given the requested index.
167    #[inline]
168    fn compute_index(&self, requested: usize) -> usize {
169        debug_assert!(requested < self.len);
170
171        let zeroed = self.zero + requested;
172
173        // Use if/else instead of remainder here to improve performance.
174        //
175        // Requires `zeroed` to be smaller than `self.inner.len() * 2`,
176        // but both `self.zero` and `requested` are always smaller than `self.inner.len()`.
177        if zeroed >= self.inner.len() {
178            zeroed - self.inner.len()
179        } else {
180            zeroed
181        }
182    }
183
184    pub fn swap_lines(&mut self, a: Line, b: Line) {
185        let offset = self.inner.len() + self.zero + *self.visible_lines - 1;
186        let a = (offset - *a) % self.inner.len();
187        let b = (offset - *b) % self.inner.len();
188        self.inner.swap(a, b);
189    }
190
191    /// Swap implementation for Row<T>.
192    ///
193    /// Exploits the known size of Row<T> to produce a slightly more efficient
194    /// swap than going through slice::swap.
195    ///
196    /// The default implementation from swap generates 8 movups and 4 movaps
197    /// instructions. This implementation achieves the swap in only 8 movups
198    /// instructions.
199    pub fn swap(&mut self, a: usize, b: usize) {
200        debug_assert_eq!(std::mem::size_of::<Row<T>>(), 32);
201
202        let a = self.compute_index(a);
203        let b = self.compute_index(b);
204
205        unsafe {
206            // Cast to a qword array to opt out of copy restrictions and avoid
207            // drop hazards. Byte array is no good here since for whatever
208            // reason LLVM won't optimized it.
209            let a_ptr = self.inner.as_mut_ptr().add(a) as *mut usize;
210            let b_ptr = self.inner.as_mut_ptr().add(b) as *mut usize;
211
212            // Copy 1 qword at a time
213            //
214            // The optimizer unrolls this loop and vectorizes it.
215            let mut tmp: usize;
216            for i in 0..4 {
217                tmp = *a_ptr.offset(i);
218                *a_ptr.offset(i) = *b_ptr.offset(i);
219                *b_ptr.offset(i) = tmp;
220            }
221        }
222    }
223
224    /// Rotate the grid, moving all lines up/down in history.
225    #[inline]
226    pub fn rotate(&mut self, count: isize) {
227        debug_assert!(count.abs() as usize <= self.inner.len());
228
229        let len = self.inner.len();
230        self.zero = (self.zero as isize + count + len as isize) as usize % self.inner.len();
231    }
232
233    /// Rotate the grid up, moving all existing lines down in history.
234    ///
235    /// This is a faster, specialized version of [`rotate`].
236    #[inline]
237    pub fn rotate_up(&mut self, count: usize) {
238        self.zero = (self.zero + count) % self.inner.len();
239    }
240
241    /// Drain all rows in the grid.
242    pub fn drain(&mut self) -> Drain<'_, Row<T>> {
243        self.truncate();
244        self.inner.drain(..)
245    }
246
247    /// Update the raw storage buffer.
248    pub fn replace_inner(&mut self, vec: Vec<Row<T>>) {
249        self.len = vec.len();
250        self.inner = vec;
251        self.zero = 0;
252    }
253}
254
255impl<T> Index<usize> for Storage<T> {
256    type Output = Row<T>;
257
258    #[inline]
259    fn index(&self, index: usize) -> &Self::Output {
260        &self.inner[self.compute_index(index)]
261    }
262}
263
264impl<T> IndexMut<usize> for Storage<T> {
265    #[inline]
266    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
267        let index = self.compute_index(index); // borrowck
268        &mut self.inner[index]
269    }
270}
271
272impl<T> Index<Line> for Storage<T> {
273    type Output = Row<T>;
274
275    #[inline]
276    fn index(&self, index: Line) -> &Self::Output {
277        let index = self.visible_lines - 1 - index;
278        &self[*index]
279    }
280}
281
282impl<T> IndexMut<Line> for Storage<T> {
283    #[inline]
284    fn index_mut(&mut self, index: Line) -> &mut Self::Output {
285        let index = self.visible_lines - 1 - index;
286        &mut self[*index]
287    }
288}
289
290#[cfg(test)]
291mod test {
292    use crate::grid::row::Row;
293    use crate::grid::storage::{Storage, MAX_CACHE_SIZE};
294    use crate::grid::GridCell;
295    use crate::index::{Column, Line};
296    use crate::term::cell::Flags;
297
298    impl GridCell for char {
299        fn is_empty(&self) -> bool {
300            *self == ' ' || *self == '\t'
301        }
302
303        fn flags(&self) -> &Flags {
304            unimplemented!();
305        }
306
307        fn flags_mut(&mut self) -> &mut Flags {
308            unimplemented!();
309        }
310
311        fn fast_eq(&self, other: Self) -> bool {
312            self == &other
313        }
314    }
315
316    #[test]
317    fn with_capacity() {
318        let storage = Storage::with_capacity(Line(3), Row::new(Column(0), &' '));
319
320        assert_eq!(storage.inner.len(), 3);
321        assert_eq!(storage.len, 3);
322        assert_eq!(storage.zero, 0);
323        assert_eq!(storage.visible_lines, Line(3));
324    }
325
326    #[test]
327    fn indexing() {
328        let mut storage = Storage::with_capacity(Line(3), Row::new(Column(0), &' '));
329
330        storage[0] = Row::new(Column(1), &'0');
331        storage[1] = Row::new(Column(1), &'1');
332        storage[2] = Row::new(Column(1), &'2');
333
334        assert_eq!(storage[0], Row::new(Column(1), &'0'));
335        assert_eq!(storage[1], Row::new(Column(1), &'1'));
336        assert_eq!(storage[2], Row::new(Column(1), &'2'));
337
338        storage.zero += 1;
339
340        assert_eq!(storage[0], Row::new(Column(1), &'1'));
341        assert_eq!(storage[1], Row::new(Column(1), &'2'));
342        assert_eq!(storage[2], Row::new(Column(1), &'0'));
343    }
344
345    #[test]
346    #[should_panic]
347    fn indexing_above_inner_len() {
348        let storage = Storage::with_capacity(Line(1), Row::new(Column(0), &' '));
349        let _ = &storage[2];
350    }
351
352    #[test]
353    fn rotate() {
354        let mut storage = Storage::with_capacity(Line(3), Row::new(Column(0), &' '));
355        storage.rotate(2);
356        assert_eq!(storage.zero, 2);
357        storage.shrink_lines(2);
358        assert_eq!(storage.len, 1);
359        assert_eq!(storage.inner.len(), 3);
360        assert_eq!(storage.zero, 2);
361    }
362
363    /// Grow the buffer one line at the end of the buffer
364    ///
365    /// Before:
366    ///   0: 0 <- Zero
367    ///   1: 1
368    ///   2: -
369    /// After:
370    ///   0: -
371    ///   1: 0 <- Zero
372    ///   2: 1
373    ///   3: -
374    #[test]
375    fn grow_after_zero() {
376        // Setup storage area
377        let mut storage = Storage {
378            inner: vec![
379                Row::new(Column(1), &'0'),
380                Row::new(Column(1), &'1'),
381                Row::new(Column(1), &'-'),
382            ],
383            zero: 0,
384            visible_lines: Line(3),
385            len: 3,
386        };
387
388        // Grow buffer
389        storage.grow_visible_lines(Line(4), Row::new(Column(1), &'-'));
390
391        // Make sure the result is correct
392        let expected = Storage {
393            inner: vec![
394                Row::new(Column(1), &'-'),
395                Row::new(Column(1), &'0'),
396                Row::new(Column(1), &'1'),
397                Row::new(Column(1), &'-'),
398            ],
399            zero: 1,
400            visible_lines: Line(4),
401            len: 4,
402        };
403        assert_eq!(storage.visible_lines, expected.visible_lines);
404        assert_eq!(storage.inner, expected.inner);
405        assert_eq!(storage.zero, expected.zero);
406        assert_eq!(storage.len, expected.len);
407    }
408
409    /// Grow the buffer one line at the start of the buffer
410    ///
411    /// Before:
412    ///   0: -
413    ///   1: 0 <- Zero
414    ///   2: 1
415    /// After:
416    ///   0: -
417    ///   1: -
418    ///   2: 0 <- Zero
419    ///   3: 1
420    #[test]
421    fn grow_before_zero() {
422        // Setup storage area
423        let mut storage = Storage {
424            inner: vec![
425                Row::new(Column(1), &'-'),
426                Row::new(Column(1), &'0'),
427                Row::new(Column(1), &'1'),
428            ],
429            zero: 1,
430            visible_lines: Line(3),
431            len: 3,
432        };
433
434        // Grow buffer
435        storage.grow_visible_lines(Line(4), Row::new(Column(1), &'-'));
436
437        // Make sure the result is correct
438        let expected = Storage {
439            inner: vec![
440                Row::new(Column(1), &'-'),
441                Row::new(Column(1), &'-'),
442                Row::new(Column(1), &'0'),
443                Row::new(Column(1), &'1'),
444            ],
445            zero: 2,
446            visible_lines: Line(4),
447            len: 4,
448        };
449        assert_eq!(storage.visible_lines, expected.visible_lines);
450        assert_eq!(storage.inner, expected.inner);
451        assert_eq!(storage.zero, expected.zero);
452        assert_eq!(storage.len, expected.len);
453    }
454
455    /// Shrink the buffer one line at the start of the buffer
456    ///
457    /// Before:
458    ///   0: 2
459    ///   1: 0 <- Zero
460    ///   2: 1
461    /// After:
462    ///   0: 2 <- Hidden
463    ///   0: 0 <- Zero
464    ///   1: 1
465    #[test]
466    fn shrink_before_zero() {
467        // Setup storage area
468        let mut storage = Storage {
469            inner: vec![
470                Row::new(Column(1), &'2'),
471                Row::new(Column(1), &'0'),
472                Row::new(Column(1), &'1'),
473            ],
474            zero: 1,
475            visible_lines: Line(3),
476            len: 3,
477        };
478
479        // Shrink buffer
480        storage.shrink_visible_lines(Line(2));
481
482        // Make sure the result is correct
483        let expected = Storage {
484            inner: vec![
485                Row::new(Column(1), &'2'),
486                Row::new(Column(1), &'0'),
487                Row::new(Column(1), &'1'),
488            ],
489            zero: 1,
490            visible_lines: Line(2),
491            len: 2,
492        };
493        assert_eq!(storage.visible_lines, expected.visible_lines);
494        assert_eq!(storage.inner, expected.inner);
495        assert_eq!(storage.zero, expected.zero);
496        assert_eq!(storage.len, expected.len);
497    }
498
499    /// Shrink the buffer one line at the end of the buffer
500    ///
501    /// Before:
502    ///   0: 0 <- Zero
503    ///   1: 1
504    ///   2: 2
505    /// After:
506    ///   0: 0 <- Zero
507    ///   1: 1
508    ///   2: 2 <- Hidden
509    #[test]
510    fn shrink_after_zero() {
511        // Setup storage area
512        let mut storage = Storage {
513            inner: vec![
514                Row::new(Column(1), &'0'),
515                Row::new(Column(1), &'1'),
516                Row::new(Column(1), &'2'),
517            ],
518            zero: 0,
519            visible_lines: Line(3),
520            len: 3,
521        };
522
523        // Shrink buffer
524        storage.shrink_visible_lines(Line(2));
525
526        // Make sure the result is correct
527        let expected = Storage {
528            inner: vec![
529                Row::new(Column(1), &'0'),
530                Row::new(Column(1), &'1'),
531                Row::new(Column(1), &'2'),
532            ],
533            zero: 0,
534            visible_lines: Line(2),
535            len: 2,
536        };
537        assert_eq!(storage.visible_lines, expected.visible_lines);
538        assert_eq!(storage.inner, expected.inner);
539        assert_eq!(storage.zero, expected.zero);
540        assert_eq!(storage.len, expected.len);
541    }
542
543    /// Shrink the buffer at the start and end of the buffer
544    ///
545    /// Before:
546    ///   0: 4
547    ///   1: 5
548    ///   2: 0 <- Zero
549    ///   3: 1
550    ///   4: 2
551    ///   5: 3
552    /// After:
553    ///   0: 4 <- Hidden
554    ///   1: 5 <- Hidden
555    ///   2: 0 <- Zero
556    ///   3: 1
557    ///   4: 2 <- Hidden
558    ///   5: 3 <- Hidden
559    #[test]
560    fn shrink_before_and_after_zero() {
561        // Setup storage area
562        let mut storage = Storage {
563            inner: vec![
564                Row::new(Column(1), &'4'),
565                Row::new(Column(1), &'5'),
566                Row::new(Column(1), &'0'),
567                Row::new(Column(1), &'1'),
568                Row::new(Column(1), &'2'),
569                Row::new(Column(1), &'3'),
570            ],
571            zero: 2,
572            visible_lines: Line(6),
573            len: 6,
574        };
575
576        // Shrink buffer
577        storage.shrink_visible_lines(Line(2));
578
579        // Make sure the result is correct
580        let expected = Storage {
581            inner: vec![
582                Row::new(Column(1), &'4'),
583                Row::new(Column(1), &'5'),
584                Row::new(Column(1), &'0'),
585                Row::new(Column(1), &'1'),
586                Row::new(Column(1), &'2'),
587                Row::new(Column(1), &'3'),
588            ],
589            zero: 2,
590            visible_lines: Line(2),
591            len: 2,
592        };
593        assert_eq!(storage.visible_lines, expected.visible_lines);
594        assert_eq!(storage.inner, expected.inner);
595        assert_eq!(storage.zero, expected.zero);
596        assert_eq!(storage.len, expected.len);
597    }
598
599    /// Check that when truncating all hidden lines are removed from the raw buffer
600    ///
601    /// Before:
602    ///   0: 4 <- Hidden
603    ///   1: 5 <- Hidden
604    ///   2: 0 <- Zero
605    ///   3: 1
606    ///   4: 2 <- Hidden
607    ///   5: 3 <- Hidden
608    /// After:
609    ///   0: 0 <- Zero
610    ///   1: 1
611    #[test]
612    fn truncate_invisible_lines() {
613        // Setup storage area
614        let mut storage = Storage {
615            inner: vec![
616                Row::new(Column(1), &'4'),
617                Row::new(Column(1), &'5'),
618                Row::new(Column(1), &'0'),
619                Row::new(Column(1), &'1'),
620                Row::new(Column(1), &'2'),
621                Row::new(Column(1), &'3'),
622            ],
623            zero: 2,
624            visible_lines: Line(1),
625            len: 2,
626        };
627
628        // Truncate buffer
629        storage.truncate();
630
631        // Make sure the result is correct
632        let expected = Storage {
633            inner: vec![Row::new(Column(1), &'0'), Row::new(Column(1), &'1')],
634            zero: 0,
635            visible_lines: Line(1),
636            len: 2,
637        };
638        assert_eq!(storage.visible_lines, expected.visible_lines);
639        assert_eq!(storage.inner, expected.inner);
640        assert_eq!(storage.zero, expected.zero);
641        assert_eq!(storage.len, expected.len);
642    }
643
644    /// Truncate buffer only at the beginning
645    ///
646    /// Before:
647    ///   0: 1
648    ///   1: 2 <- Hidden
649    ///   2: 0 <- Zero
650    /// After:
651    ///   0: 1
652    ///   0: 0 <- Zero
653    #[test]
654    fn truncate_invisible_lines_beginning() {
655        // Setup storage area
656        let mut storage = Storage {
657            inner: vec![
658                Row::new(Column(1), &'1'),
659                Row::new(Column(1), &'2'),
660                Row::new(Column(1), &'0'),
661            ],
662            zero: 2,
663            visible_lines: Line(1),
664            len: 2,
665        };
666
667        // Truncate buffer
668        storage.truncate();
669
670        // Make sure the result is correct
671        let expected = Storage {
672            inner: vec![Row::new(Column(1), &'0'), Row::new(Column(1), &'1')],
673            zero: 0,
674            visible_lines: Line(1),
675            len: 2,
676        };
677        assert_eq!(storage.visible_lines, expected.visible_lines);
678        assert_eq!(storage.inner, expected.inner);
679        assert_eq!(storage.zero, expected.zero);
680        assert_eq!(storage.len, expected.len);
681    }
682
683    /// First shrink the buffer and then grow it again
684    ///
685    /// Before:
686    ///   0: 4
687    ///   1: 5
688    ///   2: 0 <- Zero
689    ///   3: 1
690    ///   4: 2
691    ///   5: 3
692    /// After Shrinking:
693    ///   0: 4 <- Hidden
694    ///   1: 5 <- Hidden
695    ///   2: 0 <- Zero
696    ///   3: 1
697    ///   4: 2
698    ///   5: 3 <- Hidden
699    /// After Growing:
700    ///   0: 4
701    ///   1: 5
702    ///   2: -
703    ///   3: 0 <- Zero
704    ///   4: 1
705    ///   5: 2
706    ///   6: 3
707    #[test]
708    fn shrink_then_grow() {
709        // Setup storage area
710        let mut storage = Storage {
711            inner: vec![
712                Row::new(Column(1), &'4'),
713                Row::new(Column(1), &'5'),
714                Row::new(Column(1), &'0'),
715                Row::new(Column(1), &'1'),
716                Row::new(Column(1), &'2'),
717                Row::new(Column(1), &'3'),
718            ],
719            zero: 2,
720            visible_lines: Line(0),
721            len: 6,
722        };
723
724        // Shrink buffer
725        storage.shrink_lines(3);
726
727        // Make sure the result after shrinking is correct
728        let shrinking_expected = Storage {
729            inner: vec![
730                Row::new(Column(1), &'4'),
731                Row::new(Column(1), &'5'),
732                Row::new(Column(1), &'0'),
733                Row::new(Column(1), &'1'),
734                Row::new(Column(1), &'2'),
735                Row::new(Column(1), &'3'),
736            ],
737            zero: 2,
738            visible_lines: Line(0),
739            len: 3,
740        };
741        assert_eq!(storage.inner, shrinking_expected.inner);
742        assert_eq!(storage.zero, shrinking_expected.zero);
743        assert_eq!(storage.len, shrinking_expected.len);
744
745        // Grow buffer
746        storage.grow_lines(4, Row::new(Column(1), &'-'));
747
748        // Make sure the result after shrinking is correct
749        let growing_expected = Storage {
750            inner: vec![
751                Row::new(Column(1), &'4'),
752                Row::new(Column(1), &'5'),
753                Row::new(Column(1), &'-'),
754                Row::new(Column(1), &'0'),
755                Row::new(Column(1), &'1'),
756                Row::new(Column(1), &'2'),
757                Row::new(Column(1), &'3'),
758            ],
759            zero: 3,
760            visible_lines: Line(0),
761            len: 7,
762        };
763        assert_eq!(storage.inner, growing_expected.inner);
764        assert_eq!(storage.zero, growing_expected.zero);
765        assert_eq!(storage.len, growing_expected.len);
766    }
767
768    #[test]
769    fn initialize() {
770        // Setup storage area
771        let mut storage = Storage {
772            inner: vec![
773                Row::new(Column(1), &'4'),
774                Row::new(Column(1), &'5'),
775                Row::new(Column(1), &'0'),
776                Row::new(Column(1), &'1'),
777                Row::new(Column(1), &'2'),
778                Row::new(Column(1), &'3'),
779            ],
780            zero: 2,
781            visible_lines: Line(0),
782            len: 6,
783        };
784
785        // Initialize additional lines
786        let init_size = 3;
787        storage.initialize(init_size, &'-', Column(1));
788
789        // Make sure the lines are present and at the right location
790
791        let expected_init_size = std::cmp::max(init_size, MAX_CACHE_SIZE);
792        let mut expected_inner = vec![Row::new(Column(1), &'4'), Row::new(Column(1), &'5')];
793        expected_inner.append(&mut vec![Row::new(Column(1), &'-'); expected_init_size]);
794        expected_inner.append(&mut vec![
795            Row::new(Column(1), &'0'),
796            Row::new(Column(1), &'1'),
797            Row::new(Column(1), &'2'),
798            Row::new(Column(1), &'3'),
799        ]);
800        let expected_storage = Storage {
801            inner: expected_inner,
802            zero: 2 + expected_init_size,
803            visible_lines: Line(0),
804            len: 9,
805        };
806
807        assert_eq!(storage.inner, expected_storage.inner);
808        assert_eq!(storage.zero, expected_storage.zero);
809        assert_eq!(storage.len, expected_storage.len);
810    }
811
812    #[test]
813    fn rotate_wrap_zero() {
814        let mut storage = Storage {
815            inner: vec![
816                Row::new(Column(1), &'-'),
817                Row::new(Column(1), &'-'),
818                Row::new(Column(1), &'-'),
819            ],
820            zero: 2,
821            visible_lines: Line(0),
822            len: 3,
823        };
824
825        storage.rotate(2);
826
827        assert!(storage.zero < storage.inner.len());
828    }
829}