use core::ops::Index;
use mirai_annotations::*;
pub trait Bytes32Ext: Index<usize> + Sized {
fn get_nibble(&self, index: usize) -> crate::types::nibble::Nibble;
fn common_prefix_bits_len(&self, other: &[u8; 32]) -> usize;
fn iter_bits(&self) -> HashValueBitIterator<'_>;
fn nibble(&self, index: usize) -> u8;
fn common_prefix_nibbles_len(&self, other: &[u8; 32]) -> usize {
self.common_prefix_bits_len(other) / 4
}
fn from_bit_iter(iter: impl ExactSizeIterator<Item = bool>) -> Option<Self>;
}
impl Bytes32Ext for [u8; 32] {
fn get_nibble(&self, index: usize) -> crate::types::nibble::Nibble {
crate::types::nibble::Nibble::from(if index % 2 == 0 {
self[index / 2] >> 4
} else {
self[index / 2] & 0x0F
})
}
fn common_prefix_bits_len(&self, other: &[u8; 32]) -> usize {
self.iter_bits()
.zip(other.iter_bits())
.take_while(|(x, y)| x == y)
.count()
}
fn iter_bits(&self) -> HashValueBitIterator<'_> {
HashValueBitIterator::new(self)
}
fn nibble(&self, index: usize) -> u8 {
assume!(index < 32 * 2); let pos = index / 2;
let shift = if index % 2 == 0 { 4 } else { 0 };
(self[pos] >> shift) & 0x0f
}
fn from_bit_iter(iter: impl ExactSizeIterator<Item = bool>) -> Option<Self> {
if iter.len() != 256 {
return None;
}
let mut buf = [0; 32];
for (i, bit) in iter.enumerate() {
if bit {
buf[i / 8] |= 1 << (7 - i % 8);
}
}
Some(buf)
}
}
pub struct HashValueBitIterator<'a> {
hash_bytes: &'a [u8],
pos: core::ops::Range<usize>,
}
impl<'a> HashValueBitIterator<'a> {
fn new(hash_value: &'a [u8; 32]) -> Self {
HashValueBitIterator {
hash_bytes: hash_value.as_ref(),
pos: (0..32 * 8),
}
}
fn get_bit(&self, index: usize) -> bool {
assume!(index < self.pos.end); assume!(self.hash_bytes.len() == 32); assume!(self.pos.end == self.hash_bytes.len() * 8); let pos = index / 8;
let bit = 7 - index % 8;
(self.hash_bytes[pos] >> bit) & 1 != 0
}
}
impl<'a> core::iter::Iterator for HashValueBitIterator<'a> {
type Item = bool;
fn next(&mut self) -> Option<Self::Item> {
self.pos.next().map(|x| self.get_bit(x))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.pos.size_hint()
}
}
impl<'a> core::iter::DoubleEndedIterator for HashValueBitIterator<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.pos.next_back().map(|x| self.get_bit(x))
}
}
impl<'a> core::iter::ExactSizeIterator for HashValueBitIterator<'a> {}