summaryrefslogtreecommitdiff
path: root/lookahead
diff options
context:
space:
mode:
Diffstat (limited to 'lookahead')
-rw-r--r--lookahead/src/lib.rs34
1 files changed, 34 insertions, 0 deletions
diff --git a/lookahead/src/lib.rs b/lookahead/src/lib.rs
index 08bf20e..e4f9533 100644
--- a/lookahead/src/lib.rs
+++ b/lookahead/src/lib.rs
@@ -1,3 +1,20 @@
1//! Provides a simple iterator adaptor that buffers data from the
2//! underlying iterator when needed. It will only read ahead when peek requests
3//! are made, but it will only request each element from the source once. That
4//! is, no matter how many positions of lookahead you allocate, they won't be
5//! filled unless you need them, once you have seen them they will be buffered
6//! until iterated to.
7//!
8//! This is a fundamental, low level component of lexical analyzers and of
9//! parsers in general as well as many other systems.
10
11/// LookAhead uses a statically allocated ring buffer to store it's data in, an
12/// internal array of Options to make moving the data in and out easier.
13///
14/// C: How many positions are in the buffer, this should be 1+lookahead length,
15/// that is C=2 means you get a current value and one lookahead token.
16/// T: The type of the underlying items
17/// U: The type of the underlying iterator, must implement Iterator with Type=T
1pub struct LookAhead<const C: usize, T, U> 18pub struct LookAhead<const C: usize, T, U>
2where 19where
3 U: Iterator<Item=T> + Sized 20 U: Iterator<Item=T> + Sized
@@ -12,6 +29,9 @@ impl<const C: usize, T, U> LookAhead<C,T,U>
12where 29where
13 U: Iterator<Item=T> + Sized 30 U: Iterator<Item=T> + Sized
14{ 31{
32 /// Create a new LookAhead Iterator wrapping the provided iterator.
33 ///
34 /// This does nothing to the base iterator, it does not begin reading yet.
15 pub fn new(iter: U) -> Self { 35 pub fn new(iter: U) -> Self {
16 Self { 36 Self {
17 iter, 37 iter,
@@ -21,12 +41,22 @@ where
21 } 41 }
22 } 42 }
23 43
44 /// Look ahead into the buffered look-ahead. If you exceed the size of the
45 /// internal buffer (C) then this will panic. This will fill the buffer to
46 /// the point requested if it is not already full. This will not advance
47 /// the iterator, so multiple calls to peek for the same position without
48 /// calling next() will provide the same value and will not affect the state
49 /// of the interior iterator.
24 pub fn peek(&mut self, offset: usize) -> Option<&T> { 50 pub fn peek(&mut self, offset: usize) -> Option<&T> {
25 assert!(offset<C); 51 assert!(offset<C);
26 self.fill_to( offset ); 52 self.fill_to( offset );
27 self.data[(self.cur+offset)%C].as_ref() 53 self.data[(self.cur+offset)%C].as_ref()
28 } 54 }
29 55
56 /// Fills the internal buffer to the requested level by calling next() on
57 /// the underlying iterator. This will call the underlying iterator for
58 /// each position to fill, even if the next() function has returned None.
59 /// It will simply fill the lookahead buffer with None values.
30 fn fill_to(&mut self, qty: usize) { 60 fn fill_to(&mut self, qty: usize) {
31 for i in self.fill..=qty { 61 for i in self.fill..=qty {
32 if let Some(x) = self.iter.next() { 62 if let Some(x) = self.iter.next() {
@@ -43,6 +73,10 @@ where
43{ 73{
44 type Item=T; 74 type Item=T;
45 75
76 /// Follows the standard rules for an iterator. This will only call the
77 /// underlying iterator's next function if our lookahead buffer is empty.
78 /// Otherwise this is a pass-through. It does nothing special in the case
79 /// of a None response from the underlying iterator.
46 fn next(&mut self) -> Option<T> { 80 fn next(&mut self) -> Option<T> {
47 if self.fill == 0 { 81 if self.fill == 0 {
48 self.iter.next() 82 self.iter.next()