pipecircuit 0.0.22

Correct. Robust. Fast. Portable. Pick four.
Documentation
use alloc::collections::TryReserveError;
use core::num::{NonZeroU32, TryFromIntError};

use super::dense_key_index::{DenseKeyIndex, DenseKeyIndexCreationError};
use super::{WarpTable, WarpTableRow};

crate::value_wrapper! {
    #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    pub struct Capacity(NonZeroU32);
}

#[derive(::core::fmt::Debug)]
pub enum WarpTableCreationError<ColumnsError, IndexesError> {
    CapacityUnrepresentable {
        capacity: Capacity,
        source: TryFromIntError,
    },
    ColumnsUnavailable {
        source: ColumnsError,
    },
    IndexesUnavailable {
        source: IndexesError,
    },
    IdStorageUnavailable {
        source: TryReserveError,
    },
    PrimaryIndexCapacityOverflow {
        maximum_rows: usize,
    },
    PrimaryIndexStorageUnavailable {
        source: TryReserveError,
    },
}

impl<Row: WarpTableRow, Brand> WarpTable<Row, Brand> {
    pub fn try_new(
        capacity: Capacity,
    ) -> Result<Self, WarpTableCreationError<Row::ColumnsCreationError, Row::IndexesCreationError>>
    {
        let maximum_rows = represent_capacity(capacity)?;
        let columns = Row::try_new_columns(maximum_rows)
            .map_err(|source| WarpTableCreationError::ColumnsUnavailable { source })?;
        let indexes = Row::try_new_indexes(maximum_rows)
            .map_err(|source| WarpTableCreationError::IndexesUnavailable { source })?;
        let mut ids = alloc::vec::Vec::new();
        ids.try_reserve_exact(maximum_rows)
            .map_err(|source| WarpTableCreationError::IdStorageUnavailable { source })?;
        let primary_index =
            DenseKeyIndex::try_new(maximum_rows).map_err(WarpTableCreationError::from)?;
        Ok(Self {
            capacity,
            maximum_rows,
            len: 0,
            next_id: Some(core::num::NonZeroU64::MIN),
            ids,
            columns,
            indexes,
            primary_index,
            brand: core::marker::PhantomData,
        })
    }
}

fn represent_capacity<Index, ColumnsError, IndexesError>(
    capacity: Capacity,
) -> Result<Index, WarpTableCreationError<ColumnsError, IndexesError>>
where
    Index: TryFrom<u32, Error = TryFromIntError>,
{
    Index::try_from(capacity.value().get())
        .map_err(|source| WarpTableCreationError::CapacityUnrepresentable { capacity, source })
}

impl<ColumnsError, IndexesError> From<DenseKeyIndexCreationError>
    for WarpTableCreationError<ColumnsError, IndexesError>
{
    fn from(reason: DenseKeyIndexCreationError) -> Self {
        match reason {
            DenseKeyIndexCreationError::CapacityOverflow { maximum_rows } => {
                Self::PrimaryIndexCapacityOverflow { maximum_rows }
            }
            DenseKeyIndexCreationError::StorageUnavailable { source } => {
                Self::PrimaryIndexStorageUnavailable { source }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn primary_creation_refusals_preserve_the_bound_or_allocator_cause() -> Result<(), &'static str>
    {
        use alloc::string::ToString;
        let mapped: WarpTableCreationError<(), ()> =
            DenseKeyIndexCreationError::CapacityOverflow { maximum_rows: 19 }.into();
        assert!(matches!(
            mapped,
            WarpTableCreationError::PrimaryIndexCapacityOverflow { maximum_rows: 19 }
        ));
        let source = alloc::vec::Vec::<u8>::new()
            .try_reserve_exact(usize::MAX)
            .err()
            .ok_or("impossible allocation succeeded")?;
        let message = source.to_string();
        let mapped: WarpTableCreationError<(), ()> =
            DenseKeyIndexCreationError::StorageUnavailable { source }.into();
        let WarpTableCreationError::PrimaryIndexStorageUnavailable { source } = mapped else {
            return Err("failure stage changed");
        };
        assert_eq!(source.to_string(), message);
        Ok(())
    }
}
#[test]
fn capacity_representation_retains_the_bound_on_narrow_targets() -> Result<(), &'static str> {
    let maximum = Capacity::new(NonZeroU32::new(u32::from(u16::MAX)).ok_or("zero capacity")?);
    assert!(matches!(
        represent_capacity::<u16, (), ()>(maximum),
        Ok(u16::MAX)
    ));
    let outside = Capacity::new(
        NonZeroU32::new(u32::from(u16::MAX).saturating_add(1)).ok_or("zero capacity")?,
    );
    assert!(
        matches!(represent_capacity::<u16, (), ()>(outside), Err(WarpTableCreationError::CapacityUnrepresentable { capacity, .. }) if capacity == outside)
    );
    assert!(
        matches!(represent_capacity::<usize, (), ()>(maximum), Ok(value) if value == usize::from(u16::MAX))
    );
    Ok(())
}