use crate::{
db::{
data::{DataKey, DataRow, PersistedRow, RawRow},
response::{EntityResponse, Row},
},
error::InternalError,
traits::{EntityKind, EntityValue},
types::Id,
};
use std::{fmt::Display, mem::ManuallyDrop};
#[derive(Debug)]
pub(in crate::db) struct PersistedEntityRow {
data_key: DataKey,
raw_row: RawRow,
}
impl PersistedEntityRow {
#[must_use]
pub(in crate::db) fn from_data_row(row: DataRow) -> Self {
let (data_key, raw_row) = row;
Self { data_key, raw_row }
}
#[must_use]
pub(in crate::db) fn into_parts(self) -> (DataKey, RawRow) {
(self.data_key, self.raw_row)
}
}
struct ErasedEntityResponseBuilder {
state: *mut (),
push_row: unsafe fn(*mut (), DataRow) -> Result<(), InternalError>,
drop_state: unsafe fn(*mut ()),
}
impl ErasedEntityResponseBuilder {
fn new<E>(capacity: usize) -> Self
where
E: PersistedRow + EntityValue,
{
let rows = Vec::<Row<E>>::with_capacity(capacity);
Self {
state: Box::into_raw(Box::new(rows)).cast(),
push_row: push_decoded_entity_row::<E>,
drop_state: drop_entity_response_state::<E>,
}
}
fn push_row(&mut self, row: DataRow) -> Result<(), InternalError> {
unsafe { (self.push_row)(self.state, row) }
}
fn finish<E>(self) -> EntityResponse<E>
where
E: PersistedRow + EntityValue,
{
let this = ManuallyDrop::new(self);
let rows = unsafe { *Box::from_raw(this.state.cast::<Vec<Row<E>>>()) };
EntityResponse::new(rows)
}
}
impl Drop for ErasedEntityResponseBuilder {
fn drop(&mut self) {
unsafe { (self.drop_state)(self.state) };
}
}
#[inline(never)]
pub(in crate::db) fn decode_raw_row_for_entity_key<E>(
data_key: &DataKey,
raw_row: &RawRow,
) -> Result<(E::Key, E), InternalError>
where
E: PersistedRow + EntityValue,
{
let expected_key = data_key.try_key::<E>()?;
let entity = decode_and_validate_entity_key::<E, _, _, _, _>(
expected_key,
|| RawRow::try_decode::<E>(raw_row),
|err| InternalError::serialize_corruption(decode_failure_message(data_key, err)),
|expected_key, actual_key| {
let expected = format_entity_key_for_mismatch::<E>(expected_key);
let found = format_entity_key_for_mismatch::<E>(actual_key);
InternalError::store_corruption(key_mismatch_message(expected, found))
},
)?;
Ok((expected_key, entity))
}
#[inline(never)]
pub(in crate::db) fn decode_and_validate_entity_key<
E,
DecodeFn,
DecodeErr,
DecodeErrMap,
MismatchErrMap,
>(
expected_key: E::Key,
decode_entity: DecodeFn,
map_decode_error: DecodeErrMap,
map_key_mismatch: MismatchErrMap,
) -> Result<E, InternalError>
where
E: PersistedRow + EntityValue,
DecodeFn: FnOnce() -> Result<E, DecodeErr>,
DecodeErrMap: FnOnce(DecodeErr) -> InternalError,
MismatchErrMap: FnOnce(E::Key, E::Key) -> InternalError,
{
let entity = decode_entity().map_err(map_decode_error)?;
ensure_entity_key_match::<E, _>(expected_key, entity.id().key(), map_key_mismatch)?;
Ok(entity)
}
#[inline(never)]
pub(in crate::db) fn decode_data_row_into_entity_row<E>(
row: DataRow,
) -> Result<Row<E>, InternalError>
where
E: PersistedRow + EntityValue,
{
let row = PersistedEntityRow::from_data_row(row);
let (data_key, raw_row) = row.into_parts();
let (expected_key, entity) = decode_raw_row_for_entity_key::<E>(&data_key, &raw_row)?;
Ok(Row::new(Id::from_key(expected_key), entity))
}
#[inline(never)]
pub(in crate::db) fn decode_data_rows_into_entity_response<E>(
rows: Vec<DataRow>,
) -> Result<EntityResponse<E>, InternalError>
where
E: PersistedRow + EntityValue,
{
let mut builder = ErasedEntityResponseBuilder::new::<E>(rows.len());
for row in rows {
builder.push_row(row)?;
}
Ok(builder.finish::<E>())
}
fn decode_failure_message(data_key: &DataKey, err: impl Display) -> String {
format!("failed to deserialize row: {data_key} ({err})")
}
fn key_mismatch_message(expected: impl Display, actual: impl Display) -> String {
format!("row key mismatch: expected {expected}, found {actual}")
}
pub(in crate::db) fn format_entity_key_for_mismatch<E>(key: E::Key) -> String
where
E: EntityKind,
E::Key: std::fmt::Debug,
{
DataKey::try_new::<E>(key).map_or_else(|_| format!("{key:?}"), |key| key.to_string())
}
fn ensure_entity_key_match<E, MismatchErrMap>(
expected_key: E::Key,
actual_key: E::Key,
map_key_mismatch: MismatchErrMap,
) -> Result<(), InternalError>
where
E: EntityKind,
MismatchErrMap: FnOnce(E::Key, E::Key) -> InternalError,
{
if expected_key != actual_key {
return Err(map_key_mismatch(expected_key, actual_key));
}
Ok(())
}
unsafe fn push_decoded_entity_row<E>(state: *mut (), row: DataRow) -> Result<(), InternalError>
where
E: PersistedRow + EntityValue,
{
let row = decode_data_row_into_entity_row::<E>(row)?;
let rows = unsafe { &mut *state.cast::<Vec<Row<E>>>() };
rows.push(row);
Ok(())
}
unsafe fn drop_entity_response_state<E>(state: *mut ())
where
E: PersistedRow + EntityValue,
{
drop(unsafe { Box::from_raw(state.cast::<Vec<Row<E>>>()) });
}