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