use super::{nibble_ops, BackingByteVec, NibbleSlice, NibbleSliceIterator, NibbleVec};
#[cfg(feature = "std")]
use crate::rstd::fmt;
use crate::{node::NodeKey, node_codec::Partial, rstd::cmp::*};
use hash_db::Prefix;
impl<'a> Iterator for NibbleSliceIterator<'a> {
type Item = u8;
fn next(&mut self) -> Option<u8> {
self.i += 1;
match self.i <= self.p.len() {
true => Some(self.p.at(self.i - 1)),
false => None,
}
}
}
impl<'a> NibbleSlice<'a> {
pub fn new(data: &'a [u8]) -> Self {
NibbleSlice::new_slice(data, 0)
}
pub fn new_offset(data: &'a [u8], offset: usize) -> Self {
Self::new_slice(data, offset)
}
fn new_slice(data: &'a [u8], offset: usize) -> Self {
NibbleSlice { data, offset }
}
pub fn iter(&'a self) -> NibbleSliceIterator<'a> {
NibbleSliceIterator { p: self, i: 0 }
}
pub fn from_stored(i: &NodeKey) -> NibbleSlice {
NibbleSlice::new_offset(&i.1[..], i.0)
}
pub fn to_stored(&self) -> NodeKey {
let split = self.offset / nibble_ops::NIBBLE_PER_BYTE;
let offset = self.offset % nibble_ops::NIBBLE_PER_BYTE;
(offset, self.data[split..].into())
}
pub fn to_stored_range(&self, nb: usize) -> NodeKey {
if nb >= self.len() {
return self.to_stored()
}
if (self.offset + nb) % nibble_ops::NIBBLE_PER_BYTE == 0 {
let start = self.offset / nibble_ops::NIBBLE_PER_BYTE;
let end = (self.offset + nb) / nibble_ops::NIBBLE_PER_BYTE;
(
self.offset % nibble_ops::NIBBLE_PER_BYTE,
BackingByteVec::from_slice(&self.data[start..end]),
)
} else {
let start = self.offset / nibble_ops::NIBBLE_PER_BYTE;
let end = (self.offset + nb) / nibble_ops::NIBBLE_PER_BYTE;
let ea = BackingByteVec::from_slice(&self.data[start..=end]);
let ea_offset = self.offset % nibble_ops::NIBBLE_PER_BYTE;
let n_offset = nibble_ops::number_padding(nb);
let mut result = (ea_offset, ea);
nibble_ops::shift_key(&mut result, n_offset);
result.1.pop();
result
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn len(&self) -> usize {
self.data.len() * nibble_ops::NIBBLE_PER_BYTE - self.offset
}
#[inline(always)]
pub fn at(&self, i: usize) -> u8 {
nibble_ops::at(&self, i)
}
pub fn mid(&self, i: usize) -> NibbleSlice<'a> {
NibbleSlice { data: self.data, offset: self.offset + i }
}
pub fn advance(&mut self, i: usize) {
debug_assert!(self.len() >= i);
self.offset += i;
}
pub fn back(&self, i: usize) -> NibbleSlice<'a> {
NibbleSlice { data: self.data, offset: i }
}
pub fn starts_with(&self, them: &Self) -> bool {
self.common_prefix(them) == them.len()
}
pub fn common_prefix(&self, them: &Self) -> usize {
let self_align = self.offset % nibble_ops::NIBBLE_PER_BYTE;
let them_align = them.offset % nibble_ops::NIBBLE_PER_BYTE;
if self_align == them_align {
let mut self_start = self.offset / nibble_ops::NIBBLE_PER_BYTE;
let mut them_start = them.offset / nibble_ops::NIBBLE_PER_BYTE;
let mut first = 0;
if self_align != 0 {
if nibble_ops::pad_right(self.data[self_start]) !=
nibble_ops::pad_right(them.data[them_start])
{
return 0
}
self_start += 1;
them_start += 1;
first += 1;
}
nibble_ops::biggest_depth(&self.data[self_start..], &them.data[them_start..]) + first
} else {
let s = min(self.len(), them.len());
let mut i = 0usize;
while i < s {
if self.at(i) != them.at(i) {
break
}
i += 1;
}
i
}
}
pub fn right(&'a self) -> Partial {
let split = self.offset / nibble_ops::NIBBLE_PER_BYTE;
let nb = (self.len() % nibble_ops::NIBBLE_PER_BYTE) as u8;
if nb > 0 {
((nb, nibble_ops::pad_right(self.data[split])), &self.data[split + 1..])
} else {
((0, 0), &self.data[split..])
}
}
pub fn right_iter(&'a self) -> impl Iterator<Item = u8> + 'a {
let (mut first, sl) = self.right();
let mut ix = 0;
crate::rstd::iter::from_fn(move || {
if first.0 > 0 {
first.0 = 0;
Some(nibble_ops::pad_right(first.1))
} else if ix < sl.len() {
ix += 1;
Some(sl[ix - 1])
} else {
None
}
})
}
pub fn right_range_iter(&'a self, to: usize) -> impl Iterator<Item = u8> + 'a {
let mut nib_res = to % nibble_ops::NIBBLE_PER_BYTE;
let aligned_i = (self.offset + to) % nibble_ops::NIBBLE_PER_BYTE;
let aligned = aligned_i == 0;
let mut ix = self.offset / nibble_ops::NIBBLE_PER_BYTE;
let ix_lim = (self.offset + to) / nibble_ops::NIBBLE_PER_BYTE;
crate::rstd::iter::from_fn(move || {
if aligned {
if nib_res > 0 {
let v = nibble_ops::pad_right(self.data[ix]);
nib_res = 0;
ix += 1;
Some(v)
} else if ix < ix_lim {
ix += 1;
Some(self.data[ix - 1])
} else {
None
}
} else {
let (s1, s2) = nibble_ops::SPLIT_SHIFTS;
if nib_res > 0 {
let v = self.data[ix] >> s1;
let v = nibble_ops::pad_right(v);
nib_res = 0;
Some(v)
} else if ix < ix_lim {
ix += 1;
let b1 = self.data[ix - 1] << s2;
let b2 = self.data[ix] >> s1;
Some(b1 | b2)
} else {
None
}
}
})
}
pub fn left(&'a self) -> Prefix {
let split = self.offset / nibble_ops::NIBBLE_PER_BYTE;
let ix = (self.offset % nibble_ops::NIBBLE_PER_BYTE) as u8;
if ix == 0 {
(&self.data[..split], None)
} else {
(&self.data[..split], Some(nibble_ops::pad_left(self.data[split])))
}
}
pub fn original_data_as_prefix(&self) -> Prefix {
(&self.data, None)
}
pub fn left_owned(&'a self) -> (BackingByteVec, Option<u8>) {
let (a, b) = self.left();
(a.into(), b)
}
pub fn starts_with_vec(&self, other: &NibbleVec) -> bool {
if self.len() < other.len() {
return false
}
match other.as_nibbleslice() {
Some(other) => self.starts_with(&other),
None => {
for i in 0..other.len() {
if self.at(i) != other.at(i) {
return false
}
}
true
},
}
}
}
impl<'a> From<NibbleSlice<'a>> for NodeKey {
fn from(slice: NibbleSlice<'a>) -> NodeKey {
(slice.offset, slice.data.into())
}
}
impl<'a> PartialEq for NibbleSlice<'a> {
fn eq(&self, them: &Self) -> bool {
self.len() == them.len() && self.starts_with(them)
}
}
impl<'a> PartialEq<NibbleVec> for NibbleSlice<'a> {
fn eq(&self, other: &NibbleVec) -> bool {
if self.len() != other.len() {
return false
}
match other.as_nibbleslice() {
Some(other) => *self == other,
None => self.iter().enumerate().all(|(index, l)| l == other.at(index)),
}
}
}
impl<'a> Eq for NibbleSlice<'a> {}
impl<'a> PartialOrd for NibbleSlice<'a> {
fn partial_cmp(&self, them: &Self) -> Option<Ordering> {
Some(self.cmp(them))
}
}
impl<'a> Ord for NibbleSlice<'a> {
fn cmp(&self, them: &Self) -> Ordering {
let s = min(self.len(), them.len());
let mut i = 0usize;
while i < s {
match self.at(i).partial_cmp(&them.at(i)).unwrap() {
Ordering::Less => return Ordering::Less,
Ordering::Greater => return Ordering::Greater,
_ => i += 1,
}
}
self.len().cmp(&them.len())
}
}
#[cfg(feature = "std")]
impl<'a> fmt::Debug for NibbleSlice<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in 0..self.len() {
match i {
0 => write!(f, "{:01x}", self.at(i))?,
_ => write!(f, "'{:01x}", self.at(i))?,
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::nibble::{BackingByteVec, NibbleSlice};
static D: &'static [u8; 3] = &[0x01u8, 0x23, 0x45];
#[test]
fn basics() {
let n = NibbleSlice::new(D);
assert_eq!(n.len(), 6);
assert!(!n.is_empty());
let n = NibbleSlice::new_offset(D, 6);
assert!(n.is_empty());
let n = NibbleSlice::new_offset(D, 3);
assert_eq!(n.len(), 3);
for i in 0..3 {
assert_eq!(n.at(i), i as u8 + 3);
}
}
#[test]
fn iterator() {
let n = NibbleSlice::new(D);
let mut nibbles: Vec<u8> = vec![];
nibbles.extend(n.iter());
assert_eq!(nibbles, (0u8..6).collect::<Vec<_>>())
}
#[test]
fn mid() {
let n = NibbleSlice::new(D);
let m = n.mid(2);
for i in 0..4 {
assert_eq!(m.at(i), i as u8 + 2);
}
let m = n.mid(3);
for i in 0..3 {
assert_eq!(m.at(i), i as u8 + 3);
}
}
#[test]
fn encoded_pre() {
let n = NibbleSlice::new(D);
assert_eq!(n.to_stored(), (0, BackingByteVec::from_slice(&[0x01, 0x23, 0x45])));
assert_eq!(n.mid(1).to_stored(), (1, BackingByteVec::from_slice(&[0x01, 0x23, 0x45])));
assert_eq!(n.mid(2).to_stored(), (0, BackingByteVec::from_slice(&[0x23, 0x45])));
assert_eq!(n.mid(3).to_stored(), (1, BackingByteVec::from_slice(&[0x23, 0x45])));
}
#[test]
fn from_encoded_pre() {
let n = NibbleSlice::new(D);
let stored: BackingByteVec = [0x01, 0x23, 0x45][..].into();
assert_eq!(n, NibbleSlice::from_stored(&(0, stored.clone())));
assert_eq!(n.mid(1), NibbleSlice::from_stored(&(1, stored)));
}
#[test]
fn range_iter() {
let n = NibbleSlice::new(D);
for i in [
vec![],
vec![0x00],
vec![0x01],
vec![0x00, 0x12],
vec![0x01, 0x23],
vec![0x00, 0x12, 0x34],
vec![0x01, 0x23, 0x45],
]
.iter()
.enumerate()
{
range_iter_test(n, i.0, None, &i.1[..]);
}
for i in [
vec![],
vec![0x01],
vec![0x12],
vec![0x01, 0x23],
vec![0x12, 0x34],
vec![0x01, 0x23, 0x45],
]
.iter()
.enumerate()
{
range_iter_test(n, i.0, Some(1), &i.1[..]);
}
for i in [vec![], vec![0x02], vec![0x23], vec![0x02, 0x34], vec![0x23, 0x45]]
.iter()
.enumerate()
{
range_iter_test(n, i.0, Some(2), &i.1[..]);
}
for i in [vec![], vec![0x03], vec![0x34], vec![0x03, 0x45]].iter().enumerate() {
range_iter_test(n, i.0, Some(3), &i.1[..]);
}
}
fn range_iter_test(n: NibbleSlice, nb: usize, mid: Option<usize>, res: &[u8]) {
let n = if let Some(i) = mid { n.mid(i) } else { n };
assert_eq!(&n.right_range_iter(nb).collect::<Vec<_>>()[..], res);
}
#[test]
fn shared() {
let n = NibbleSlice::new(D);
let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45, 0x67];
let m = NibbleSlice::new(other);
assert_eq!(n.common_prefix(&m), 4);
assert_eq!(m.common_prefix(&n), 4);
assert_eq!(n.mid(1).common_prefix(&m.mid(1)), 3);
assert_eq!(n.mid(1).common_prefix(&m.mid(2)), 0);
assert_eq!(n.common_prefix(&m.mid(4)), 6);
assert!(!n.starts_with(&m.mid(4)));
assert!(m.mid(4).starts_with(&n));
}
#[test]
fn compare() {
let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45];
let n = NibbleSlice::new(D);
let m = NibbleSlice::new(other);
assert!(n != m);
assert!(n > m);
assert!(m < n);
assert!(n == m.mid(4));
assert!(n >= m.mid(4));
assert!(n <= m.mid(4));
}
}