saphyr_parser_bw/input/
buffered.rs1use crate::char_traits::is_breakz;
2use crate::input::{BorrowedInput, Input};
3
4use arraydeque::ArrayDeque;
5
6const BUFFER_LEN: usize = 16;
17
18#[allow(clippy::module_name_repetitions)]
26pub struct BufferedInput<T: Iterator<Item = char>> {
27 input: T,
29 buffer: ArrayDeque<char, BUFFER_LEN>,
31}
32
33impl<T: Iterator<Item = char>> BufferedInput<T> {
34 pub fn new(input: T) -> Self {
36 Self {
37 input,
38 buffer: ArrayDeque::default(),
39 }
40 }
41}
42
43impl<T: Iterator<Item = char>> Input for BufferedInput<T> {
44 #[inline]
45 fn lookahead(&mut self, count: usize) {
46 let target = count.min(BUFFER_LEN);
47
48 if self.buffer.len() >= target {
49 return;
50 }
51 for _ in 0..(target - self.buffer.len()) {
52 self.buffer
53 .push_back(self.input.next().unwrap_or('\0'))
54 .unwrap();
55 }
56 }
57
58 #[inline]
59 fn buflen(&self) -> usize {
60 self.buffer.len()
61 }
62
63 #[inline]
64 fn bufmaxlen(&self) -> usize {
65 BUFFER_LEN
66 }
67
68 #[inline]
69 fn raw_read_ch(&mut self) -> char {
70 self.input.next().unwrap_or('\0')
71 }
72
73 #[inline]
74 fn raw_read_non_breakz_ch(&mut self) -> Option<char> {
75 if let Some(c) = self.input.next() {
76 if is_breakz(c) {
77 self.buffer.push_back(c).unwrap();
78 None
79 } else {
80 Some(c)
81 }
82 } else {
83 None
84 }
85 }
86
87 #[inline]
88 fn skip(&mut self) {
89 self.buffer.pop_front();
90 }
91
92 #[inline]
93 fn skip_n(&mut self, count: usize) {
94 self.buffer.drain(0..count);
95 }
96
97 #[inline]
98 fn peek(&self) -> char {
99 self.buffer[0]
100 }
101
102 #[inline]
103 fn peek_nth(&self, n: usize) -> char {
104 self.buffer[n]
105 }
106}
107
108impl<T: Iterator<Item = char>> BorrowedInput<'static> for BufferedInput<T> {
111 #[inline]
112 fn slice_borrowed(&self, _start: usize, _end: usize) -> Option<&'static str> {
113 None
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[test]
122 fn lookahead_larger_than_buffer_is_clamped() {
123 let mut input = BufferedInput::new("abc".chars());
124
125 input.lookahead(BUFFER_LEN + 8);
126
127 assert_eq!(input.buflen(), BUFFER_LEN);
128 assert_eq!(input.peek(), 'a');
129 assert_eq!(input.peek_nth(1), 'b');
130 assert_eq!(input.peek_nth(2), 'c');
131 assert_eq!(input.peek_nth(3), '\0');
132 }
133}