jmt/types/nibble/
nibble_path.rsuse alloc::vec;
use core::{fmt, iter::FromIterator};
use alloc::vec::Vec;
use mirai_annotations::*;
#[cfg(any(test))]
use proptest::{collection::vec, prelude::*};
use serde::{Deserialize, Serialize};
use crate::types::nibble::{Nibble, ROOT_NIBBLE_HEIGHT};
#[derive(
Clone,
Hash,
Eq,
PartialEq,
Ord,
PartialOrd,
Serialize,
Deserialize,
borsh::BorshSerialize,
borsh::BorshDeserialize,
)]
pub struct NibblePath {
num_nibbles: usize,
bytes: Vec<u8>,
}
impl fmt::Debug for NibblePath {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.nibbles().try_for_each(|x| write!(f, "{:x}", x))
}
}
impl FromIterator<Nibble> for NibblePath {
fn from_iter<I: IntoIterator<Item = Nibble>>(iter: I) -> Self {
let mut nibble_path = NibblePath::new(vec![]);
for nibble in iter {
nibble_path.push(nibble);
}
nibble_path
}
}
#[cfg(any(test))]
impl Arbitrary for NibblePath {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
arb_nibble_path().boxed()
}
type Strategy = BoxedStrategy<Self>;
}
#[cfg(any(test))]
prop_compose! {
fn arb_nibble_path()(
mut bytes in vec(any::<u8>(), 0..=ROOT_NIBBLE_HEIGHT/2),
is_odd in any::<bool>()
) -> NibblePath {
if let Some(last_byte) = bytes.last_mut() {
if is_odd {
*last_byte &= 0xf0;
return NibblePath::new_odd(bytes);
}
}
NibblePath::new(bytes)
}
}
#[cfg(any(test))]
prop_compose! {
pub(crate) fn arb_internal_nibble_path()(
nibble_path in arb_nibble_path().prop_filter(
"Filter out leaf paths.",
|p| p.num_nibbles() < ROOT_NIBBLE_HEIGHT,
)
) -> NibblePath {
nibble_path
}
}
impl NibblePath {
pub(crate) fn new(bytes: Vec<u8>) -> Self {
checked_precondition!(bytes.len() <= ROOT_NIBBLE_HEIGHT / 2);
let num_nibbles = bytes.len() * 2;
NibblePath { num_nibbles, bytes }
}
#[allow(unused)]
pub(crate) fn new_odd(bytes: Vec<u8>) -> Self {
checked_precondition!(bytes.len() <= ROOT_NIBBLE_HEIGHT / 2);
assert_eq!(
bytes.last().expect("Should have odd number of nibbles.") & 0x0f,
0,
"Last nibble must be 0."
);
let num_nibbles = bytes.len() * 2 - 1;
NibblePath { num_nibbles, bytes }
}
pub(crate) fn push(&mut self, nibble: Nibble) {
assert!(ROOT_NIBBLE_HEIGHT > self.num_nibbles);
if self.num_nibbles % 2 == 0 {
self.bytes.push(u8::from(nibble) << 4);
} else {
self.bytes[self.num_nibbles / 2] |= u8::from(nibble);
}
self.num_nibbles += 1;
}
pub(crate) fn pop(&mut self) -> Option<Nibble> {
let poped_nibble = if self.num_nibbles % 2 == 0 {
self.bytes.last_mut().map(|last_byte| {
let nibble = *last_byte & 0x0f;
*last_byte &= 0xf0;
Nibble::from(nibble)
})
} else {
self.bytes.pop().map(|byte| Nibble::from(byte >> 4))
};
if poped_nibble.is_some() {
self.num_nibbles -= 1;
}
poped_nibble
}
pub fn last(&self) -> Option<Nibble> {
let last_byte_option = self.bytes.last();
if self.num_nibbles % 2 == 0 {
last_byte_option.map(|last_byte| Nibble::from(*last_byte & 0x0f))
} else {
let last_byte = last_byte_option.expect("Last byte must exist if num_nibbles is odd.");
Some(Nibble::from(*last_byte >> 4))
}
}
pub(crate) fn get_bit(&self, i: usize) -> bool {
assert!(i < self.num_nibbles * 4);
let pos = i / 8;
let bit = 7 - i % 8;
((self.bytes[pos] >> bit) & 1) != 0
}
pub fn get_nibble(&self, i: usize) -> Nibble {
assert!(i < self.num_nibbles);
Nibble::from((self.bytes[i / 2] >> (if i % 2 == 1 { 0 } else { 4 })) & 0xf)
}
pub fn bits(&self) -> BitIterator {
assume!(self.num_nibbles <= ROOT_NIBBLE_HEIGHT); BitIterator {
nibble_path: self,
pos: (0..self.num_nibbles * 4),
}
}
pub fn nibbles(&self) -> NibbleIterator {
assume!(self.num_nibbles <= ROOT_NIBBLE_HEIGHT); NibbleIterator::new(self, 0, self.num_nibbles)
}
pub fn num_nibbles(&self) -> usize {
self.num_nibbles
}
pub fn is_empty(&self) -> bool {
self.num_nibbles() == 0
}
pub(crate) fn bytes(&self) -> &[u8] {
&self.bytes
}
}
pub trait Peekable: Iterator {
fn peek(&self) -> Option<Self::Item>;
}
pub struct BitIterator<'a> {
nibble_path: &'a NibblePath,
pos: core::ops::Range<usize>,
}
impl<'a> Peekable for BitIterator<'a> {
fn peek(&self) -> Option<Self::Item> {
if self.pos.start < self.pos.end {
Some(self.nibble_path.get_bit(self.pos.start))
} else {
None
}
}
}
impl<'a> Iterator for BitIterator<'a> {
type Item = bool;
fn next(&mut self) -> Option<Self::Item> {
self.pos.next().map(|i| self.nibble_path.get_bit(i))
}
}
impl<'a> DoubleEndedIterator for BitIterator<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.pos.next_back().map(|i| self.nibble_path.get_bit(i))
}
}
#[derive(Debug, Clone)]
pub struct NibbleIterator<'a> {
nibble_path: &'a NibblePath,
pos: core::ops::Range<usize>,
start: usize,
}
impl<'a> Iterator for NibbleIterator<'a> {
type Item = Nibble;
fn next(&mut self) -> Option<Self::Item> {
self.pos.next().map(|i| self.nibble_path.get_nibble(i))
}
}
impl<'a> Peekable for NibbleIterator<'a> {
fn peek(&self) -> Option<Self::Item> {
if self.pos.start < self.pos.end {
Some(self.nibble_path.get_nibble(self.pos.start))
} else {
None
}
}
}
impl<'a> NibbleIterator<'a> {
fn new(nibble_path: &'a NibblePath, start: usize, end: usize) -> Self {
precondition!(start <= end);
precondition!(start <= ROOT_NIBBLE_HEIGHT);
precondition!(end <= ROOT_NIBBLE_HEIGHT);
Self {
nibble_path,
pos: (start..end),
start,
}
}
pub fn visited_nibbles(&self) -> NibbleIterator<'a> {
assume!(self.start <= self.pos.start); assume!(self.pos.start <= ROOT_NIBBLE_HEIGHT); Self::new(self.nibble_path, self.start, self.pos.start)
}
pub fn remaining_nibbles(&self) -> NibbleIterator<'a> {
assume!(self.pos.start <= self.pos.end); assume!(self.pos.end <= ROOT_NIBBLE_HEIGHT); Self::new(self.nibble_path, self.pos.start, self.pos.end)
}
pub fn bits(&self) -> BitIterator<'a> {
assume!(self.pos.start <= self.pos.end); assume!(self.pos.end <= ROOT_NIBBLE_HEIGHT); BitIterator {
nibble_path: self.nibble_path,
pos: (self.pos.start * 4..self.pos.end * 4),
}
}
pub fn get_nibble_path(&self) -> NibblePath {
self.visited_nibbles()
.chain(self.remaining_nibbles())
.collect()
}
pub fn num_nibbles(&self) -> usize {
assume!(self.start <= self.pos.end); self.pos.end - self.start
}
pub fn is_finished(&self) -> bool {
self.peek().is_none()
}
}
pub fn skip_common_prefix<I1, I2>(x: &mut I1, y: &mut I2) -> usize
where
I1: Iterator + Peekable,
I2: Iterator + Peekable,
<I1 as Iterator>::Item: core::cmp::PartialEq<<I2 as Iterator>::Item>,
{
let mut count = 0;
loop {
let x_peek = x.peek();
let y_peek = y.peek();
if x_peek.is_none()
|| y_peek.is_none()
|| x_peek.expect("cannot be none") != y_peek.expect("cannot be none")
{
break;
}
count += 1;
x.next();
y.next();
}
count
}