use crate::model::Hash;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub enum TrieNode {
Branch {
prefix: Vec<u8>,
children: BTreeMap<u8, Hash>,
value: Option<Hash>,
},
Leaf {
key_suffix: Vec<u8>,
value: Hash,
},
#[default]
Empty,
}
impl TrieNode {
pub fn empty() -> Self {
TrieNode::Empty
}
pub fn leaf(key_suffix: Vec<u8>, value: Hash) -> Self {
TrieNode::Leaf { key_suffix, value }
}
pub fn branch(prefix: Vec<u8>) -> Self {
TrieNode::Branch {
prefix,
children: BTreeMap::new(),
value: None,
}
}
pub fn hash(&self) -> Hash {
let data = bincode::serialize(self).expect("serialization should not fail");
Hash::digest(&data)
}
pub fn is_empty(&self) -> bool {
matches!(self, TrieNode::Empty)
}
pub fn value(&self) -> Option<Hash> {
match self {
TrieNode::Leaf { value, .. } => Some(*value),
TrieNode::Branch { value, .. } => *value,
TrieNode::Empty => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_node_hash_deterministic() {
let node = TrieNode::leaf(b"key".to_vec(), Hash::digest(b"value"));
let h1 = node.hash();
let h2 = node.hash();
assert_eq!(h1, h2);
}
#[test]
fn test_different_nodes_different_hashes() {
let n1 = TrieNode::leaf(b"key1".to_vec(), Hash::digest(b"value"));
let n2 = TrieNode::leaf(b"key2".to_vec(), Hash::digest(b"value"));
assert_ne!(n1.hash(), n2.hash());
}
}