use super::dense_key_index::{PrepareRemoveOutcome, RowRelocation};
use super::get::stored_id;
use super::inconsistency::invariant_violation;
use super::{WarpTable, WarpTableInconsistency, WarpTableRow, WarpTableRowGetOutcome};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub enum WarpTableRowRelocation<Id> {
Stable,
Relocated { id: Id, from: usize, to: usize },
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub enum WarpTableRemoveOutcome<Id, Row> {
Removed {
id: Id,
removed: Row,
relocation: WarpTableRowRelocation<Id>,
},
Absent {
id: Id,
},
}
pub(super) fn require_removal<Id, Row, Error>(
outcome: WarpTableRemoveOutcome<Id, Row>,
absent: Error,
) -> Result<(Id, Row, WarpTableRowRelocation<Id>), Error> {
match outcome {
WarpTableRemoveOutcome::Removed {
id,
removed,
relocation,
} => Ok((id, removed, relocation)),
WarpTableRemoveOutcome::Absent { .. } => Err(absent),
}
}
impl<Row: WarpTableRow, Brand> WarpTable<Row, Brand> {
pub fn remove(&mut self, id: Row::Id) -> WarpTableRemoveOutcome<Row::Id, Row> {
let ids = &self.ids;
if ids.len() != self.len {
invariant_violation(WarpTableInconsistency::IdColumnLengthMismatch {
ids: ids.len(),
rows: self.len,
});
}
let Some((last_row, last_id)) = ids.iter().enumerate().next_back() else {
return WarpTableRemoveOutcome::Absent { id };
};
let prepared = self
.primary_index
.prepare_remove(id, ids, last_row)
.unwrap_or_else(|reason| invariant_violation(WarpTableInconsistency::from(reason)));
let removal = match prepared {
PrepareRemoveOutcome::Prepared(removal) => removal,
PrepareRemoveOutcome::Absent => return WarpTableRemoveOutcome::Absent { id },
};
let WarpTableRowGetOutcome::Present { .. } = Row::get(last_id, &self.columns, last_row)
.unwrap_or_else(|reason| invariant_violation(WarpTableInconsistency::from(reason)));
let row = removal.row;
let indexed_id = stored_id(ids, row);
let WarpTableRowGetOutcome::Present {
row: warp_table_row,
} = Row::get(indexed_id, &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: id, from, to, ..
} => WarpTableRowRelocation::Relocated { id, from, to },
};
self.primary_index.commit_remove(removal, ids);
self.ids.swap_remove(row);
Row::commit_indexes_remove(indexes_remove);
let removed = Row::swap_remove(&mut self.columns, row);
self.len = last_row;
WarpTableRemoveOutcome::Removed {
id,
removed,
relocation,
}
}
}