pipecircuit 0.0.2

Correct. Robust. Fast. Portable.
Documentation
use core::iter::FusedIterator;

use super::{SlotLocation, StableSlot, StableSlots, StableSlotsInconsistency};
use crate::storage::warp_table::secondary_index::{SlotSet, SlotSetSlots};

pub trait StableSlotResolver {
    fn resolve_stable_slot(
        &self,
        slot: StableSlot,
    ) -> Result<StableSlotResolveOutcome, StableSlotsInconsistency>;
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub enum StableSlotResolveOutcome {
    Resolved { slot: StableSlot, dense_row: usize },
}

#[must_use]
pub struct StableSlotResolutions<'slots> {
    slots: SlotSetSlots<'slots>,
    stable_slots: &'slots StableSlots,
}

impl Iterator for StableSlotResolutions<'_> {
    type Item = Result<StableSlotResolveOutcome, StableSlotsInconsistency>;

    fn next(&mut self) -> Option<Self::Item> {
        self.slots
            .next()
            .map(|slot| self.stable_slots.resolve(slot))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.slots.size_hint()
    }
}

impl DoubleEndedIterator for StableSlotResolutions<'_> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.slots
            .next_back()
            .map(|slot| self.stable_slots.resolve(slot))
    }
}

#[cfg(target_pointer_width = "64")]
impl ExactSizeIterator for StableSlotResolutions<'_> {}

impl FusedIterator for StableSlotResolutions<'_> {}

impl StableSlots {
    pub fn resolve_slots<'slots>(
        &'slots self,
        slots: &'slots SlotSet,
    ) -> StableSlotResolutions<'slots> {
        StableSlotResolutions {
            slots: slots.slots(),
            stable_slots: self,
        }
    }

    pub fn resolve(
        &self,
        slot: StableSlot,
    ) -> Result<StableSlotResolveOutcome, StableSlotsInconsistency> {
        let slot_index = usize::try_from(slot.value())
            .map_err(|_| StableSlotsInconsistency::SlotUnrepresentable { slot })?;
        match self
            .slot_locations
            .get(slot_index)
            .ok_or(StableSlotsInconsistency::SlotUnavailable { slot })?
        {
            SlotLocation::Occupied(stored_row) => {
                let dense_row = usize::try_from(*stored_row).map_err(|_| {
                    StableSlotsInconsistency::StoredRowUnrepresentable {
                        slot,
                        stored_row: *stored_row,
                    }
                })?;
                Ok(StableSlotResolveOutcome::Resolved { slot, dense_row })
            }
            SlotLocation::Free(_) => Err(StableSlotsInconsistency::SlotVacant { slot }),
        }
    }

    pub fn slot(&self, row: usize) -> Result<StableSlot, StableSlotsInconsistency> {
        let slot = self
            .row_to_slot
            .get(row)
            .copied()
            .ok_or(StableSlotsInconsistency::RowUnavailable { row })?;
        self.validate_location(slot, row)?;
        Ok(slot)
    }

    pub(super) fn validate_location(
        &self,
        slot: StableSlot,
        expected_row: usize,
    ) -> Result<usize, StableSlotsInconsistency> {
        let expected = u32::try_from(expected_row)
            .map_err(|_| StableSlotsInconsistency::RowUnrepresentable { row: expected_row })?;
        let slot_index = usize::try_from(slot.value())
            .map_err(|_| StableSlotsInconsistency::SlotUnrepresentable { slot })?;
        match self
            .slot_locations
            .get(slot_index)
            .ok_or(StableSlotsInconsistency::SlotUnavailable { slot })?
        {
            SlotLocation::Occupied(actual) if *actual == expected => Ok(slot_index),
            SlotLocation::Occupied(actual) => Err(StableSlotsInconsistency::SlotRowMismatch {
                slot,
                expected,
                actual: *actual,
            }),
            SlotLocation::Free(_) => Err(StableSlotsInconsistency::SlotVacant { slot }),
        }
    }
}