commonware_storage/adb/operation/fixed/
unordered.rs1use crate::{
2 adb::operation::{self, fixed::FixedOperation},
3 mmr::Location,
4};
5use bytes::{Buf, BufMut};
6use commonware_codec::{
7 util::at_least, CodecFixed, Error as CodecError, FixedSize, Read, ReadExt as _, Write,
8};
9use commonware_utils::{hex, Array};
10use core::fmt::Display;
11
12#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
14pub enum Operation<K: Array, V: CodecFixed> {
15 Delete(K),
17
18 Update(K, V),
20
21 CommitFloor(Location),
24}
25
26impl<K: Array, V: CodecFixed> Operation<K, V> {
27 const _MIN_OPERATION_LEN: usize = 9;
30
31 #[inline(always)]
33 const fn assert_valid_size() {
34 assert!(
35 Self::SIZE >= Self::_MIN_OPERATION_LEN,
36 "array size too small for commit op"
37 );
38 }
39}
40
41impl<K: Array, V: CodecFixed> FixedSize for Operation<K, V> {
42 const SIZE: usize = u8::SIZE + K::SIZE + V::SIZE;
43}
44
45impl<K: Array, V: CodecFixed<Cfg = ()>> FixedOperation for Operation<K, V> {
46 type Key = K;
47 type Value = V;
48
49 fn commit_floor(&self) -> Option<Location> {
50 match self {
51 Self::CommitFloor(loc) => Some(*loc),
52 _ => None,
53 }
54 }
55
56 fn key(&self) -> Option<&Self::Key> {
57 const {
59 Self::assert_valid_size();
60 }
61
62 match self {
63 Self::Delete(key) => Some(key),
64 Self::Update(key, _) => Some(key),
65 Self::CommitFloor(_) => None,
66 }
67 }
68
69 fn value(&self) -> Option<&Self::Value> {
70 const {
72 Self::assert_valid_size();
73 }
74
75 match self {
76 Self::Delete(_) => None,
77 Self::Update(_, value) => Some(value),
78 Self::CommitFloor(_) => None,
79 }
80 }
81
82 fn into_value(self) -> Option<Self::Value> {
83 const {
85 Self::assert_valid_size();
86 }
87
88 match self {
89 Self::Delete(_) => None,
90 Self::Update(_, value) => Some(value),
91 Self::CommitFloor(_) => None,
92 }
93 }
94}
95
96impl<K: Array, V: CodecFixed> Write for Operation<K, V> {
97 fn write(&self, buf: &mut impl BufMut) {
98 match &self {
99 Self::Delete(k) => {
100 operation::DELETE_CONTEXT.write(buf);
101 k.write(buf);
102 buf.put_bytes(0, V::SIZE);
104 }
105 Self::Update(k, v) => {
106 operation::UPDATE_CONTEXT.write(buf);
107 k.write(buf);
108 v.write(buf);
109 }
110 Self::CommitFloor(floor_loc) => {
111 operation::COMMIT_FLOOR_CONTEXT.write(buf);
112 buf.put_slice(&floor_loc.to_be_bytes());
113 buf.put_bytes(0, Self::SIZE - 1 - u64::SIZE);
115 }
116 }
117 }
118}
119
120impl<K: Array, V: CodecFixed> Read for Operation<K, V> {
121 type Cfg = <V as Read>::Cfg;
122
123 fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, CodecError> {
124 at_least(buf, Self::SIZE)?;
125
126 match u8::read(buf)? {
127 operation::UPDATE_CONTEXT => {
128 let key = K::read(buf)?;
129 let value = V::read_cfg(buf, cfg)?;
130 Ok(Self::Update(key, value))
131 }
132 operation::DELETE_CONTEXT => {
133 let key = K::read(buf)?;
134 for _ in 0..V::SIZE {
136 if u8::read(buf)? != 0 {
137 return Err(CodecError::Invalid(
138 "storage::adb::operation::fixed::unordered::Operation",
139 "delete value non-zero",
140 ));
141 }
142 }
143 Ok(Self::Delete(key))
144 }
145 operation::COMMIT_FLOOR_CONTEXT => {
146 let floor_loc = u64::read(buf)?;
147 for _ in 0..(Self::SIZE - 1 - u64::SIZE) {
148 if u8::read(buf)? != 0 {
149 return Err(CodecError::Invalid(
150 "storage::adb::operation::fixed::unordered::Operation",
151 "commit value non-zero",
152 ));
153 }
154 }
155 let floor_loc = Location::new(floor_loc).ok_or_else(|| {
156 CodecError::Invalid(
157 "storage::adb::operation::fixed::unordered::Operation",
158 "commit floor location overflow",
159 )
160 })?;
161 Ok(Self::CommitFloor(floor_loc))
162 }
163 e => Err(CodecError::InvalidEnum(e)),
164 }
165 }
166}
167
168impl<K: Array, V: CodecFixed> Display for Operation<K, V> {
169 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170 match self {
171 Self::Delete(key) => write!(f, "[key:{key} <deleted>]"),
172 Self::Update(key, value) => write!(f, "[key:{key} value:{}]", hex(&value.encode())),
173 Self::CommitFloor(loc) => write!(f, "[commit with inactivity floor: {loc}]"),
174 }
175 }
176}