use novasmt::{ContentAddrStore, FullProof};
use serde::{de::DeserializeOwned, Serialize};
use std::fmt::Debug;
use std::marker::PhantomData;
use tmelcrypt::HashVal;
use crate::stats::{STAT_SMT_GET_SECS, STAT_SMT_INSERT_SECS};
pub struct SmtMapping<C: ContentAddrStore, K: Serialize, V: Serialize + DeserializeOwned> {
pub mapping: novasmt::Tree<C>,
_phantom_k: PhantomData<K>,
_phantom_v: PhantomData<V>,
}
impl<C: ContentAddrStore, K: Serialize, V: Serialize + DeserializeOwned> Debug
for SmtMapping<C, K, V>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.mapping.root_hash().fmt(f)
}
}
impl<C: ContentAddrStore, K: Serialize, V: Serialize + DeserializeOwned> Clone
for SmtMapping<C, K, V>
{
fn clone(&self) -> Self {
SmtMapping::new(self.mapping.clone())
}
}
impl<C: ContentAddrStore, K: Serialize, V: Serialize + DeserializeOwned> SmtMapping<C, K, V> {
pub fn clear(&mut self) {
self.mapping.clear()
}
pub fn is_empty(&self) -> bool {
self.root_hash().0 == [0; 32]
}
pub fn new(tree: novasmt::Tree<C>) -> Self {
SmtMapping {
mapping: tree,
_phantom_k: PhantomData,
_phantom_v: PhantomData,
}
}
pub fn get(&self, key: &K) -> (Option<V>, FullProof) {
let _timer = STAT_SMT_GET_SECS.timer_secs("smt get");
let key = tmelcrypt::hash_single(&stdcode::serialize(key).unwrap());
let (v_bytes, proof) = self.mapping.get_with_proof(key.0);
match v_bytes.len() {
0 => (None, proof),
_ => {
let res: V = stdcode::deserialize(&v_bytes).expect("SmtMapping saw invalid data");
(Some(res), proof)
}
}
}
pub fn insert(&mut self, key: K, val: V) {
let _timer = STAT_SMT_INSERT_SECS.timer_secs("smt insert");
let key = tmelcrypt::hash_single(&stdcode::serialize(&key).unwrap());
self.mapping
.insert(key.0, &stdcode::serialize(&val).unwrap());
}
pub fn delete(&mut self, key: &K) {
let _timer = STAT_SMT_INSERT_SECS.timer_secs("smt delete");
let key = tmelcrypt::hash_single(&stdcode::serialize(key).unwrap());
self.mapping.insert(key.0, Default::default());
}
pub fn root_hash(&self) -> HashVal {
HashVal(self.mapping.root_hash())
}
pub fn val_iter(&'_ self) -> impl Iterator<Item = V> + '_ {
self.mapping
.iter()
.map(|(_, v)| stdcode::deserialize::<V>(&v).unwrap())
}
}