pipecircuit 0.0.17

Correct. Robust. Fast. Portable. Pick four.
Documentation
use super::dense_key_index::FindOutcome;
use super::inconsistency::invariant_violation;
use super::{
    WarpTable, WarpTableInconsistency, WarpTableRow, WarpTableRowGetOutcome,
    WarpTableRowReplaceError, WarpTableRowReplaceOutcome,
};

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub enum WarpTableReplaceOutcome<Id, Row: WarpTableRow> {
    Replaced {
        id: Id,
        row: usize,
        previous: Row,
    },
    Absent {
        id: Id,
        rejected: Row,
    },
    UniqueConflict {
        id: Id,
        conflict: Row::UniqueConflict,
        rejected: Row,
    },
}

impl<Row: WarpTableRow, Brand> WarpTable<Row, Brand> {
    pub fn replace(
        &mut self,
        id: Row::Id,
        replacement: Row,
    ) -> WarpTableReplaceOutcome<Row::Id, Row> {
        let found = {
            let ids = &self.ids;
            if ids.len() != self.len {
                invariant_violation(WarpTableInconsistency::IdColumnLengthMismatch {
                    ids: ids.len(),
                    rows: self.len,
                });
            }
            self.primary_index.find(id, ids)
        };
        let row = match found {
            Ok(FindOutcome::Present { row, .. }) => row,
            Ok(FindOutcome::Absent) => {
                return WarpTableReplaceOutcome::Absent {
                    id,
                    rejected: replacement,
                };
            }
            Err(reason) => invariant_violation(WarpTableInconsistency::from(reason)),
        };
        match self.replace_at(id, row, replacement) {
            Ok(previous) => WarpTableReplaceOutcome::Replaced { id, row, previous },
            Err((conflict, rejected)) => WarpTableReplaceOutcome::UniqueConflict {
                id,
                conflict,
                rejected,
            },
        }
    }

    pub(super) fn replace_at(
        &mut self,
        id: Row::Id,
        row: usize,
        replacement: Row,
    ) -> Result<Row, (Row::UniqueConflict, Row)> {
        let WarpTableRowGetOutcome::Present { row: current } = Row::get(&id, &self.columns, row)
            .unwrap_or_else(|reason| invariant_violation(WarpTableInconsistency::from(reason)));
        if let Some(conflict) = Row::unique_replace_conflict(&self.indexes, current, &replacement) {
            return Err((conflict, replacement));
        }
        let WarpTableRowGetOutcome::Present { row: current } = Row::get(&id, &self.columns, row)
            .unwrap_or_else(|reason| invariant_violation(WarpTableInconsistency::from(reason)));
        let indexes_replace =
            Row::try_prepare_indexes_replace(&mut self.indexes, current, &replacement, row)
                .unwrap_or_else(|reason| invariant_violation(reason));
        match Row::replace(&mut self.columns, row, replacement) {
            Ok(WarpTableRowReplaceOutcome::Replaced { previous }) => {
                Row::commit_indexes_replace(indexes_replace);
                Ok(previous)
            }
            Err(WarpTableRowReplaceError::ColumnUnavailable { column, row, .. }) => {
                invariant_violation(WarpTableInconsistency::ColumnUnavailable { column, row })
            }
        }
    }
}