pipecircuit 0.0.2

Correct. Robust. Fast. Portable.
Documentation
use super::dense_key_index::{PrepareRemoveOutcome, RowRelocation};
use super::inconsistency::invariant_violation;
use super::{WarpTable, WarpTableInconsistency, WarpTableRow, WarpTableRowGetOutcome};

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub enum WarpTableRowRelocation<Key> {
    Stable,
    Relocated { key: Key, from: usize, to: usize },
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub enum WarpTableRemoveOutcome<Key, Row> {
    Removed {
        key: Key,
        removed: Row,
        relocation: WarpTableRowRelocation<Key>,
    },
    Absent {
        key: Key,
    },
}

impl<Row: WarpTableRow, Brand> WarpTable<Row, Brand> {
    pub fn remove(&mut self, key: Row::Key) -> WarpTableRemoveOutcome<Row::Key, Row> {
        let keys = &self.primary_keys;
        if keys.len() != self.len {
            invariant_violation(WarpTableInconsistency::PrimaryKeyColumnLengthMismatch {
                keys: keys.len(),
                rows: self.len,
            });
        }
        let Some(last_row) = self.len.checked_sub(1) else {
            return WarpTableRemoveOutcome::Absent { key };
        };
        let prepared = self
            .primary_index
            .prepare_remove(key, keys, last_row)
            .unwrap_or_else(|reason| invariant_violation(WarpTableInconsistency::from(reason)));
        let removal = match prepared {
            PrepareRemoveOutcome::Prepared(removal) => removal,
            PrepareRemoveOutcome::Absent => return WarpTableRemoveOutcome::Absent { key },
        };
        let last_key = keys.get(last_row).unwrap_or_else(|| {
            invariant_violation(WarpTableInconsistency::PrimaryKeyUnavailable { row: last_row })
        });
        let WarpTableRowGetOutcome::Present { .. } = Row::get(last_key, &self.columns, last_row)
            .unwrap_or_else(|reason| invariant_violation(WarpTableInconsistency::from(reason)));
        let row = removal.row;
        let indexed_key = keys.get(row).unwrap_or_else(|| {
            invariant_violation(WarpTableInconsistency::PrimaryKeyUnavailable { row })
        });
        let WarpTableRowGetOutcome::Present {
            row: warp_table_row,
        } = Row::get(indexed_key, &self.columns, row)
            .unwrap_or_else(|reason| invariant_violation(WarpTableInconsistency::from(reason)));
        let indexes_remove =
            Row::try_prepare_indexes_remove(&mut self.indexes, warp_table_row, row)
                .unwrap_or_else(|reason| invariant_violation(reason));
        let relocation = match removal.relocation {
            RowRelocation::Stable => WarpTableRowRelocation::Stable,
            RowRelocation::Relocated { key, from, to, .. } => {
                WarpTableRowRelocation::Relocated { key, from, to }
            }
        };
        self.primary_index.commit_remove(removal, keys);
        self.primary_keys.swap_remove(row);
        Row::commit_indexes_remove(indexes_remove);
        let removed = Row::swap_remove(&mut self.columns, row);
        self.len = last_row;
        WarpTableRemoveOutcome::Removed {
            key,
            removed,
            relocation,
        }
    }
}