| 492 | } |
| 493 | |
| 494 | fn project_impl(mut self, projection: Option<&[usize]>) -> Self { |
| 495 | let Some(projection) = projection.map(AsRef::as_ref) else { |
| 496 | return self; |
| 497 | }; |
| 498 | |
| 499 | #[expect(clippy::large_enum_variant)] |
| 500 | enum Slot { |
| 501 | /// The column is taken and put into the specified statistics location |
| 502 | Taken(usize), |
| 503 | /// The original columns is present |
| 504 | Present(ColumnStatistics), |
| 505 | } |
| 506 | |
| 507 | // Convert to Vec<Slot> so we can avoid copying the statistics |
| 508 | let mut columns: Vec<_> = std::mem::take(&mut self.column_statistics) |
| 509 | .into_iter() |
| 510 | .map(Slot::Present) |
| 511 | .collect(); |
| 512 | |
| 513 | for idx in projection.iter() { |
| 514 | let next_idx = self.column_statistics.len(); |
| 515 | let slot = std::mem::replace( |
| 516 | columns.get_mut(*idx).expect("projection out of bounds"), |
| 517 | Slot::Taken(next_idx), |
| 518 | ); |
| 519 | match slot { |
| 520 | // The column was there, so just move it |
| 521 | Slot::Present(col) => self.column_statistics.push(col), |
| 522 | // The column was taken, so copy from the previous location |
| 523 | Slot::Taken(prev_idx) => self |
| 524 | .column_statistics |
| 525 | .push(self.column_statistics[prev_idx].clone()), |
| 526 | } |
| 527 | } |
| 528 | |
| 529 | self |
| 530 | } |
| 531 | |
| 532 | /// Calculates the statistics after applying `fetch` and `skip` operations. |
| 533 | /// |