pipecircuit 0.0.18

Correct. Robust. Fast. Portable. Pick four.
Documentation
use super::dense_key_index::{CommitOutcome, PrepareInsertOutcome, PreparedVacancy};
use super::inconsistency::invariant_violation;
use super::{WarpTable, WarpTableInconsistency, WarpTableRow, WarpTableRowGetOutcome};

#[must_use]
pub enum WarpTableEntry<'table, Row: WarpTableRow + 'table, Brand: 'table> {
    Present {
        id: Row::Id,
        dense_row: usize,
        row: Row::Ref<'table>,
    },
    Vacant {
        vacancy: WarpTableVacantEntry<'table, Row, Brand>,
    },
}

pub struct WarpTableVacantEntry<'table, Row: WarpTableRow, Brand> {
    table: &'table mut WarpTable<Row, Brand>,
    id: Row::Id,
    prepared_vacancy: PreparedVacancy,
}

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

impl<Row: WarpTableRow, Brand> WarpTable<Row, Brand> {
    pub fn entry(&mut self, id: Row::Id) -> WarpTableEntry<'_, Row, Brand> {
        if self.ids.len() != self.len {
            invariant_violation(WarpTableInconsistency::IdColumnLengthMismatch {
                ids: self.ids.len(),
                rows: self.len,
            });
        }
        match self.primary_index.prepare_insert(id, &self.ids) {
            Ok(PrepareInsertOutcome::Vacant(prepared_vacancy)) => WarpTableEntry::Vacant {
                vacancy: WarpTableVacantEntry {
                    table: self,
                    id,
                    prepared_vacancy,
                },
            },
            Ok(PrepareInsertOutcome::Present { row: dense_row }) => {
                let stored_id = self.ids.get(dense_row).unwrap_or_else(|| {
                    invariant_violation(WarpTableInconsistency::IdUnavailable { row: dense_row })
                });
                let WarpTableRowGetOutcome::Present { row } =
                    Row::get(stored_id, &self.columns, dense_row).unwrap_or_else(|reason| {
                        invariant_violation(WarpTableInconsistency::from(reason))
                    });
                WarpTableEntry::Present {
                    id: *stored_id,
                    dense_row,
                    row,
                }
            }
            Err(reason) => invariant_violation(WarpTableInconsistency::from(reason)),
        }
    }
}

impl<Row: WarpTableRow, Brand> WarpTableVacantEntry<'_, Row, Brand> {
    pub const fn id(&self) -> Row::Id {
        self.id
    }

    pub fn insert(self, row: Row) -> WarpTableVacantInsertOutcome<Row::Id, Row> {
        let Self {
            table,
            id,
            prepared_vacancy,
        } = self;
        if table.len >= table.maximum_rows {
            return WarpTableVacantInsertOutcome::Full { id, rejected: row };
        }
        if let Some(conflict) = Row::unique_insert_conflict(&table.indexes, &row) {
            return WarpTableVacantInsertOutcome::UniqueConflict {
                id,
                conflict,
                rejected: row,
            };
        }
        let dense_row = table.len;
        let primary_insert = table
            .primary_index
            .prepare_commit(prepared_vacancy, dense_row)
            .unwrap_or_else(|reason| invariant_violation(WarpTableInconsistency::from(reason)));
        let indexes_insert = Row::try_prepare_indexes_insert(&mut table.indexes, &row)
            .unwrap_or_else(|reason| invariant_violation(reason));
        let CommitOutcome::Committed { row: dense_row } =
            table.primary_index.commit_prepared(primary_insert);
        table.ids.push(id);
        Row::commit_indexes_insert(indexes_insert);
        Row::append(&mut table.columns, row);
        table.len = table.len.saturating_add(1);
        WarpTableVacantInsertOutcome::Inserted { id, row: dense_row }
    }
}