pipecircuit 0.0.25

Correct. Robust. Fast. Portable. Pick four.
Documentation
use super::super::{
    RangeIndexOrderingLevel, RankingWorkspaceError, StorageLease, WarpTable, WarpTableBacking,
    WarpTableGetAtOutcome, WarpTableRow,
    inconsistency::invariant_violation,
    range_ordering::{
        RangeIndexRankingCandidates, WorkspaceRanking, rank_with, ranking_storage_bytes,
    },
    stable_slots::{StableSlotResolveOutcome, StableSlotResolver},
};
use super::selection::CallerSelection;
use core::num::NonZeroUsize;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CallerRankingError {
    NoOrderingLevels,
    DifferentTables,
    Workspace(RankingWorkspaceError),
}

pub struct CallerRanking<'table, 'storage, Row: WarpTableRow, Brand, Backing: WarpTableBacking<Row>>
{
    table: &'table WarpTable<Row, Brand, Backing>,
    ranking: WorkspaceRanking<'storage>,
}

impl<'table, Row: WarpTableRow, Brand, Backing: WarpTableBacking<Row>>
    CallerSelection<'table, '_, Row, Brand, Backing>
{
    pub fn ranking_storage_bytes(
        &self,
    ) -> Result<usize, pipecircuit_storage_backing::StorageRefusalReason> {
        ranking_storage_bytes(self.table.maximum_rows)
    }

    pub fn rank_in<'storage, const LEVELS: usize>(
        &self,
        storage: StorageLease<'storage>,
        limit: NonZeroUsize,
        order: impl FnOnce(
            &'table Backing::Indexes,
        ) -> [CallerOrderingLevel<'table, Backing::Indexes>; LEVELS],
    ) -> Result<CallerRanking<'table, 'storage, Row, Brand, Backing>, CallerRankingError>
    where
        'table: 'storage,
    {
        let levels = order(&self.table.indexes);
        if levels
            .iter()
            .any(|level| !core::ptr::eq(&self.table.indexes, level.indexes))
        {
            return Err(CallerRankingError::DifferentTables);
        }
        let levels = levels.map(|level| level.ordering);
        let (first, later) = levels
            .split_first()
            .ok_or(CallerRankingError::NoOrderingLevels)?;
        let (ranking, _remaining) = rank_with(
            first,
            later,
            RangeIndexRankingCandidates::Workspace(&self.membership),
            limit,
            storage,
        )
        .map_err(CallerRankingError::Workspace)?;
        Ok(CallerRanking {
            table: self.table,
            ranking,
        })
    }
}

impl<'table, Row: WarpTableRow, Brand, Backing: WarpTableBacking<Row>>
    CallerRanking<'table, '_, Row, Brand, Backing>
where
    Backing::Indexes: StableSlotResolver,
{
    pub fn leaders(&self) -> impl Iterator<Item = Row::Ref<'table>> + '_ {
        self.ranking.leaders().map(|slot| self.row(slot))
    }
    pub fn ties(&self) -> impl Iterator<Item = Row::Ref<'table>> + '_ {
        self.ranking.tied().map(|slot| self.row(slot))
    }
    pub const fn needed_from_ties(&self) -> Option<NonZeroUsize> {
        self.ranking.needed
    }
    pub fn leader_count(&self) -> usize {
        self.ranking.leader_count()
    }
    pub fn tie_count(&self) -> usize {
        self.ranking.tied_count()
    }
    fn row(&self, slot: crate::storage::StableSlot) -> Row::Ref<'table> {
        let StableSlotResolveOutcome::Resolved { dense_row, .. } = self
            .table
            .indexes
            .resolve_stable_slot(slot)
            .unwrap_or_else(|reason| invariant_violation(reason));
        match self.table.get_at(dense_row) {
            WarpTableGetAtOutcome::Present { row, .. } => row,
            WarpTableGetAtOutcome::Absent { dense_row } => invariant_violation(dense_row),
        }
    }
}

pub struct CallerOrderingLevel<'index, Indexes> {
    indexes: &'index Indexes,
    ordering: RangeIndexOrderingLevel<'index>,
}
impl<'index, Indexes> CallerOrderingLevel<'index, Indexes> {
    pub fn new(indexes: &'index Indexes, ordering: RangeIndexOrderingLevel<'index>) -> Self {
        Self { indexes, ordering }
    }
}