commonware_storage/qmdb/any/operation/
fixed.rs1use crate::{
2 merkle::Family,
3 qmdb::{
4 any::{
5 FixedValue,
6 operation::{
7 COMMIT_CONTEXT, DELETE_CONTEXT, Operation, OperationCodec, UPDATE_CONTEXT, Update,
8 update,
9 },
10 value::FixedEncoding,
11 },
12 operation::{commit_fixed_operation_size, read_commit_fixed, write_commit_fixed},
13 },
14};
15use commonware_codec::{
16 Codec, CodecFixed, Error as CodecError, FixedSize, ReadExt as _, Write,
17 util::{at_least, ensure_zeros},
18};
19use commonware_runtime::{Buf, BufMut};
20use commonware_utils::Array;
21
22const fn const_max(a: usize, b: usize) -> usize {
24 if a > b { a } else { b }
25}
26
27const fn update_op_size<S: FixedSize>() -> usize {
28 1 + S::SIZE
29}
30
31const fn delete_op_size<K: Array>() -> usize {
32 1 + K::SIZE
33}
34
35const fn total_op_size<K: Array, V: FixedSize, S: FixedSize>() -> usize {
36 const_max(
37 update_op_size::<S>(),
38 const_max(commit_fixed_operation_size::<V>(), delete_op_size::<K>()),
39 )
40}
41
42impl<F, V, S> OperationCodec<F, S> for FixedEncoding<V>
43where
44 F: Family,
45 S::Key: Array + Codec,
46 V: FixedValue,
47 S: Update<Value = V, ValueEncoding = Self> + CodecFixed<Cfg = ()>,
48{
49 type ReadCfg = ();
50
51 fn write_operation(op: &Operation<F, S>, buf: &mut impl BufMut) {
52 let total = total_op_size::<S::Key, V, S>();
53 match op {
54 Operation::Delete(k) => {
55 DELETE_CONTEXT.write(buf);
56 k.write(buf);
57 buf.put_bytes(0, total - delete_op_size::<S::Key>());
58 }
59 Operation::Update(p) => {
60 UPDATE_CONTEXT.write(buf);
61 p.write(buf);
62 buf.put_bytes(0, total - update_op_size::<S>());
63 }
64 Operation::CommitFloor(metadata, floor_loc) => {
65 COMMIT_CONTEXT.write(buf);
66 write_commit_fixed(metadata, *floor_loc, buf);
67 buf.put_bytes(0, total - commit_fixed_operation_size::<V>());
68 }
69 }
70 }
71
72 fn read_operation(
73 buf: &mut impl Buf,
74 cfg: &Self::ReadCfg,
75 ) -> Result<Operation<F, S>, CodecError> {
76 let total = total_op_size::<S::Key, V, S>();
77 at_least(buf, total)?;
78
79 match u8::read(buf)? {
80 DELETE_CONTEXT => {
81 let key = S::Key::read(buf)?;
82 ensure_zeros(buf, total - delete_op_size::<S::Key>())?;
83 Ok(Operation::Delete(key))
84 }
85 UPDATE_CONTEXT => {
86 let payload = S::read_cfg(buf, cfg)?;
87 ensure_zeros(buf, total - update_op_size::<S>())?;
88 Ok(Operation::Update(payload))
89 }
90 COMMIT_CONTEXT => {
91 let (metadata, floor_loc) = read_commit_fixed(buf)?;
92 ensure_zeros(buf, total - commit_fixed_operation_size::<V>())?;
93 Ok(Operation::CommitFloor(metadata, floor_loc))
94 }
95 e => Err(CodecError::InvalidEnum(e)),
96 }
97 }
98}
99
100impl<F, K, V> FixedSize for Operation<F, update::Ordered<K, FixedEncoding<V>>>
102where
103 F: Family,
104 K: Array,
105 V: FixedValue,
106 update::Ordered<K, FixedEncoding<V>>: FixedSize,
107{
108 const SIZE: usize = total_op_size::<K, V, update::Ordered<K, FixedEncoding<V>>>();
109}
110
111impl<F, K, V> FixedSize for Operation<F, update::Unordered<K, FixedEncoding<V>>>
113where
114 F: Family,
115 K: Array,
116 V: FixedValue,
117 update::Unordered<K, FixedEncoding<V>>: FixedSize,
118{
119 const SIZE: usize = total_op_size::<K, V, update::Unordered<K, FixedEncoding<V>>>();
120}