use crate::merkle::{Family, Location};
use commonware_codec::{
CodecShared, EncodeSize, Error as CodecError, FixedSize, Read, ReadExt as _, Write,
util::ensure_zeros,
};
use commonware_runtime::{Buf, BufMut};
use core::{fmt::Debug, hash::Hash, ops::Deref};
pub trait Key:
CodecShared + Clone + 'static + Eq + Ord + Hash + AsRef<[u8]> + Deref<Target = [u8]> + Debug
{
}
impl<T> Key for T where
T: CodecShared + Clone + 'static + Eq + Ord + Hash + AsRef<[u8]> + Deref<Target = [u8]> + Debug
{
}
pub trait Floored<F: Family> {
fn has_floor(&self) -> Option<Location<F>>;
}
pub trait Operation<F: Family>: Floored<F> {
type Key: Key;
fn key(&self) -> Option<&Self::Key>;
fn into_key(self) -> Option<Self::Key>;
fn is_update(&self) -> bool;
fn is_delete(&self) -> bool;
}
pub trait Committable {
fn is_commit(&self) -> bool;
}
pub(crate) const fn commit_fixed_operation_size<V: FixedSize>() -> usize {
1 + 1 + V::SIZE + u64::SIZE
}
pub(crate) fn write_commit_fixed<F: Family, V: Write + FixedSize>(
metadata: &Option<V>,
floor: Location<F>,
buf: &mut impl BufMut,
) {
if let Some(value) = metadata {
true.write(buf);
value.write(buf);
} else {
buf.put_bytes(0, 1 + V::SIZE);
}
buf.put_slice(&floor.as_u64().to_be_bytes());
}
pub(crate) fn read_commit_fixed<F: Family, V: Read<Cfg = ()> + FixedSize>(
buf: &mut impl Buf,
) -> Result<(Option<V>, Location<F>), CodecError> {
let metadata = if bool::read(buf)? {
Some(V::read(buf)?)
} else {
ensure_zeros(buf, V::SIZE)?;
None
};
let floor = Location::new(u64::read(buf)?);
if !floor.is_valid() {
return Err(CodecError::Invalid(
"storage::qmdb::operation::commit",
"commit floor location overflow",
));
}
Ok((metadata, floor))
}
pub(crate) fn commit_variable_payload_size<F: Family, V: EncodeSize>(
metadata: &Option<V>,
floor: Location<F>,
) -> usize {
metadata.encode_size() + floor.encode_size()
}
pub(crate) fn write_commit_variable<F: Family, V: Write>(
metadata: &Option<V>,
floor: Location<F>,
buf: &mut impl BufMut,
) {
metadata.write(buf);
floor.write(buf);
}
pub(crate) fn read_commit_variable<F: Family, V: Read>(
buf: &mut impl Buf,
value_cfg: &V::Cfg,
) -> Result<(Option<V>, Location<F>), CodecError> {
let metadata = Option::<V>::read_cfg(buf, value_cfg)?;
let floor = Location::read(buf)?;
Ok((metadata, floor))
}