pipecircuit 0.0.23

Correct. Robust. Fast. Portable. Pick four.
Documentation
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(())
    }
}