commonware_storage/qmdb/keyless/operation/
mod.rs1use crate::{
2 merkle::{Family, Location},
3 qmdb::{any::value::ValueEncoding, operation::Committable},
4};
5use commonware_codec::{Encode as _, Error as CodecError, Read, Write};
6use commonware_formatting::hex;
7use commonware_runtime::{Buf, BufMut};
8use core::fmt::Display;
9
10pub(crate) mod fixed;
11pub(crate) mod variable;
12
13const COMMIT_CONTEXT: u8 = 0;
15const APPEND_CONTEXT: u8 = 1;
16
17pub trait Codec: ValueEncoding + Sized {
24 type ReadCfg: Clone + Send + Sync + 'static;
25
26 fn write_operation<F: Family>(op: &Operation<F, Self>, buf: &mut impl BufMut);
27 fn read_operation<F: Family>(
28 buf: &mut impl Buf,
29 cfg: &Self::ReadCfg,
30 ) -> Result<Operation<F, Self>, CodecError>;
31}
32
33#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
35pub enum Operation<F: Family, V: ValueEncoding> {
36 Append(V::Value),
38
39 Commit(Option<V::Value>, Location<F>),
42}
43
44impl<F: Family, V: ValueEncoding> Operation<F, V> {
45 pub fn into_value(self) -> Option<V::Value> {
47 match self {
48 Self::Append(value) => Some(value),
49 Self::Commit(value, _) => value,
50 }
51 }
52
53 pub const fn has_floor(&self) -> Option<Location<F>> {
55 match self {
56 Self::Commit(_, loc) => Some(*loc),
57 Self::Append(_) => None,
58 }
59 }
60}
61
62impl<F: Family, V: Codec> Write for Operation<F, V> {
63 fn write(&self, buf: &mut impl BufMut) {
64 V::write_operation(self, buf)
65 }
66}
67
68impl<F: Family, V: Codec> Committable for Operation<F, V> {
69 fn is_commit(&self) -> bool {
70 matches!(self, Self::Commit(_, _))
71 }
72}
73
74impl<F: Family, V: Codec> Read for Operation<F, V> {
75 type Cfg = <V as Codec>::ReadCfg;
76
77 fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, CodecError> {
78 V::read_operation(buf, cfg)
79 }
80}
81
82impl<F: Family, V: ValueEncoding> Display for Operation<F, V> {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 match self {
85 Self::Append(value) => write!(f, "[append value:{}]", hex(&value.encode())),
86 Self::Commit(value, floor) => {
87 if let Some(value) = value {
88 write!(f, "[commit {} floor:{}]", hex(&value.encode()), **floor)
89 } else {
90 write!(f, "[commit floor:{}]", **floor)
91 }
92 }
93 }
94 }
95}
96
97#[cfg(feature = "arbitrary")]
98impl<F: Family, V: ValueEncoding> arbitrary::Arbitrary<'_> for Operation<F, V>
99where
100 V::Value: for<'a> arbitrary::Arbitrary<'a>,
101{
102 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
103 let choice = u.int_in_range(0..=1)?;
104 match choice {
105 0 => Ok(Self::Append(V::Value::arbitrary(u)?)),
106 1 => {
107 let metadata = Option::<V::Value>::arbitrary(u)?;
108 let floor = Location::<F>::arbitrary(u)?;
109 Ok(Self::Commit(metadata, floor))
110 }
111 _ => unreachable!(),
112 }
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use crate::{merkle::mmr, qmdb::any::value::VariableEncoding};
120 use commonware_codec::Encode;
121 use commonware_formatting::hex;
122 use commonware_utils::sequence::U64;
123
124 #[test]
125 fn display_append() {
126 let op = Operation::<mmr::Family, VariableEncoding<U64>>::Append(U64::new(12345));
127 assert_eq!(
128 format!("{op}"),
129 format!("[append value:{}]", hex(&U64::new(12345).encode()))
130 );
131 }
132
133 #[test]
134 fn display_commit_some() {
135 let op = Operation::<mmr::Family, VariableEncoding<U64>>::Commit(
136 Some(U64::new(42)),
137 Location::new(7),
138 );
139 assert_eq!(
140 format!("{op}"),
141 format!("[commit {} floor:7]", hex(&U64::new(42).encode()))
142 );
143 }
144
145 #[test]
146 fn display_commit_none() {
147 let op = Operation::<mmr::Family, VariableEncoding<U64>>::Commit(None, Location::new(3));
148 assert_eq!(format!("{op}"), "[commit floor:3]");
149 }
150
151 #[cfg(feature = "arbitrary")]
152 mod conformance {
153 use super::Operation;
154 use crate::{
155 merkle::mmr,
156 qmdb::any::value::{FixedEncoding, VariableEncoding},
157 };
158 use commonware_codec::conformance::CodecConformance;
159 use commonware_utils::sequence::U64;
160
161 commonware_conformance::conformance_tests! {
162 CodecConformance<Operation<mmr::Family, VariableEncoding<U64>>>,
163 CodecConformance<Operation<mmr::Family, FixedEncoding<U64>>>
164 }
165 }
166}