use crate::{ merkle::Family, qmdb::{ any::{ FixedValue, operation::{ COMMIT_CONTEXT, DELETE_CONTEXT, Operation, OperationCodec, UPDATE_CONTEXT, Update, update, }, value::FixedEncoding, }, operation::{commit_fixed_operation_size, read_commit_fixed, write_commit_fixed}, }, }; use commonware_codec::{ Codec, CodecFixed, Error as CodecError, FixedSize, ReadExt as _, Write, util::{at_least, ensure_zeros}, }; use commonware_runtime::{Buf, BufMut}; use commonware_utils::Array; /// `max(a, b)` in a const context. const fn const_max(a: usize, b: usize) -> usize { if a > b { a } else { b } } const fn update_op_size() -> usize { 1 + S::SIZE } const fn delete_op_size() -> usize { 1 + K::SIZE } const fn total_op_size() -> usize { const_max( update_op_size::(), const_max(commit_fixed_operation_size::(), delete_op_size::()), ) } impl OperationCodec for FixedEncoding where F: Family, S::Key: Array + Codec, V: FixedValue, S: Update + CodecFixed, { type ReadCfg = (); fn write_operation(op: &Operation, buf: &mut impl BufMut) { let total = total_op_size::(); match op { Operation::Delete(k) => { DELETE_CONTEXT.write(buf); k.write(buf); buf.put_bytes(0, total - delete_op_size::()); } Operation::Update(p) => { UPDATE_CONTEXT.write(buf); p.write(buf); buf.put_bytes(0, total - update_op_size::()); } Operation::CommitFloor(metadata, floor_loc) => { COMMIT_CONTEXT.write(buf); write_commit_fixed(metadata, *floor_loc, buf); buf.put_bytes(0, total - commit_fixed_operation_size::()); } } } fn read_operation( buf: &mut impl Buf, cfg: &Self::ReadCfg, ) -> Result, CodecError> { let total = total_op_size::(); at_least(buf, total)?; match u8::read(buf)? { DELETE_CONTEXT => { let key = S::Key::read(buf)?; ensure_zeros(buf, total - delete_op_size::())?; Ok(Operation::Delete(key)) } UPDATE_CONTEXT => { let payload = S::read_cfg(buf, cfg)?; ensure_zeros(buf, total - update_op_size::())?; Ok(Operation::Update(payload)) } COMMIT_CONTEXT => { let (metadata, floor_loc) = read_commit_fixed(buf)?; ensure_zeros(buf, total - commit_fixed_operation_size::())?; Ok(Operation::CommitFloor(metadata, floor_loc)) } e => Err(CodecError::InvalidEnum(e)), } } } // FixedSize for ordered fixed operations. impl FixedSize for Operation>> where F: Family, K: Array, V: FixedValue, update::Ordered>: FixedSize, { const SIZE: usize = total_op_size::>>(); } // FixedSize for unordered fixed operations. impl FixedSize for Operation>> where F: Family, K: Array, V: FixedValue, update::Unordered>: FixedSize, { const SIZE: usize = total_op_size::>>(); }