pipecircuit 0.0.22

Correct. Robust. Fast. Portable. Pick four.
Documentation
use alloc::{collections::TryReserveError, vec::Vec};

use super::SecondaryIndex;
use crate::storage::warp_table::IndexKey;
use crate::storage::warp_table::dense_key_index::{DenseKeyIndex, DenseKeyIndexCreationError};

#[derive(Debug)]
pub enum SecondaryIndexCreationError {
    SecondaryKeyStorageUnavailable { source: TryReserveError },
    SlotSetStorageUnavailable { source: TryReserveError },
    SecondaryKeyIndexCapacityOverflow { maximum_distinct_keys: usize },
    SecondaryKeyIndexStorageUnavailable { source: TryReserveError },
}

impl<SecondaryKey: IndexKey> SecondaryIndex<SecondaryKey> {
    pub fn try_new(maximum_distinct_keys: usize) -> Result<Self, SecondaryIndexCreationError> {
        let mut secondary_keys = Vec::new();
        secondary_keys
            .try_reserve_exact(maximum_distinct_keys)
            .map_err(
                |source| SecondaryIndexCreationError::SecondaryKeyStorageUnavailable { source },
            )?;
        let mut slot_sets = Vec::new();
        slot_sets
            .try_reserve_exact(maximum_distinct_keys)
            .map_err(|source| SecondaryIndexCreationError::SlotSetStorageUnavailable { source })?;
        let secondary_key_index = DenseKeyIndex::try_new(maximum_distinct_keys)
            .map_err(SecondaryIndexCreationError::from)?;
        Ok(Self {
            maximum_distinct_keys,
            secondary_keys,
            slot_sets,
            secondary_key_index,
        })
    }
}

impl From<DenseKeyIndexCreationError> for SecondaryIndexCreationError {
    fn from(reason: DenseKeyIndexCreationError) -> Self {
        match reason {
            DenseKeyIndexCreationError::CapacityOverflow { maximum_rows } => {
                Self::SecondaryKeyIndexCapacityOverflow {
                    maximum_distinct_keys: maximum_rows,
                }
            }
            DenseKeyIndexCreationError::StorageUnavailable { source } => {
                Self::SecondaryKeyIndexStorageUnavailable { source }
            }
        }
    }
}

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

    #[test]
    fn secondary_creation_refusals_preserve_the_bound_or_allocator_cause()
    -> Result<(), &'static str> {
        use alloc::string::ToString;
        let mapped =
            SecondaryIndexCreationError::from(DenseKeyIndexCreationError::CapacityOverflow {
                maximum_rows: 23,
            });
        assert!(matches!(
            mapped,
            SecondaryIndexCreationError::SecondaryKeyIndexCapacityOverflow {
                maximum_distinct_keys: 23
            }
        ));
        let source = Vec::<u8>::new()
            .try_reserve_exact(usize::MAX)
            .err()
            .ok_or("impossible allocation succeeded")?;
        let message = source.to_string();
        let mapped =
            SecondaryIndexCreationError::from(DenseKeyIndexCreationError::StorageUnavailable {
                source,
            });
        let SecondaryIndexCreationError::SecondaryKeyIndexStorageUnavailable { source } = mapped
        else {
            return Err("failure stage changed");
        };
        assert_eq!(source.to_string(), message);
        Ok(())
    }
}