use std::cmp::Ordering;
use std::ops::Range;
use super::Block;
use crate::error::{Error, Result};
use crate::varint;
#[derive(Debug)]
pub struct BlockIter {
block: Block,
current: usize,
next: usize,
key: Vec<u8>,
value: Range<usize>,
valid: bool,
error: Option<Error>,
}
impl BlockIter {
pub(super) fn new(block: Block) -> Self {
Self {
block,
current: 0,
next: 0,
key: Vec::new(),
value: 0..0,
valid: false,
error: None,
}
}
pub fn valid(&self) -> bool {
self.valid
}
pub fn key(&self) -> &[u8] {
if self.valid { &self.key } else { &[] }
}
pub fn value(&self) -> &[u8] {
if self.valid {
self.block.bytes.get(self.value.clone()).unwrap_or_default()
} else {
&[]
}
}
pub fn status(&self) -> Result<()> {
self.error.clone().map_or(Ok(()), Err)
}
pub fn seek_to_first(&mut self) {
self.restart_at(0);
self.step();
}
pub fn seek(&mut self, target: &[u8]) {
let (mut low, mut high) = (0, self.block.restart_count.saturating_sub(1));
while low < high {
let middle = low.saturating_add(high.saturating_sub(low).saturating_add(1) / 2);
self.restart_at(middle);
self.step();
if !self.valid {
return;
}
if (self.block.compare)(&self.key, target) == Ordering::Less {
low = middle;
} else {
high = middle.saturating_sub(1);
}
}
self.restart_at(low);
self.step();
while self.valid && (self.block.compare)(&self.key, target) == Ordering::Less {
self.step();
}
}
pub fn next(&mut self) {
if self.valid {
self.step();
}
}
pub fn seek_to_last(&mut self) {
self.restart_at(self.block.restart_count.saturating_sub(1));
self.step();
while self.valid && self.next < self.block.entries_end {
self.step();
}
}
pub fn prev(&mut self) {
if !self.valid {
return;
}
let current = self.current;
let Some(restart) = self.restart_before(current) else {
self.key.clear();
self.valid = false;
self.next = self.block.entries_end;
return;
};
self.restart_at(restart);
self.step();
while self.valid && self.next < current {
self.step();
}
}
fn restart_before(&self, offset: usize) -> Option<usize> {
let (mut low, mut high) = (0, self.block.restart_count);
while low < high {
let middle = low.saturating_add(high.saturating_sub(low) / 2);
match self.block.restart(middle) {
Some(start) if start < offset => low = middle.saturating_add(1),
_ => high = middle,
}
}
low.checked_sub(1)
}
fn restart_at(&mut self, index: usize) {
self.key.clear();
self.valid = false;
match self.block.restart(index) {
Some(offset) if index < self.block.restart_count => self.next = offset,
_ => self.next = self.block.entries_end,
}
}
fn step(&mut self) {
if self.next >= self.block.entries_end {
self.valid = false;
return;
}
self.current = self.next;
match self.decode() {
Some(next) => {
self.next = next;
self.valid = true;
}
None => {
self.valid = false;
self.next = self.block.entries_end;
self.error = Some(Error::Malformed {
what: "block",
reason: "an entry runs past the entries or shares more than the previous key",
});
}
}
}
fn decode(&mut self) -> Option<usize> {
let entries = self.block.bytes.get(..self.block.entries_end)?;
let mut at = self.next;
let field = |at: &mut usize| -> Option<usize> {
let (value, used) = varint::get_u32(entries.get(*at..)?)?;
*at = at.checked_add(used)?;
usize::try_from(value).ok()
};
let shared = field(&mut at)?;
let unshared = field(&mut at)?;
let value_len = field(&mut at)?;
if shared > self.key.len() {
return None;
}
let suffix_end = at.checked_add(unshared)?;
let value_end = suffix_end.checked_add(value_len)?;
let suffix = entries.get(at..suffix_end)?;
entries.get(suffix_end..value_end)?;
self.key.truncate(shared);
self.key.extend_from_slice(suffix);
self.value = suffix_end..value_end;
Some(value_end)
}
}