1use super::*;
2use crate::classification::{quotes::QuoteClassifiedBlock, ResumeClassifierBlockState};
3use crate::debug;
4
5pub(crate) struct Constructor;
6
7impl StructuralImpl for Constructor {
8 type Classifier<'i, I, Q>
9 = SequentialClassifier<'i, I, Q, BLOCK_SIZE>
10 where
11 I: InputBlockIterator<'i, BLOCK_SIZE>,
12 Q: QuoteClassifiedIterator<'i, I, MaskType, BLOCK_SIZE>;
13
14 #[inline(always)]
15 fn new<'i, I, Q>(iter: Q) -> Self::Classifier<'i, I, Q>
16 where
17 I: InputBlockIterator<'i, BLOCK_SIZE>,
18 Q: QuoteClassifiedIterator<'i, I, MaskType, BLOCK_SIZE>,
19 {
20 Self::Classifier {
21 iter,
22 block: None,
23 are_colons_on: false,
24 are_commas_on: false,
25 }
26 }
27}
28
29struct Block<'i, I, const N: usize>
30where
31 I: InputBlockIterator<'i, N>,
32{
33 quote_classified: QuoteClassifiedBlock<I::Block, MaskType, N>,
34 idx: usize,
35 are_colons_on: bool,
36 are_commas_on: bool,
37}
38
39impl<'i, I, const N: usize> Block<'i, I, N>
40where
41 I: InputBlockIterator<'i, N>,
42{
43 fn new(
44 quote_classified_block: QuoteClassifiedBlock<I::Block, MaskType, N>,
45 are_colons_on: bool,
46 are_commas_on: bool,
47 ) -> Self {
48 Self {
49 quote_classified: quote_classified_block,
50 idx: 0,
51 are_colons_on,
52 are_commas_on,
53 }
54 }
55
56 fn from_idx(
57 quote_classified_block: QuoteClassifiedBlock<I::Block, MaskType, N>,
58 idx: usize,
59 are_colons_on: bool,
60 are_commas_on: bool,
61 ) -> Self {
62 Self {
63 quote_classified: quote_classified_block,
64 idx,
65 are_colons_on,
66 are_commas_on,
67 }
68 }
69}
70
71impl<'i, I, const N: usize> Iterator for Block<'i, I, N>
72where
73 I: InputBlockIterator<'i, N>,
74{
75 type Item = Structural;
76
77 fn next(&mut self) -> Option<Self::Item> {
78 while self.idx < self.quote_classified.block.len() {
79 let character = self.quote_classified.block[self.idx];
80 let idx_mask = 1 << self.idx;
81 let is_quoted = (self.quote_classified.within_quotes_mask & idx_mask) == idx_mask;
82
83 let structural = match character {
84 _ if is_quoted => None,
85 b':' if self.are_colons_on => Some(Colon(self.idx)),
86 b'{' => Some(Opening(BracketType::Curly, self.idx)),
87 b'[' => Some(Opening(BracketType::Square, self.idx)),
88 b',' if self.are_commas_on => Some(Comma(self.idx)),
89 b'}' => Some(Closing(BracketType::Curly, self.idx)),
90 b']' => Some(Closing(BracketType::Square, self.idx)),
91 _ => None,
92 };
93
94 self.idx += 1;
95
96 if structural.is_some() {
97 return structural;
98 }
99 }
100
101 None
102 }
103}
104
105pub(crate) struct SequentialClassifier<'i, I, Q, const N: usize>
106where
107 I: InputBlockIterator<'i, N>,
108{
109 iter: Q,
110 block: Option<Block<'i, I, N>>,
111 are_colons_on: bool,
112 are_commas_on: bool,
113}
114
115impl<'i, I, Q, const N: usize> SequentialClassifier<'i, I, Q, N>
116where
117 I: InputBlockIterator<'i, N>,
118 Q: QuoteClassifiedIterator<'i, I, MaskType, N>,
119{
120 #[inline]
121 fn reclassify(&mut self, idx: usize) {
122 if let Some(block) = self.block.take() {
123 let relative_idx = idx + 1 - self.iter.get_offset();
124 let quote_classified_block = block.quote_classified;
125 debug!("relative_idx is {relative_idx}.");
126 if relative_idx < N {
127 let new_block = Block::from_idx(
128 quote_classified_block,
129 relative_idx,
130 self.are_colons_on,
131 self.are_commas_on,
132 );
133 self.block = Some(new_block);
134 }
135 }
136 }
137}
138
139impl<'i, I, Q, const N: usize> FallibleIterator for SequentialClassifier<'i, I, Q, N>
140where
141 I: InputBlockIterator<'i, N>,
142 Q: QuoteClassifiedIterator<'i, I, MaskType, N>,
143{
144 type Item = Structural;
145 type Error = InputError;
146
147 #[inline(always)]
148 fn next(&mut self) -> Result<Option<Structural>, InputError> {
149 let mut item = self.block.as_mut().and_then(Iterator::next);
150
151 while item.is_none() {
152 match self.iter.next()? {
153 Some(block) => {
154 let mut block = Block::new(block, self.are_colons_on, self.are_commas_on);
155 item = block.next();
156 self.block = Some(block);
157 }
158 None => return Ok(None),
159 }
160 }
161
162 Ok(item.map(|x| x.offset(self.iter.get_offset())))
163 }
164}
165
166impl<'i, I, Q, const N: usize> StructuralIterator<'i, I, Q, MaskType, N> for SequentialClassifier<'i, I, Q, N>
167where
168 I: InputBlockIterator<'i, N>,
169 Q: QuoteClassifiedIterator<'i, I, MaskType, N>,
170{
171 fn turn_colons_and_commas_on(&mut self, idx: usize) {
172 if !self.are_commas_on && !self.are_colons_on {
173 self.are_commas_on = true;
174 self.are_colons_on = true;
175 debug!("Turning both commas and colons on at {idx}.");
176
177 self.reclassify(idx);
178 } else if !self.are_commas_on {
179 self.turn_commas_on(idx);
180 } else if !self.are_colons_on {
181 self.turn_colons_on(idx);
182 }
183 }
184
185 fn turn_colons_and_commas_off(&mut self) {
186 if self.are_commas_on && self.are_colons_on {
187 self.are_commas_on = false;
188 self.are_colons_on = false;
189 debug!("Turning both commas and colons off.");
190 } else if self.are_commas_on {
191 self.turn_commas_off();
192 } else if self.are_colons_on {
193 self.turn_colons_off();
194 }
195 }
196
197 fn turn_commas_on(&mut self, idx: usize) {
198 if !self.are_commas_on {
199 self.are_commas_on = true;
200 debug!("Turning commas on at {idx}.");
201
202 self.reclassify(idx);
203 }
204 }
205
206 fn turn_commas_off(&mut self) {
207 self.are_commas_on = false;
208 debug!("Turning commas off.");
209 }
210
211 fn turn_colons_on(&mut self, idx: usize) {
212 if !self.are_colons_on {
213 self.are_colons_on = true;
214 debug!("Turning colons on at {idx}.");
215
216 self.reclassify(idx);
217 }
218 }
219
220 fn turn_colons_off(&mut self) {
221 self.are_colons_on = false;
222 debug!("Turning colons off.");
223 }
224
225 fn stop(self) -> ResumeClassifierState<'i, I, Q, MaskType, N> {
226 let block = self.block.map(|b| ResumeClassifierBlockState {
227 block: b.quote_classified,
228 idx: b.idx,
229 });
230 ResumeClassifierState {
231 iter: self.iter,
232 block,
233 are_colons_on: self.are_colons_on,
234 are_commas_on: self.are_commas_on,
235 }
236 }
237
238 fn resume(state: ResumeClassifierState<'i, I, Q, MaskType, N>) -> Self {
239 Self {
240 iter: state.iter,
241 block: state.block.map(|b| Block {
242 quote_classified: b.block,
243 idx: b.idx,
244 are_commas_on: state.are_commas_on,
245 are_colons_on: state.are_colons_on,
246 }),
247 are_commas_on: state.are_commas_on,
248 are_colons_on: state.are_colons_on,
249 }
250 }
251}