pipecircuit 0.0.5

Correct. Robust. Fast. Portable.
Documentation
use core::num::NonZeroU64;

use super::dense_key_index::{CommitOutcome, PrepareInsertOutcome};
use super::inconsistency::invariant_violation;
use super::{WarpId, WarpTable, WarpTableInconsistency, WarpTableRow};

#[derive(Debug, Eq, PartialEq)]
#[must_use]
pub enum WarpTableInsertOutcome<Id, Row> {
    Inserted { id: Id, row: usize },
    Full { rejected: Row },
    IdentifiersExhausted { rejected: Row },
}

#[derive(Debug, Eq, PartialEq)]
#[must_use]
pub enum WarpTableInsertWithIdOutcome<Id, Row> {
    Inserted {
        id: Id,
        row: usize,
    },
    AlreadyPresent {
        id: Id,
        existing_row: usize,
        rejected: Row,
    },
    Full {
        id: Id,
        rejected: Row,
    },
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub enum WarpTableInsertAllOutcome {
    Completed,
}

impl<Row: WarpTableRow, Brand> WarpTable<Row, Brand> {
    /// Inserts a row under a caller-supplied ID.
    pub fn insert_with_id(
        &mut self,
        id: Row::Id,
        row: Row,
    ) -> WarpTableInsertWithIdOutcome<Row::Id, Row> {
        let ids = &self.ids;
        if ids.len() != self.len {
            invariant_violation(WarpTableInconsistency::IdColumnLengthMismatch {
                ids: ids.len(),
                rows: self.len,
            });
        }
        let vacancy = match self.primary_index.prepare_insert(id, ids) {
            Ok(PrepareInsertOutcome::Vacant(vacancy)) => vacancy,
            Ok(PrepareInsertOutcome::Present { row: existing_row }) => {
                return WarpTableInsertWithIdOutcome::AlreadyPresent {
                    id,
                    existing_row,
                    rejected: row,
                };
            }
            Err(reason) => invariant_violation(WarpTableInconsistency::from(reason)),
        };
        if self.len >= self.maximum_rows {
            return WarpTableInsertWithIdOutcome::Full { id, rejected: row };
        }
        let warp_table_row = self.len;
        let primary_insert = self
            .primary_index
            .prepare_commit(vacancy, warp_table_row)
            .unwrap_or_else(|reason| invariant_violation(WarpTableInconsistency::from(reason)));
        let indexes_insert = Row::try_prepare_indexes_insert(&mut self.indexes, &row)
            .unwrap_or_else(|reason| invariant_violation(reason));
        let CommitOutcome::Committed {
            row: warp_table_row,
        } = self.primary_index.commit_prepared(primary_insert);
        self.ids.push(id);
        Row::commit_indexes_insert(indexes_insert);
        Row::append(&mut self.columns, row);
        self.len = self.len.saturating_add(1);
        WarpTableInsertWithIdOutcome::Inserted {
            id,
            row: warp_table_row,
        }
    }

    /// Inserts every caller-identified row through [`Self::insert_with_id`].
    ///
    /// `observe` receives each outcome by value, including every rejected row.
    /// The operation allocates no result collection of its own.
    pub fn insert_all_with_id(
        &mut self,
        rows: impl IntoIterator<Item = (Row::Id, Row)>,
        mut observe: impl FnMut(WarpTableInsertWithIdOutcome<Row::Id, Row>),
    ) -> WarpTableInsertAllOutcome {
        for (id, row) in rows {
            observe(self.insert_with_id(id, row));
        }
        WarpTableInsertAllOutcome::Completed
    }
}

impl<Row, Brand> WarpTable<Row, Brand>
where
    Row: WarpTableRow<Id = WarpId<Row>>,
{
    /// Inserts a row under the next available typed sequential identifier.
    pub fn insert(&mut self, mut row: Row) -> WarpTableInsertOutcome<WarpId<Row>, Row> {
        if self.ids.len() != self.len {
            invariant_violation(WarpTableInconsistency::IdColumnLengthMismatch {
                ids: self.ids.len(),
                rows: self.len,
            });
        }
        if self.len >= self.maximum_rows {
            return WarpTableInsertOutcome::Full { rejected: row };
        }
        let attempts = self.len.saturating_add(1);
        for _ in 0..attempts {
            let Some(sequence) = self.next_id else {
                return WarpTableInsertOutcome::IdentifiersExhausted { rejected: row };
            };
            let id = WarpId::new(sequence);
            match self.insert_with_id(id, row) {
                WarpTableInsertWithIdOutcome::Inserted {
                    row: warp_table_row,
                    ..
                } => {
                    self.next_id = following_sequence(sequence);
                    return WarpTableInsertOutcome::Inserted {
                        id,
                        row: warp_table_row,
                    };
                }
                WarpTableInsertWithIdOutcome::AlreadyPresent { rejected, .. } => {
                    self.next_id = following_sequence(sequence);
                    row = rejected;
                }
                WarpTableInsertWithIdOutcome::Full { .. } => invariant_violation(
                    WarpTableInconsistency::CapacityReachedDuringGeneratedInsert,
                ),
            }
        }
        invariant_violation(WarpTableInconsistency::IdentifierSequenceBlocked { attempts })
    }

    /// Inserts every row through [`Self::insert`] under generated identifiers.
    ///
    /// `observe` receives each outcome by value, including every generated ID
    /// and rejected row. The operation allocates no result collection of its own.
    pub fn insert_all(
        &mut self,
        rows: impl IntoIterator<Item = Row>,
        mut observe: impl FnMut(WarpTableInsertOutcome<WarpId<Row>, Row>),
    ) -> WarpTableInsertAllOutcome {
        for row in rows {
            observe(self.insert(row));
        }
        WarpTableInsertAllOutcome::Completed
    }
}

#[inline(always)]
fn following_sequence(sequence: NonZeroU64) -> Option<NonZeroU64> {
    sequence.get().checked_add(1).and_then(NonZeroU64::new)
}