use crate::{
db::data::structural_field::{
decode_list_field_items, decode_map_field_entries, decode_value_storage_list_item_slices,
decode_value_storage_map_entry_slices, encode_list_field_owned_items,
encode_map_field_owned_entries, encode_value_storage_owned_list_items,
encode_value_storage_owned_map_entries,
},
error::InternalError,
model::field::FieldKind,
};
use std::collections::BTreeMap;
fn resolve_collection_item_kind(
kind: FieldKind,
field_name: &'static str,
encode: bool,
) -> Result<FieldKind, InternalError> {
collection_item_kind(kind).ok_or_else(|| {
let message = format!("field kind {kind:?} does not accept collection payloads");
if encode {
InternalError::persisted_row_field_encode_failed(field_name, message)
} else {
InternalError::persisted_row_field_decode_failed(field_name, message)
}
})
}
fn resolve_map_entry_kinds(
kind: FieldKind,
field_name: &'static str,
encode: bool,
) -> Result<(FieldKind, FieldKind), InternalError> {
map_entry_kinds(kind).ok_or_else(|| {
let message = format!("field kind {kind:?} does not accept map payloads");
if encode {
InternalError::persisted_row_field_encode_failed(field_name, message)
} else {
InternalError::persisted_row_field_decode_failed(field_name, message)
}
})
}
pub(in crate::db::data::persisted_row::codec) fn encode_collection<'a, I, T>(
kind: FieldKind,
items: I,
field_name: &'static str,
mut encode_item: impl FnMut(FieldKind, &T, &'static str) -> Result<Vec<u8>, InternalError>,
) -> Result<Vec<u8>, InternalError>
where
I: IntoIterator<Item = &'a T>,
T: 'a,
{
let item_kind = resolve_collection_item_kind(kind, field_name, true)?;
let iter = items.into_iter();
let mut item_payloads = Vec::with_capacity(iter.size_hint().0);
for item in iter {
item_payloads.push(encode_item(item_kind, item, field_name)?);
}
encode_list_field_owned_items(item_payloads.as_slice(), kind, field_name)
}
pub(in crate::db::data::persisted_row::codec) fn encode_structured_collection<'a, I, T>(
items: I,
mut encode_item: impl FnMut(&T) -> Result<Vec<u8>, InternalError>,
) -> Result<Vec<u8>, InternalError>
where
I: IntoIterator<Item = &'a T>,
T: 'a,
{
let iter = items.into_iter();
let mut item_payloads = Vec::with_capacity(iter.size_hint().0);
for item in iter {
item_payloads.push(encode_item(item)?);
}
Ok(encode_value_storage_owned_list_items(
item_payloads.as_slice(),
))
}
pub(in crate::db::data::persisted_row::codec) fn decode_collection<T>(
kind: FieldKind,
bytes: &[u8],
field_name: &'static str,
mut decode_item: impl FnMut(
FieldKind,
&[u8],
&'static str,
&'static str,
) -> Result<T, InternalError>,
) -> Result<Vec<T>, InternalError> {
let item_kind = resolve_collection_item_kind(kind, field_name, false)?;
let item_bytes = decode_list_field_items(bytes, kind)
.map_err(|err| InternalError::persisted_row_field_decode_failed(field_name, err))?;
item_bytes
.iter()
.map(|item| decode_item(item_kind, item.as_slice(), field_name, "item"))
.collect()
}
pub(in crate::db::data::persisted_row::codec) fn decode_structured_collection<T>(
bytes: &[u8],
decode_item: impl FnMut(&[u8]) -> Result<T, InternalError>,
) -> Result<Vec<T>, InternalError> {
let item_bytes = decode_value_storage_list_item_slices(bytes)
.map_err(InternalError::persisted_row_decode_failed)?;
item_bytes.into_iter().map(decode_item).collect()
}
pub(in crate::db::data::persisted_row::codec) fn encode_map<K, V>(
kind: FieldKind,
entries: &BTreeMap<K, V>,
field_name: &'static str,
mut encode_key: impl FnMut(FieldKind, &K, &'static str) -> Result<Vec<u8>, InternalError>,
mut encode_value: impl FnMut(FieldKind, &V, &'static str) -> Result<Vec<u8>, InternalError>,
) -> Result<Vec<u8>, InternalError>
where
K: Ord,
{
let (key_kind, value_kind) = resolve_map_entry_kinds(kind, field_name, true)?;
let mut entry_payloads = Vec::with_capacity(entries.len());
for (entry_key, entry_value) in entries {
entry_payloads.push((
encode_key(key_kind, entry_key, field_name)?,
encode_value(value_kind, entry_value, field_name)?,
));
}
encode_map_field_owned_entries(entry_payloads.as_slice(), kind, field_name)
}
pub(in crate::db::data::persisted_row::codec) fn encode_structured_map<K, V>(
entries: &BTreeMap<K, V>,
mut encode_key: impl FnMut(&K) -> Result<Vec<u8>, InternalError>,
mut encode_value: impl FnMut(&V) -> Result<Vec<u8>, InternalError>,
) -> Result<Vec<u8>, InternalError>
where
K: Ord,
{
let mut entry_payloads = Vec::with_capacity(entries.len());
for (entry_key, entry_value) in entries {
entry_payloads.push((encode_key(entry_key)?, encode_value(entry_value)?));
}
Ok(encode_value_storage_owned_map_entries(
entry_payloads.as_slice(),
))
}
pub(in crate::db::data::persisted_row::codec) fn decode_map<K, V>(
kind: FieldKind,
bytes: &[u8],
field_name: &'static str,
decode_key: impl FnMut(FieldKind, &[u8], &'static str, &'static str) -> Result<K, InternalError>,
decode_value: impl FnMut(FieldKind, &[u8], &'static str, &'static str) -> Result<V, InternalError>,
) -> Result<BTreeMap<K, V>, InternalError>
where
K: Ord,
{
let (key_kind, value_kind) = resolve_map_entry_kinds(kind, field_name, false)?;
let entry_bytes = decode_map_field_entries(bytes, kind)
.map_err(|err| InternalError::persisted_row_field_decode_failed(field_name, err))?;
decode_map_entries(
entry_bytes
.iter()
.map(|(key_bytes, value_bytes)| (key_bytes.as_slice(), value_bytes.as_slice())),
key_kind,
value_kind,
field_name,
true,
|| by_kind_map_decode_failed::<K, V>(field_name),
decode_key,
decode_value,
)
}
pub(in crate::db::data::persisted_row::codec) fn decode_structured_map<K, V>(
bytes: &[u8],
mut decode_key: impl FnMut(&[u8]) -> Result<K, InternalError>,
mut decode_value: impl FnMut(&[u8]) -> Result<V, InternalError>,
) -> Result<BTreeMap<K, V>, InternalError>
where
K: Ord,
{
let entry_bytes = decode_value_storage_map_entry_slices(bytes)
.map_err(InternalError::persisted_row_decode_failed)?;
decode_entries(
entry_bytes,
true,
structured_map_decode_failed::<K, V>,
|key_bytes, value_bytes| Ok((decode_key(key_bytes)?, decode_value(value_bytes)?)),
)
}
#[expect(
clippy::too_many_arguments,
reason = "by-kind map traversal keeps key/value kind, field label, ordering, and decode callbacks explicit"
)]
fn decode_map_entries<'a, K, V>(
entries: impl IntoIterator<Item = (&'a [u8], &'a [u8])>,
key_kind: FieldKind,
value_kind: FieldKind,
field_name: &'static str,
enforce_order: bool,
violation_error: impl FnMut() -> InternalError,
mut decode_key: impl FnMut(FieldKind, &[u8], &'static str, &'static str) -> Result<K, InternalError>,
mut decode_value: impl FnMut(
FieldKind,
&[u8],
&'static str,
&'static str,
) -> Result<V, InternalError>,
) -> Result<BTreeMap<K, V>, InternalError>
where
K: 'a + Ord,
V: 'a,
{
decode_entries(
entries,
enforce_order,
violation_error,
|key_bytes, value_bytes| {
let key = decode_key(key_kind, key_bytes, field_name, "map key")?;
let value = decode_value(value_kind, value_bytes, field_name, "map value")?;
Ok((key, value))
},
)
}
fn decode_entries<'a, K, V>(
entries: impl IntoIterator<Item = (&'a [u8], &'a [u8])>,
enforce_order: bool,
mut violation_error: impl FnMut() -> InternalError,
mut decode_entry: impl FnMut(&'a [u8], &'a [u8]) -> Result<(K, V), InternalError>,
) -> Result<BTreeMap<K, V>, InternalError>
where
K: 'a + Ord,
V: 'a,
{
let mut out = BTreeMap::new();
for (key_bytes, value_bytes) in entries {
let (key, value) = decode_entry(key_bytes, value_bytes)?;
if enforce_order
&& let Some((previous_key, _)) = out.last_key_value()
&& key <= *previous_key
{
return Err(violation_error());
}
if out.insert(key, value).is_some() && enforce_order {
return Err(violation_error());
}
}
Ok(out)
}
fn by_kind_map_decode_failed<K, V>(field_name: &'static str) -> InternalError {
InternalError::persisted_row_field_decode_failed(
field_name,
format!(
"by-kind map payload contains duplicate or unordered keys for BTreeMap<{}, {}>",
std::any::type_name::<K>(),
std::any::type_name::<V>()
),
)
}
fn structured_map_decode_failed<K, V>() -> InternalError {
structured_container_decode_failed(&format!(
"BTreeMap<{}, {}>",
std::any::type_name::<K>(),
std::any::type_name::<V>()
))
}
pub(in crate::db::data::persisted_row::codec) fn structured_container_decode_failed(
type_name: &str,
) -> InternalError {
InternalError::persisted_row_decode_failed(format!("value payload does not match {type_name}"))
}
const fn collection_item_kind(kind: FieldKind) -> Option<FieldKind> {
let (FieldKind::List(inner) | FieldKind::Set(inner)) = kind else {
return None;
};
Some(*inner)
}
const fn map_entry_kinds(kind: FieldKind) -> Option<(FieldKind, FieldKind)> {
let FieldKind::Map { key, value } = kind else {
return None;
};
Some((*key, *value))
}