use super::dense_key_index::{CommitOutcome, PrepareInsertOutcome, PreparedVacancy};
use super::get::{row_ref, stored_id, validate_id_count};
use super::inconsistency::invariant_violation;
use super::{WarpTable, WarpTableInconsistency, WarpTableRow};
#[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> {
validate_id_count(self.ids.len(), 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 = stored_id(&self.ids, dense_row);
let row = row_ref::<Row>(stored_id, &self.columns, dense_row);
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 }
}
}