use engine_shared::newtypes::{Blake2bHash, BLAKE2B_DIGEST_LENGTH};
use types::bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH};
#[cfg(test)]
pub mod gens;
#[cfg(test)]
mod tests;
pub const RADIX: usize = 256;
pub type Parents<K, V> = Vec<(u8, Trie<K, V>)>;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Pointer {
LeafPointer(Blake2bHash),
NodePointer(Blake2bHash),
}
impl Pointer {
pub fn hash(&self) -> &Blake2bHash {
match self {
Pointer::LeafPointer(hash) => hash,
Pointer::NodePointer(hash) => hash,
}
}
pub fn update(&self, hash: Blake2bHash) -> Self {
match self {
Pointer::LeafPointer(_) => Pointer::LeafPointer(hash),
Pointer::NodePointer(_) => Pointer::NodePointer(hash),
}
}
fn tag(&self) -> u8 {
match self {
Pointer::LeafPointer(_) => 0,
Pointer::NodePointer(_) => 1,
}
}
}
impl ToBytes for Pointer {
fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
let mut ret = bytesrepr::unchecked_allocate_buffer(self);
ret.push(self.tag());
let mut hash_bytes = self.hash().to_bytes()?;
ret.append(&mut hash_bytes);
Ok(ret)
}
fn serialized_length(&self) -> usize {
U8_SERIALIZED_LENGTH + BLAKE2B_DIGEST_LENGTH
}
}
impl FromBytes for Pointer {
fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
let (tag, rem) = u8::from_bytes(bytes)?;
match tag {
0 => {
let (hash, rem) = Blake2bHash::from_bytes(rem)?;
Ok((Pointer::LeafPointer(hash), rem))
}
1 => {
let (hash, rem) = Blake2bHash::from_bytes(rem)?;
Ok((Pointer::NodePointer(hash), rem))
}
_ => Err(bytesrepr::Error::Formatting),
}
}
}
#[derive(Copy, Clone)]
pub struct PointerBlock([Option<Pointer>; RADIX]);
impl PointerBlock {
pub fn new() -> Self {
Default::default()
}
pub fn from_indexed_pointers(indexed_pointers: &[(usize, Pointer)]) -> Self {
let mut ret = PointerBlock::new();
for (idx, ptr) in indexed_pointers.iter() {
ret[*idx] = Some(*ptr);
}
ret
}
}
impl From<[Option<Pointer>; RADIX]> for PointerBlock {
fn from(src: [Option<Pointer>; RADIX]) -> Self {
PointerBlock(src)
}
}
impl PartialEq for PointerBlock {
#[inline]
fn eq(&self, other: &PointerBlock) -> bool {
self.0[..] == other.0[..]
}
}
impl Eq for PointerBlock {}
impl Default for PointerBlock {
fn default() -> Self {
PointerBlock([Default::default(); RADIX])
}
}
impl ToBytes for PointerBlock {
fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
self.0.to_bytes()
}
fn serialized_length(&self) -> usize {
self.0.serialized_length()
}
}
impl FromBytes for PointerBlock {
fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
FromBytes::from_bytes(bytes).map(|(arr, rem)| (PointerBlock(arr), rem))
}
}
impl core::ops::Index<usize> for PointerBlock {
type Output = Option<Pointer>;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
let PointerBlock(dat) = self;
&dat[index]
}
}
impl core::ops::IndexMut<usize> for PointerBlock {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let PointerBlock(dat) = self;
&mut dat[index]
}
}
impl core::ops::Index<core::ops::Range<usize>> for PointerBlock {
type Output = [Option<Pointer>];
#[inline]
fn index(&self, index: core::ops::Range<usize>) -> &[Option<Pointer>] {
let &PointerBlock(ref dat) = self;
&dat[index]
}
}
impl core::ops::Index<core::ops::RangeTo<usize>> for PointerBlock {
type Output = [Option<Pointer>];
#[inline]
fn index(&self, index: core::ops::RangeTo<usize>) -> &[Option<Pointer>] {
let &PointerBlock(ref dat) = self;
&dat[index]
}
}
impl core::ops::Index<core::ops::RangeFrom<usize>> for PointerBlock {
type Output = [Option<Pointer>];
#[inline]
fn index(&self, index: core::ops::RangeFrom<usize>) -> &[Option<Pointer>] {
let &PointerBlock(ref dat) = self;
&dat[index]
}
}
impl core::ops::Index<core::ops::RangeFull> for PointerBlock {
type Output = [Option<Pointer>];
#[inline]
fn index(&self, index: core::ops::RangeFull) -> &[Option<Pointer>] {
let &PointerBlock(ref dat) = self;
&dat[index]
}
}
impl ::std::fmt::Debug for PointerBlock {
#[allow(clippy::assertions_on_constants)]
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
assert!(RADIX > 1, "RADIX must be > 1");
write!(f, "{}([", stringify!(PointerBlock))?;
write!(f, "{:?}", self.0[0])?;
for item in self.0[1..].iter() {
write!(f, ", {:?}", item)?;
}
write!(f, "])")
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Trie<K, V> {
Leaf { key: K, value: V },
Node { pointer_block: Box<PointerBlock> },
Extension { affix: Vec<u8>, pointer: Pointer },
}
impl<K, V> Trie<K, V> {
fn tag(&self) -> u8 {
match self {
Trie::Leaf { .. } => 0,
Trie::Node { .. } => 1,
Trie::Extension { .. } => 2,
}
}
pub fn leaf(key: K, value: V) -> Self {
Trie::Leaf { key, value }
}
pub fn node(indexed_pointers: &[(usize, Pointer)]) -> Self {
let pointer_block = PointerBlock::from_indexed_pointers(indexed_pointers);
let pointer_block = Box::new(pointer_block);
Trie::Node { pointer_block }
}
pub fn extension(affix: Vec<u8>, pointer: Pointer) -> Self {
Trie::Extension { affix, pointer }
}
pub fn key(&self) -> Option<&K> {
match self {
Trie::Leaf { key, .. } => Some(key),
_ => None,
}
}
}
impl<K, V> ToBytes for Trie<K, V>
where
K: ToBytes,
V: ToBytes,
{
fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
let mut ret = bytesrepr::allocate_buffer(self)?;
ret.push(self.tag());
match self {
Trie::Leaf { key, value } => {
ret.append(&mut key.to_bytes()?);
ret.append(&mut value.to_bytes()?);
}
Trie::Node { pointer_block } => {
ret.append(&mut pointer_block.to_bytes()?);
}
Trie::Extension { affix, pointer } => {
ret.append(&mut affix.to_bytes()?);
ret.append(&mut pointer.to_bytes()?);
}
}
Ok(ret)
}
fn serialized_length(&self) -> usize {
U8_SERIALIZED_LENGTH
+ match self {
Trie::Leaf { key, value } => key.serialized_length() + value.serialized_length(),
Trie::Node { pointer_block } => pointer_block.serialized_length(),
Trie::Extension { affix, pointer } => {
affix.serialized_length() + pointer.serialized_length()
}
}
}
}
impl<K: FromBytes, V: FromBytes> FromBytes for Trie<K, V> {
fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
let (tag, rem) = u8::from_bytes(bytes)?;
match tag {
0 => {
let (key, rem) = K::from_bytes(rem)?;
let (value, rem) = V::from_bytes(rem)?;
Ok((Trie::Leaf { key, value }, rem))
}
1 => {
let (pointer_block, rem) = PointerBlock::from_bytes(rem)?;
Ok((
Trie::Node {
pointer_block: Box::new(pointer_block),
},
rem,
))
}
2 => {
let (affix, rem) = Vec::<u8>::from_bytes(rem)?;
let (pointer, rem) = Pointer::from_bytes(rem)?;
Ok((Trie::Extension { affix, pointer }, rem))
}
_ => Err(bytesrepr::Error::Formatting),
}
}
}
pub(crate) mod operations {
use crate::trie::Trie;
use engine_shared::newtypes::Blake2bHash;
use types::bytesrepr::{self, ToBytes};
pub fn create_hashed_empty_trie<K: ToBytes, V: ToBytes>(
) -> Result<(Blake2bHash, Trie<K, V>), bytesrepr::Error> {
let root: Trie<K, V> = Trie::Node {
pointer_block: Default::default(),
};
let root_bytes: Vec<u8> = root.to_bytes()?;
Ok((Blake2bHash::new(&root_bytes), root))
}
}