use core::{iter::FusedIterator, ops::Range};
use super::inconsistency::invariant_violation;
use super::{WarpTable, WarpTableGetAtOutcome, WarpTableInconsistency, WarpTableRow};
#[must_use]
pub struct WarpTableRows<'table, Row: WarpTableRow, Brand = Row> {
table: &'table WarpTable<Row, Brand>,
dense_rows: Range<usize>,
}
impl<'table, Row: WarpTableRow, Brand> Iterator for WarpTableRows<'table, Row, Brand> {
type Item = Row::Ref<'table>;
fn next(&mut self) -> Option<Self::Item> {
let dense_row = self.dense_rows.next()?;
match self.table.get_at(dense_row) {
WarpTableGetAtOutcome::Present { row, .. } => Some(row),
WarpTableGetAtOutcome::Absent { dense_row } => {
invariant_violation(WarpTableInconsistency::DenseRowUnavailable {
row: dense_row,
rows: self.table.len(),
})
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.dense_rows.size_hint()
}
}
impl<Row: WarpTableRow, Brand> ExactSizeIterator for WarpTableRows<'_, Row, Brand> {}
impl<Row: WarpTableRow, Brand> FusedIterator for WarpTableRows<'_, Row, Brand> {}
impl<Row: WarpTableRow, Brand> WarpTable<Row, Brand> {
pub fn rows(&self) -> WarpTableRows<'_, Row, Brand> {
WarpTableRows {
table: self,
dense_rows: 0..self.len,
}
}
}
#[cfg(test)]
mod tests {
extern crate std;
use self::std::panic::catch_unwind;
use super::*;
use core::panic::AssertUnwindSafe;
#[derive(WarpTableRow)]
struct Item {
value: u8,
}
#[test]
fn an_invalid_dense_iteration_range_reports_the_exact_row_and_bound() -> Result<(), &'static str>
{
let table =
WarpTable::<Item>::try_new(super::super::Capacity::new(core::num::NonZeroU32::MIN))
.map_err(|_| "table unavailable")?;
let mut rows = WarpTableRows {
table: &table,
dense_rows: 7..8,
};
let Err(reason) = catch_unwind(AssertUnwindSafe(|| rows.next())) else {
return Err("invalid row range yielded normally");
};
let diagnostic = reason
.downcast_ref::<alloc::string::String>()
.ok_or("missing diagnostic")?;
assert_eq!(
diagnostic,
"WarpTable invariant violated: DenseRowUnavailable { row: 7, rows: 0 }"
);
assert!(table.is_empty());
Ok(())
}
}