rsonpath/classification/structural/
shared.rs

1#[cfg(target_arch = "x86")]
2pub(super) mod mask_32;
3#[cfg(target_arch = "x86_64")]
4pub(super) mod mask_64;
5#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
6pub(super) mod vector_128;
7#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
8pub(super) mod vector_256;
9
10#[allow(unused_macros)]
11macro_rules! structural_classifier {
12    ($name:ident, $core:ident, $mask_mod:ident, $size:literal, $mask_ty:ty) => {
13        pub(crate) struct Constructor;
14
15        impl StructuralImpl for Constructor {
16            type Classifier<'i, I, Q>
17                = $name<'i, I, Q>
18            where
19                I: InputBlockIterator<'i, BLOCK_SIZE>,
20                Q: QuoteClassifiedIterator<'i, I, MaskType, BLOCK_SIZE>;
21
22            #[inline]
23            #[allow(dead_code)]
24            fn new<'i, I, Q>(iter: Q) -> Self::Classifier<'i, I, Q>
25            where
26                I: InputBlockIterator<'i, BLOCK_SIZE>,
27                Q: QuoteClassifiedIterator<'i, I, MaskType, BLOCK_SIZE>,
28            {
29                Self::Classifier {
30                    iter,
31                    classifier: $core::new(),
32                    block: None,
33                    are_commas_on: false,
34                    are_colons_on: false,
35                }
36            }
37        }
38
39        pub(crate) struct $name<'a, I, Q>
40        where
41            I: InputBlockIterator<'a, $size>,
42        {
43            iter: Q,
44            classifier: $core,
45            block: Option<$mask_mod::StructuralsBlock<I::Block>>,
46            are_commas_on: bool,
47            are_colons_on: bool,
48        }
49
50        impl<'a, I: InputBlockIterator<'a, $size>, Q: QuoteClassifiedIterator<'a, I, $mask_ty, $size>> $name<'a, I, Q> {
51            #[inline(always)]
52            fn current_block_is_spent(&self) -> bool {
53                self.block
54                    .as_ref()
55                    .map_or(true, $mask_mod::StructuralsBlock::is_empty)
56            }
57
58            #[inline]
59            fn reclassify(&mut self, idx: usize) {
60                if let Some(block) = self.block.take() {
61                    let quote_classified_block = block.quote_classified;
62                    let relevant_idx = idx + 1;
63                    let block_idx = (idx + 1) % $size;
64                    debug!("relevant_idx is {relevant_idx}.");
65
66                    if block_idx != 0 || relevant_idx == self.iter.get_offset() {
67                        debug!("need to reclassify.");
68
69                        let mask = <$mask_ty>::MAX << block_idx;
70                        // SAFETY: target_feature invariant
71                        let mut new_block = unsafe { self.classifier.classify(quote_classified_block) };
72                        new_block.structural_mask &= mask;
73                        self.block = Some(new_block);
74                    }
75                }
76            }
77        }
78
79        impl<'a, I, Q> FallibleIterator for $name<'a, I, Q>
80        where
81            I: InputBlockIterator<'a, $size>,
82            Q: QuoteClassifiedIterator<'a, I, $mask_ty, $size>,
83        {
84            type Item = Structural;
85            type Error = InputError;
86
87            #[inline(always)]
88            fn next(&mut self) -> Result<Option<Structural>, Self::Error> {
89                while self.current_block_is_spent() {
90                    match self.iter.next() {
91                        Ok(Some(block)) => {
92                            // SAFETY: target_feature invariant
93                            self.block = unsafe { Some(self.classifier.classify(block)) };
94                        }
95                        Ok(None) => {
96                            self.block = None;
97                            break;
98                        }
99                        Err(err) => return Err(err),
100                    }
101                }
102
103                Ok(self
104                    .block
105                    .as_mut()
106                    .and_then(|b| b.next().map(|x| x.offset(self.iter.get_offset()))))
107            }
108        }
109
110        impl<'a, I, Q> StructuralIterator<'a, I, Q, $mask_ty, $size> for $name<'a, I, Q>
111        where
112            I: InputBlockIterator<'a, $size>,
113            Q: QuoteClassifiedIterator<'a, I, $mask_ty, $size>,
114        {
115            #[inline(always)]
116            fn turn_colons_and_commas_on(&mut self, idx: usize) {
117                if !self.are_commas_on && !self.are_colons_on {
118                    self.are_commas_on = true;
119                    self.are_colons_on = true;
120                    debug!("Turning both commas and colons on at {idx}.");
121                    // SAFETY: target_feature invariant
122                    unsafe { self.classifier.internal_classifier.toggle_colons_and_commas() }
123
124                    self.reclassify(idx);
125                } else if !self.are_commas_on {
126                    self.turn_commas_on(idx);
127                } else if !self.are_colons_on {
128                    self.turn_colons_on(idx);
129                }
130            }
131
132            #[inline(always)]
133            fn turn_colons_and_commas_off(&mut self) {
134                if self.are_commas_on && self.are_colons_on {
135                    self.are_commas_on = false;
136                    self.are_colons_on = false;
137                    debug!("Turning both commas and colons off.");
138                    // SAFETY: target_feature invariant
139                    unsafe { self.classifier.internal_classifier.toggle_colons_and_commas() }
140                } else if self.are_commas_on {
141                    self.turn_commas_off();
142                } else if self.are_colons_on {
143                    self.turn_colons_off();
144                }
145            }
146
147            #[inline(always)]
148            fn turn_commas_on(&mut self, idx: usize) {
149                if !self.are_commas_on {
150                    self.are_commas_on = true;
151                    debug!("Turning commas on at {idx}.");
152                    // SAFETY: target_feature invariant
153                    unsafe { self.classifier.internal_classifier.toggle_commas() }
154
155                    self.reclassify(idx);
156                }
157            }
158
159            #[inline(always)]
160            fn turn_commas_off(&mut self) {
161                if self.are_commas_on {
162                    self.are_commas_on = false;
163                    debug!("Turning commas off.");
164                    // SAFETY: target_feature invariant
165                    unsafe { self.classifier.internal_classifier.toggle_commas() }
166                }
167            }
168
169            #[inline(always)]
170            fn turn_colons_on(&mut self, idx: usize) {
171                if !self.are_colons_on {
172                    self.are_colons_on = true;
173                    debug!("Turning colons on at {idx}.");
174                    // SAFETY: target_feature invariant
175                    unsafe { self.classifier.internal_classifier.toggle_colons() }
176
177                    self.reclassify(idx);
178                }
179            }
180
181            #[inline(always)]
182            fn turn_colons_off(&mut self) {
183                if self.are_colons_on {
184                    self.are_colons_on = false;
185                    debug!("Turning colons off.");
186                    // SAFETY: target_feature invariant
187                    unsafe { self.classifier.internal_classifier.toggle_colons() }
188                }
189            }
190
191            #[inline(always)]
192            fn stop(self) -> ResumeClassifierState<'a, I, Q, $mask_ty, $size> {
193                let block = self.block.map(|b| ResumeClassifierBlockState {
194                    idx: b.get_idx() as usize,
195                    block: b.quote_classified,
196                });
197
198                ResumeClassifierState {
199                    iter: self.iter,
200                    block,
201                    are_commas_on: self.are_commas_on,
202                    are_colons_on: self.are_colons_on,
203                }
204            }
205
206            #[inline(always)]
207            fn resume(state: ResumeClassifierState<'a, I, Q, $mask_ty, $size>) -> Self {
208                let mut classifier = $core::new();
209
210                // SAFETY: target_feature invariant
211                unsafe {
212                    if state.are_commas_on && state.are_colons_on {
213                        classifier.internal_classifier.toggle_colons_and_commas();
214                    } else {
215                        if state.are_commas_on {
216                            classifier.internal_classifier.toggle_commas();
217                        }
218                        if state.are_colons_on {
219                            classifier.internal_classifier.toggle_colons();
220                        }
221                    }
222                }
223
224                let block = state.block.map(|b| {
225                    // SAFETY: target_feature invariant
226                    let mut block = unsafe { classifier.classify(b.block) };
227                    let idx_mask = <$mask_ty>::MAX.checked_shl(b.idx as u32).unwrap_or(0);
228                    block.structural_mask &= idx_mask;
229
230                    block
231                });
232
233                Self {
234                    iter: state.iter,
235                    block,
236                    classifier,
237                    are_commas_on: state.are_commas_on,
238                    are_colons_on: state.are_colons_on,
239                }
240            }
241        }
242    };
243}
244
245#[allow(unused_imports)]
246pub(crate) use structural_classifier;