pipecircuit 0.0.21

Correct. Robust. Fast. Portable. Pick four.
Documentation
use super::inconsistency;
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(
    ::core::clone::Clone,
    ::core::marker::Copy,
    ::core::fmt::Debug,
    ::core::cmp::Eq,
    ::core::cmp::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 = inconsistency::slot_index::<usize>(slot)?;
        match self
            .slot_locations
            .get(slot_index)
            .ok_or(StableSlotsInconsistency::SlotUnavailable { slot })?
        {
            SlotLocation::Occupied(stored_row) => {
                let dense_row = inconsistency::stored_row(slot, *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 = inconsistency::row(expected_row)?;
        let slot_index = inconsistency::slot_index::<usize>(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 }),
        }
    }
}