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 })
}
}
}
}