use crate::qmdb::{any::value::ValueEncoding, operation::Key};
use commonware_codec::CodecShared;
use std::fmt;
mod sealed {
pub trait Sealed {}
}
mod ordered;
pub use ordered::Update as Ordered;
mod unordered;
pub use unordered::Update as Unordered;
pub trait Update: sealed::Sealed + Clone + Send + Sync + 'static {
type Key: Key;
type Value: CodecShared + Clone;
type ValueEncoding: ValueEncoding<Value = Self::Value>;
type Cached: Send + Sync;
fn key(&self) -> &Self::Key;
fn into_key(self) -> Self::Key;
fn value(&self) -> &Self::Value;
fn into_value(self) -> Self::Value;
fn cached<'a>(update: impl FnOnce() -> &'a Self) -> Self::Cached
where
Self: 'a;
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
}
pub(crate) trait Parts: Update {
const SIBLINGS: bool;
fn into_parts(self) -> (Self::Key, Self::Value, Self::Cached);
fn from_parts(key: Self::Key, value: Self::Value, cached: Self::Cached) -> Self;
}
#[cfg(test)]
mod tests {
use super::ordered::Update as OrderedUpdate;
use crate::qmdb::any::{
unordered::Update as UnorderedUpdate,
value::{FixedEncoding, VariableEncoding},
};
use commonware_codec::{Codec, RangeCfg, Read};
use commonware_utils::sequence::FixedBytes;
use std::fmt;
fn roundtrip<T>(value: &T, cfg: &<T as Read>::Cfg)
where
T: Codec + PartialEq + fmt::Debug,
{
let encoded = value.encode();
let decoded = T::decode_cfg(encoded.clone(), cfg).expect("decode");
assert_eq!(decoded, *value);
let encoded2 = decoded.encode();
assert_eq!(encoded, encoded2);
}
#[test]
fn ordered_update_fixed_roundtrip() {
type K = FixedBytes<4>;
type V = u64;
let upd = OrderedUpdate::<K, FixedEncoding<V>> {
key: FixedBytes::from([1, 2, 3, 4]),
value: 0xdead_beef_u64,
next_key: FixedBytes::from([4, 3, 2, 1]),
};
roundtrip(&upd, &());
}
#[test]
fn ordered_update_variable_roundtrip() {
type K = FixedBytes<4>;
type V = Vec<u8>;
let upd = OrderedUpdate::<K, VariableEncoding<V>> {
key: FixedBytes::from([1, 2, 3, 4]),
value: vec![1, 2, 3, 4, 5],
next_key: FixedBytes::from([4, 3, 2, 1]),
};
roundtrip(&upd, &((), (RangeCfg::from(..), ())));
}
#[test]
fn unordered_update_fixed_roundtrip() {
type K = FixedBytes<4>;
type V = u64;
let upd = UnorderedUpdate::<K, FixedEncoding<V>>(FixedBytes::from([7, 7, 7, 7]), 42u64);
roundtrip(&upd, &());
}
#[test]
fn unordered_update_variable_roundtrip() {
type K = FixedBytes<4>;
type V = Vec<u8>;
let upd = UnorderedUpdate::<K, VariableEncoding<V>>(
FixedBytes::from([0, 1, 2, 3]),
vec![10, 11, 12, 13],
);
roundtrip(&upd, &((), (RangeCfg::from(..), ())));
}
#[cfg(feature = "arbitrary")]
mod conformance {
use super::*;
use commonware_codec::conformance::CodecConformance;
use commonware_utils::sequence::U64;
commonware_conformance::conformance_tests! {
CodecConformance<OrderedUpdate<U64, FixedEncoding<U64>>>,
CodecConformance<OrderedUpdate<U64, VariableEncoding<Vec<u8>>>>,
CodecConformance<UnorderedUpdate<U64, FixedEncoding<U64>>>,
CodecConformance<UnorderedUpdate<U64, VariableEncoding<Vec<u8>>>>,
}
}
}