Advances the decoder state machine until the next [`RecordBatch`] is produced, the file is fully consumed, or an error occurs. On each iteration the decoder is polled via [`ParquetPushDecoder::try_decode`]: - [`NeedsData`](DecodeResult::NeedsData) – the requested byte ranges are fetched from the [`AsyncFileReader`] and fed back into the decoder. - [`Data`](DecodeResult::Data) – a decoded batch is
(mut self)
| 147 | /// miri where `&mut self` creates a single opaque borrow that conflicts |
| 148 | /// with `unfold`'s ownership across yield points. |
| 149 | async fn transition(mut self) -> Option<(Result<RecordBatch>, Self)> { |
| 150 | loop { |
| 151 | if self.remaining_limit == Some(0) { |
| 152 | return None; |
| 153 | } |
| 154 | match self.decoder.try_decode() { |
| 155 | Ok(DecodeResult::NeedsData(ranges)) => { |
| 156 | let data = self |
| 157 | .reader |
| 158 | .get_byte_ranges(ranges.clone()) |
| 159 | .await |
| 160 | .map_err(DataFusionError::from); |
| 161 | match data { |
| 162 | Ok(data) => { |
| 163 | if let Err(e) = self.decoder.push_ranges(ranges, data) { |
| 164 | return Some((Err(DataFusionError::from(e)), self)); |
| 165 | } |
| 166 | } |
| 167 | Err(e) => return Some((Err(e), self)), |
| 168 | } |
| 169 | } |
| 170 | Ok(DecodeResult::Data(batch)) => { |
| 171 | let batch = if let Some(remaining_limit) = self.remaining_limit { |
| 172 | if batch.num_rows() > remaining_limit { |
| 173 | self.remaining_limit = Some(0); |
| 174 | batch.slice(0, remaining_limit) |
| 175 | } else { |
| 176 | self.remaining_limit = |
| 177 | Some(remaining_limit - batch.num_rows()); |
| 178 | batch |
| 179 | } |
| 180 | } else { |
| 181 | batch |
| 182 | }; |
| 183 | let mut timer = self.baseline_metrics.elapsed_compute().timer(); |
| 184 | self.copy_arrow_reader_metrics(); |
| 185 | let result = self.project_batch(&batch); |
| 186 | timer.stop(); |
| 187 | // Release the borrow on baseline_metrics before moving self |
| 188 | drop(timer); |
| 189 | return Some((result, self)); |
| 190 | } |
| 191 | Ok(DecodeResult::Finished) => { |
| 192 | // If there are pending decoders (e.g. for consecutive runs |
| 193 | // with different filter configurations), switch to the next. |
| 194 | if let Some(next) = self.pending_decoders.pop_front() { |
| 195 | self.decoder = next; |
| 196 | continue; |
| 197 | } |
| 198 | return None; |
| 199 | } |
| 200 | Err(e) => { |
| 201 | return Some((Err(DataFusionError::from(e)), self)); |
| 202 | } |
| 203 | } |
| 204 | } |
| 205 | } |
| 206 |
no test coverage detected