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 }),
}
}
}