summaryrefslogtreecommitdiff
path: root/lookahead
diff options
context:
space:
mode:
authorMike Buland <mike@xagasoft.com>2026-06-30 13:21:38 -0700
committerMike Buland <mike@xagasoft.com>2026-06-30 13:21:38 -0700
commit1553b785cbc75bfc47066096b81d0066017a91ad (patch)
treed10b1dcf71c6ecf833b2eb9e9dbfde303b88fa9e /lookahead
parent062048ef6e3e060bcf841ea2ec92e026f09d8da0 (diff)
downloadcrimtag-1553b785cbc75bfc47066096b81d0066017a91ad.tar.gz
crimtag-1553b785cbc75bfc47066096b81d0066017a91ad.tar.bz2
crimtag-1553b785cbc75bfc47066096b81d0066017a91ad.tar.xz
crimtag-1553b785cbc75bfc47066096b81d0066017a91ad.zip
Added LookAhead, fixed up the proc-macro.
LookAhead should make the rest of the parser and lexer stuff way easier, probably spin that out into it's own lib later on.
Diffstat (limited to 'lookahead')
-rw-r--r--lookahead/Cargo.toml6
-rw-r--r--lookahead/src/lib.rs84
2 files changed, 90 insertions, 0 deletions
diff --git a/lookahead/Cargo.toml b/lookahead/Cargo.toml
new file mode 100644
index 0000000..d79f913
--- /dev/null
+++ b/lookahead/Cargo.toml
@@ -0,0 +1,6 @@
1[package]
2name = "lookahead"
3version = "0.1.0"
4edition = "2024"
5
6[dependencies]
diff --git a/lookahead/src/lib.rs b/lookahead/src/lib.rs
new file mode 100644
index 0000000..08bf20e
--- /dev/null
+++ b/lookahead/src/lib.rs
@@ -0,0 +1,84 @@
1pub struct LookAhead<const C: usize, T, U>
2where
3 U: Iterator<Item=T> + Sized
4{
5 iter: U,
6 data: [Option<T>;C],
7 cur: usize,
8 fill: usize,
9}
10
11impl<const C: usize, T, U> LookAhead<C,T,U>
12where
13 U: Iterator<Item=T> + Sized
14{
15 pub fn new(iter: U) -> Self {
16 Self {
17 iter,
18 data: [const {None};C],
19 cur: 0,
20 fill: 0,
21 }
22 }
23
24 pub fn peek(&mut self, offset: usize) -> Option<&T> {
25 assert!(offset<C);
26 self.fill_to( offset );
27 self.data[(self.cur+offset)%C].as_ref()
28 }
29
30 fn fill_to(&mut self, qty: usize) {
31 for i in self.fill..=qty {
32 if let Some(x) = self.iter.next() {
33 self.data[(self.cur+i)%C].replace( x );
34 self.fill += 1;
35 }
36 }
37 }
38}
39
40impl<const C: usize, T, U> std::iter::Iterator for LookAhead<C,T,U>
41where
42 U: Iterator<Item=T> + Sized
43{
44 type Item=T;
45
46 fn next(&mut self) -> Option<T> {
47 if self.fill == 0 {
48 self.iter.next()
49 } else {
50 let old = self.cur;
51 self.cur = (self.cur+1)%C;
52 self.fill -= 1;
53 self.data[old].take()
54 }
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn basic() {
64 let data = [1, 2, 3, 4, 5, 6, 7, 8];
65 let mut i = LookAhead::<3,_,_>::new(data.iter());
66 assert_eq!(i.next(), Some(&1));
67 assert_eq!(i.peek(1), Some(&&3));
68 assert_eq!(i.peek(0), Some(&&2));
69 assert_eq!(i.next(), Some(&2));
70 assert_eq!(i.peek(0), Some(&&3));
71 assert_eq!(i.next(), Some(&3));
72 assert_eq!(i.next(), Some(&4));
73 assert_eq!(i.next(), Some(&5));
74 assert_eq!(i.peek(0), Some(&&6));
75 assert_eq!(i.peek(1), Some(&&7));
76 assert_eq!(i.peek(2), Some(&&8));
77 assert_eq!(i.next(), Some(&6));
78 assert_eq!(i.peek(2), None);
79 assert_eq!(i.next(), Some(&7));
80 assert_eq!(i.peek(2), None);
81 assert_eq!(i.next(), Some(&8));
82 assert_eq!(i.next(), None);
83 }
84}