peekable_buffer/
lib.rs

1use std::{cell::RefCell, rc::Rc};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub struct PeekableBuffer<T>
5    where T: Clone
6{
7    iter: Vec<T>,
8    ctr: Rc<RefCell<usize>>,
9}
10
11impl<T> IntoIterator for PeekableBuffer<T>
12    where T: Clone
13{
14    type Item = T;
15    type IntoIter = std::vec::IntoIter<T>;
16
17    fn into_iter(self) -> Self::IntoIter {
18        self.iter.into_iter()
19    }
20}
21
22impl<T> PeekableBuffer<T>
23    where T: Clone
24{
25    /// Creates a `PeekableBuffer` object that owns all elements of `&[T]` via cloning.
26    pub fn new<E>(elements: E) -> Self
27        where E: AsRef<[T]>
28    {
29        Self {
30            iter: elements.as_ref().iter().cloned().collect(),
31            ctr: Rc::new(RefCell::new(0)),
32        }
33    }
34
35    /// Returns true if the stream has reached the end.
36    pub fn is_at_end(&self) -> bool {
37        let borrowed_ctr = self.ctr.borrow();
38        *borrowed_ctr >= self.iter.len()
39    }
40
41    /// Returns the number of elements in the stream.
42    pub fn len(&self) -> usize {
43        self.iter.len()
44    }
45
46    /// Returns a reference to the element `offset` positions away from the
47    /// element currently being pointed to by the cursor. If the
48    /// computed offset is outside the bounds of the stream, `None` is returned.
49    pub fn lookaround(&self, offset: i64) -> Option<&T> {
50        let i = self.compute_bounded_offset(offset);
51        if i < 0 || self.len() <= i as usize {
52            None
53        } else {
54            Some(&(self.iter[i as usize]))
55        }
56    }
57
58    /// Returns a reference to the element just after the element currently
59    /// being pointed to by the cursor. This is equivalent to calling
60    /// `lookaround(1)`.
61    pub fn peek(&self) -> Option<&T> {
62        self.lookaround(1)
63    }
64
65    /// Returns a reference to the element currently being pointed to by the
66    /// cursor. This is equivalent to calling `lookaround(0)`.
67    pub fn current(&self) -> Option<&T> {
68        self.lookaround(0)
69    }
70
71    /// Shifts the cursor by `offset` positions. The computed offset
72    /// will be within the range `[0, len()]`. If the computed offset is less
73    /// than 0, the cursor will point to the first element. If the
74    /// computed offset is greater than `len() - 1`, the cursor will
75    /// point to the end and `is_at_end()` returns true.
76    pub fn shift(&mut self, offset: i64) -> () {
77        let i = self.compute_bounded_offset(offset);
78        *self.ctr.borrow_mut() = if i == -1 {
79            0
80        } else {
81            i as usize
82        }
83    }
84
85    /// A convenience method that advances the cursor by 1. If the
86    /// stream is at the end, no action is taken. This is equivalent to calling
87    /// `shift(1)`.
88    pub fn advance(&mut self) -> () {
89        self.shift(1);
90    }
91
92    /// Sets the zero-indexed position of the cursor. If the
93    /// given `pos` is outside of the range of the stream length, the
94    /// cursor will be set to `len()`.
95    pub fn set_pos(&mut self, pos: usize) -> usize {
96        let i = std::cmp::min(pos, self.iter.len());
97        *self.ctr.borrow_mut() = i;
98        i
99    }
100
101    /// Returns the current zero-indexed position of the cursor. The
102    /// returned value is in the range `[0, len()]`.
103    pub fn pos(&self) -> usize {
104        *self.ctr.borrow_mut()
105    }
106
107    /// Returns a reference to the element currently being pointed to by the
108    /// cursor, then advances the pointer by 1.
109    pub fn consume(&mut self) -> Option<&T> {
110        let tmp = self.current();
111        let mut mctr = self.ctr.borrow_mut();
112        *mctr += 1;
113        if *mctr >= self.len() {
114            *mctr = self.len(); //just in case
115        }
116        tmp
117    }
118
119    /// Returns an iterator containing elements that satisfy the given
120    /// predicate, starting from the element currently pointed to by the stream
121    /// pointer, up to either the end of the stream, or when the predicate
122    /// returns fall, whichever comes first.
123    pub fn take_while<P>(&mut self, predicate: P) -> impl Iterator<Item = &T>
124        where P: Fn(&T) -> bool
125    {
126        let mut v = Vec::new();
127        let mut mctr = self.ctr.borrow_mut();
128        while *mctr < self.iter.len() && predicate(&self.iter[*mctr]) {
129            v.push(&self.iter[*mctr]);
130            *mctr += 1;
131        }
132        v.into_iter()
133    }
134
135    /// Returns an iterator containing all elements in the range
136    /// `[pos(), pos() + n)`. The cursor will point to either the
137    /// end of the stream, or the element at `pos() + n`, whichever is
138    /// first. If `pos() + n` is outside the bounds of the stream, then
139    /// the rest of the stream is consumed and `is_at_end()` returns true.
140    pub fn take(&mut self, n: usize) -> impl Iterator<Item = &T> {
141        let mut v = Vec::new();
142        let mut mctr = self.ctr.borrow_mut();
143        for _ in 0..n {
144            if *mctr >= self.iter.len() {
145                break;
146            }
147            v.push(&self.iter[*mctr]);
148            *mctr += 1;
149        }
150        v.into_iter()
151    }
152
153    /// Returns true if the current element matches the given predicate, false
154    /// otherwise. The function will return false if the stream is at the end
155    /// regardless of the predicate.
156    pub fn accept<P>(&self, predicate: P) -> bool
157        where P: Fn(&T) -> bool
158    {
159        if self.is_at_end() {
160            false
161        } else {
162            predicate(self.current().unwrap())
163        }
164    }
165
166    /// Returns a new `PeekableBuffer` containing all elements from the range
167    /// `[from_inc, len() - 1]`, cloning the required elements into their
168    /// own iterable. If `from_inc` is outside the range of the stream, an
169    /// empty `PeekableBuffer` is returned.
170    pub fn slice_from(&self, from_inc: usize) -> PeekableBuffer<T> {
171        self.slice_between(from_inc, usize::MAX)
172    }
173
174    /// Returns a new `PeekableBuffer` containing all elements from the range
175    /// `[from_inc, to_exc - 1]`, cloning the required elements into their
176    /// own iterable. If `from_inc > to_exc`, this function will panic.
177    /// Otherwise, if `from_inc` is greater than `len()`, an empty
178    /// `PeekableBuffer` is returned. If `from_inc == to_exc`, an empty
179    /// `PeekableBuffer` is returned as well.
180    pub fn slice_between(&self, from_inc: usize, to_exc: usize) -> PeekableBuffer<T> {
181        if from_inc > to_exc {
182            panic!("from_inc={} greater than to_exc{}", from_inc, to_exc);
183        }
184        let a: usize = std::cmp::min(self.len(), from_inc);
185        let b: usize = std::cmp::min(self.len(), to_exc);
186        PeekableBuffer::new(&self.iter[a..b])
187    }
188
189    /// Computes current cursor position offset by integer `offset`
190    /// amount, returning the new position in the range `[-1, len()]`.
191    ///
192    /// Note: this function makes the assumption that `i128` contains the range
193    /// `[-usize, usize]`.
194    fn compute_bounded_offset(&self, offset: i64) -> i128 {
195        let curr: i128 = *self.ctr.borrow_mut() as i128 + offset as i128; //so no over/underflow
196        if offset < 0 {
197            std::cmp::max(-1, curr)
198        } else {
199            std::cmp::min(self.iter.len(), curr as usize) as i128
200        }
201    }
202}
203
204#[cfg(test)]
205mod tests {
206    use super::*;
207
208    #[test]
209    fn test_is_at_end() {
210        let elems = vec![1, 2, 3];
211        let mut stream = PeekableBuffer::new(&elems);
212        for _ in elems {
213            stream.advance();
214        }
215        assert!(stream.is_at_end());
216    }
217
218    #[test]
219    fn test_len() {
220        let elems = vec![1, 2, 3, 4];
221        let stream = PeekableBuffer::new(&elems);
222        assert_eq!(stream.len(), elems.len());
223    }
224
225    #[test]
226    fn test_lookaround_peek_current() {
227        let elems = vec![1, 2, 3];
228        let mut stream = PeekableBuffer::new(&elems);
229
230        assert_eq!(stream.len(), 3);
231
232        // pointer at position 0
233        assert!(!stream.is_at_end());
234        assert_eq!(stream.pos(), 0);
235        assert_eq!(stream.current(), Some(&1));
236        assert_eq!(stream.peek(), Some(&2));
237        assert_eq!(stream.lookaround(-1), None);
238        assert_eq!(stream.lookaround(0), Some(&1));
239        assert_eq!(stream.lookaround(1), Some(&2));
240        assert_eq!(stream.lookaround(2), Some(&3));
241        assert_eq!(stream.lookaround(3), None);
242        assert_eq!(stream.lookaround(4), None);
243
244        assert!(!stream.is_at_end());
245        assert_eq!(stream.current(), Some(&1));
246
247        // pointer at position 1
248        stream.advance();
249        assert_eq!(stream.pos(), 1);
250        assert_eq!(stream.peek(), Some(&3));
251        stream.shift(-1);
252        assert_eq!(stream.pos(), 0);
253        assert_eq!(stream.peek(), Some(&2));
254        stream.shift(1);
255        assert_eq!(stream.pos(), 1);
256        assert_eq!(stream.peek(), Some(&3));
257        assert!(!stream.is_at_end());
258        assert_eq!(stream.current(), Some(&2));
259        assert_eq!(stream.peek(), Some(&3));
260        assert_eq!(stream.lookaround(-2), None);
261        assert_eq!(stream.lookaround(-1), Some(&1));
262        assert_eq!(stream.lookaround(0), Some(&2));
263        assert_eq!(stream.lookaround(1), Some(&3));
264        assert_eq!(stream.lookaround(2), None);
265        assert_eq!(stream.lookaround(3), None);
266
267        assert!(!stream.is_at_end());
268        assert_eq!(stream.current(), Some(&2));
269    }
270
271    #[test]
272    fn test_shift_advance() {
273        fn limit(stream: &mut PeekableBuffer<i64>) {
274            let offset_from_end = *stream.ctr.borrow_mut() as i64 - stream.len() as i64;
275
276            // shift right
277            stream.shift(i64::MAX);
278            assert_eq!(stream.pos(), 3);
279            assert!(stream.is_at_end());
280            assert_eq!(stream.current(), None);
281            stream.shift(-2);
282            assert_eq!(stream.current(), Some(&2));
283
284            // shift left
285            assert!(!stream.is_at_end());
286            stream.shift(i64::MIN);
287            assert_eq!(stream.pos(), 0);
288            assert!(!stream.is_at_end());
289            assert_eq!(stream.current(), Some(&1));
290            stream.shift(1);
291            assert_eq!(stream.current(), Some(&2));
292
293            // reset to original position
294            stream.shift(i64::MAX);
295            stream.shift(offset_from_end as i64);
296        }
297
298        let elems = vec![1, 2, 3];
299        let mut stream = PeekableBuffer::new(&elems);
300        for i in 1..=4 {
301            assert_eq!(stream.pos(), (i - 1) as usize);
302            limit(&mut stream);
303            stream.advance();
304        }
305    }
306
307    #[test]
308    fn test_set_pos() {
309        let elems = vec![1, 2, 3];
310        let mut stream = PeekableBuffer::new(&elems);
311        assert_eq!(stream.current(), Some(&1));
312        stream.set_pos(2);
313        assert_eq!(stream.current(), Some(&3));
314        stream.set_pos(1);
315        assert_eq!(stream.current(), Some(&2));
316        stream.set_pos(0);
317        assert_eq!(stream.current(), Some(&1));
318        stream.set_pos(3);
319        assert_eq!(stream.current(), None);
320        stream.set_pos(100);
321        assert_eq!(stream.current(), None);
322        assert!(stream.is_at_end());
323    }
324
325    #[test]
326    fn test_pos_consume() {
327        let elems = vec![1, 2, 3];
328        let mut stream = PeekableBuffer::new(&elems);
329
330        assert_eq!(stream.len(), 3);
331
332        assert_eq!(stream.pos(), 0);
333        assert_eq!(stream.consume(), Some(&1));
334        assert_eq!(stream.pos(), 1);
335        assert_eq!(stream.consume(), Some(&2));
336        assert_eq!(stream.pos(), 2);
337        assert_eq!(stream.consume(), Some(&3));
338        assert_eq!(stream.pos(), 3);
339        assert_eq!(stream.consume(), None);
340        assert_eq!(stream.pos(), 3);
341        assert_eq!(stream.consume(), None);
342        assert_eq!(stream.pos(), 3);
343    }
344
345    #[test]
346    fn test_take_while_consumes_part_of_stream() {
347        let elems = vec![1, 2, 3, 3, 4, 5];
348        let mut stream = PeekableBuffer::new(&elems);
349
350        assert_eq!(stream.len(), 6);
351
352        let taken: Vec<&i64> = stream.take_while(|&i| i < 4).collect();
353        assert_eq!(taken, vec![&1, &2, &3, &3]);
354
355        assert_eq!(stream.pos(), 4);
356        assert!(!stream.is_at_end());
357        assert_eq!(stream.current(), Some(&4));
358        assert_eq!(stream.peek(), Some(&5));
359    }
360
361    #[test]
362    fn test_take_while_predicate_consumes_entire_stream() {
363        let elems = vec![1, 2, 3, 4, 5];
364        let mut stream = PeekableBuffer::new(&elems);
365
366        assert_eq!(stream.len(), 5);
367
368        let taken: Vec<&i64> = stream.take_while(|&i| i < 10).collect();
369        assert_eq!(taken, vec![&1, &2, &3, &4, &5]);
370
371        assert_eq!(stream.pos(), 5);
372        assert!(stream.is_at_end());
373        assert_eq!(stream.current(), None);
374        assert_eq!(stream.peek(), None);
375        assert_eq!(stream.lookaround(-1), Some(&5));
376    }
377
378    #[test]
379    fn test_take_while_predicate_consumes_no_elements() {
380        let elems = vec![1, 2, 3, 4, 5];
381        let mut stream = PeekableBuffer::new(&elems);
382
383        assert_eq!(stream.len(), 5);
384
385        // at position 1
386        stream.advance();
387
388        let taken: Vec<&i64> = stream.take_while(|&i| i == 1).collect();
389        assert!(taken.is_empty());
390
391        assert_eq!(stream.pos(), 1);
392        assert!(!stream.is_at_end());
393        assert_eq!(stream.current(), Some(&2));
394        assert_eq!(stream.peek(), Some(&3));
395    }
396
397    #[test]
398    fn test_take() {
399        let elems = vec![1, 2, 3, 4, 5];
400        let mut stream = PeekableBuffer::new(&elems);
401        assert_eq!(stream.len(), 5);
402
403        {
404            let taken: Vec<&i64> = stream.take(0).collect();
405            assert!(taken.is_empty());
406            assert_eq!(taken, Vec::<&i64>::new());
407            assert!(stream.pos() == 0);
408            assert!(!stream.is_at_end());
409        }
410        {
411            let taken: Vec<&i64> = stream.take(2).collect();
412            assert!(!taken.is_empty());
413            assert_eq!(taken, vec![&1, &2]);
414            assert!(stream.pos() == 2);
415            assert!(!stream.is_at_end());
416        }
417        {
418            let taken: Vec<&i64> = stream.take(2).collect();
419            assert!(!taken.is_empty());
420            assert_eq!(taken, vec![&3, &4]);
421            assert!(stream.pos() == 4);
422            assert!(!stream.is_at_end());
423        }
424        {
425            let taken: Vec<&i64> = stream.take(2).collect();
426            assert!(!taken.is_empty());
427            assert_eq!(taken, vec![&5]);
428            assert!(stream.pos() == 5);
429            assert!(stream.is_at_end());
430        }
431        {
432            let taken: Vec<&i64> = stream.take(10).collect();
433            assert!(taken.is_empty());
434            assert_eq!(taken, Vec::<&i64>::new());
435            assert!(stream.pos() == 5);
436            assert!(stream.is_at_end());
437        }
438    }
439
440    #[test]
441    fn test_accept() {
442        let elems = vec![1, 2, 3];
443        let mut stream = PeekableBuffer::new(&elems);
444        assert!(stream.accept(|&x| x < 2));
445        stream.advance();
446        assert!(stream.accept(|&x| x == 2));
447        stream.advance();
448        assert!(stream.accept(|&x| x >= 3));
449        assert!(stream.accept(|&x| x != 3) == false);
450        stream.advance();
451        assert!(stream.accept(|&_| true) == false);
452    }
453
454    #[test]
455    pub fn test_slice_from() {
456        let elems = vec![1, 2, 3, 4, 5];
457        let stream = PeekableBuffer::new(&elems);
458        assert_eq!(stream.slice_from(0), PeekableBuffer::new(&vec![1, 2, 3, 4, 5]));
459        assert_eq!(stream.slice_from(1), PeekableBuffer::new(&vec![2, 3, 4, 5]));
460        assert_eq!(stream.slice_from(4), PeekableBuffer::new(&vec![5]));
461        assert_eq!(stream.slice_from(5), PeekableBuffer::new(&vec![]));
462        assert_eq!(stream.slice_from(10), PeekableBuffer::new(&vec![]));
463    }
464
465    #[test]
466    pub fn test_slice_between() {
467        let elems = vec![1, 2, 3, 4, 5];
468        let stream = PeekableBuffer::new(&elems);
469
470        //to len()
471        assert_eq!(stream.slice_between(0, 5), PeekableBuffer::new(&vec![1, 2, 3, 4, 5]));
472        assert_eq!(stream.slice_between(1, 5), PeekableBuffer::new(&vec![2, 3, 4, 5]));
473        assert_eq!(stream.slice_between(4, 5), PeekableBuffer::new(&vec![5]));
474        assert_eq!(stream.slice_between(5, 5), PeekableBuffer::new(&vec![]));
475
476        //to >len()
477        assert_eq!(stream.slice_between(0, 10), PeekableBuffer::new(&vec![1, 2, 3, 4, 5]));
478        assert_eq!(stream.slice_between(1, 10), PeekableBuffer::new(&vec![2, 3, 4, 5]));
479        assert_eq!(stream.slice_between(4, 10), PeekableBuffer::new(&vec![5]));
480        assert_eq!(stream.slice_between(5, 10), PeekableBuffer::new(&vec![]));
481
482        //in between
483        assert_eq!(stream.slice_between(0, 1), PeekableBuffer::new(&vec![1]));
484        assert_eq!(stream.slice_between(1, 3), PeekableBuffer::new(&vec![2, 3]));
485        assert_eq!(stream.slice_between(2, 4), PeekableBuffer::new(&vec![3, 4]));
486        assert_eq!(stream.slice_between(3, 5), PeekableBuffer::new(&vec![4, 5]));
487        assert_eq!(stream.slice_between(1, 1), PeekableBuffer::new(&vec![]));
488        assert_eq!(stream.slice_between(3, 3), PeekableBuffer::new(&vec![]));
489        assert_eq!(stream.slice_between(10, 10), PeekableBuffer::new(&vec![]));
490
491        //complete outside the range
492        assert_eq!(stream.slice_between(10, 20), PeekableBuffer::new(&vec![]));
493    }
494
495    #[test]
496    #[should_panic]
497    pub fn test_slice_between_panicking() {
498        let elems = vec![1, 2, 3, 4, 5];
499        let stream = PeekableBuffer::new(&elems);
500        assert_eq!(stream.slice_between(20, 1), PeekableBuffer::new(&vec![]));
501        assert_eq!(stream.slice_between(2, 1), PeekableBuffer::new(&vec![]));
502        assert_eq!(stream.slice_between(20, 10), PeekableBuffer::new(&vec![]));
503    }
504
505    #[test]
506    pub fn test_readme_example() {
507        let v = vec![1, 2, 3, 4, 5];
508        let mut stream = PeekableBuffer::new(&v);
509
510        assert!(!stream.is_at_end());
511        assert_eq!(stream.pos(), 0);
512        assert_eq!(stream.current(), Some(&1));
513
514        stream.advance();
515        assert_eq!(stream.pos(), 1);
516        assert_eq!(stream.current(), Some(&2));
517
518        assert_eq!(stream.lookaround(-1), Some(&1));
519        assert_eq!(stream.lookaround(-10), None);
520
521        stream.shift(3);
522        assert_eq!(stream.current(), Some(&5));
523
524        assert_eq!(stream.consume(), Some(&5));
525        assert!(stream.is_at_end());
526        assert_eq!(stream.current(), None);
527    }
528}