use std::cmp::Ordering;
use std::sync::Arc;
use super::block::{Block, BlockIter, Compare};
use super::handle::BlockHandle;
use super::source::BlockSource;
use crate::error::{Error, Result};
#[derive(Debug)]
pub struct TableIter {
source: Arc<dyn BlockSource>,
compare: Compare,
index: BlockIter,
data: Option<BlockIter>,
pending: Option<(BlockHandle, Want)>,
error: Option<Error>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum Want {
First,
Seek(Vec<u8>),
Last,
ForPrev(Vec<u8>),
}
impl TableIter {
pub(super) fn new(source: Arc<dyn BlockSource>, compare: Compare, index: BlockIter) -> Self {
Self {
source,
compare,
index,
data: None,
pending: None,
error: None,
}
}
pub fn valid(&self) -> bool {
self.error.is_none() && self.data.as_ref().is_some_and(BlockIter::valid)
}
pub fn key(&self) -> &[u8] {
if self.valid() {
self.data.as_ref().map_or(&[], BlockIter::key)
} else {
&[]
}
}
pub fn value(&self) -> &[u8] {
if self.valid() {
self.data.as_ref().map_or(&[], BlockIter::value)
} else {
&[]
}
}
pub fn status(&self) -> Result<()> {
if let Some(error) = &self.error {
return Err(error.clone());
}
self.index.status()?;
self.data.as_ref().map_or(Ok(()), BlockIter::status)
}
pub fn pending(&self) -> Option<BlockHandle> {
self.pending.as_ref().map(|(handle, _)| *handle)
}
pub fn resume(&mut self, block: Block) {
if let Some((_, want)) = self.pending.take() {
self.enter(block, want);
}
}
pub fn seek_to_first(&mut self) {
self.reset();
self.index.seek_to_first();
self.load(Want::First);
}
pub fn seek(&mut self, target: &[u8]) {
self.reset();
self.index.seek(target);
self.load(Want::Seek(target.to_vec()));
}
pub fn next(&mut self) {
if self.pending.is_some() {
return;
}
if let Some(data) = &mut self.data {
data.next();
self.forward();
}
}
pub fn seek_to_last(&mut self) {
self.reset();
self.index.seek_to_last();
self.load(Want::Last);
}
pub fn seek_for_prev(&mut self, target: &[u8]) {
self.reset();
self.index.seek(target);
if self.index.valid() {
self.load(Want::ForPrev(target.to_vec()));
} else if self.index.status().is_ok() {
self.index.seek_to_last();
self.load(Want::Last);
}
}
pub fn prev(&mut self) {
if self.pending.is_some() {
return;
}
if let Some(data) = &mut self.data {
data.prev();
self.backward();
}
}
fn reset(&mut self) {
self.data = None;
self.pending = None;
}
fn load(&mut self, want: Want) {
self.data = None;
if self.error.is_some() || !self.index.valid() {
return;
}
let handle = match BlockHandle::decode(self.index.value()) {
Ok(handle) => handle,
Err(error) => {
self.error = Some(error);
return;
}
};
match self.source.block(handle) {
Ok(Some(block)) => self.enter(block, want),
Ok(None) => self.pending = Some((handle, want)),
Err(error) => self.error = Some(error),
}
}
fn enter(&mut self, block: Block, want: Want) {
let mut data = block.iter();
let forward = match &want {
Want::First => {
data.seek_to_first();
true
}
Want::Seek(target) => {
data.seek(target);
true
}
Want::Last => {
data.seek_to_last();
false
}
Want::ForPrev(target) => {
data.seek(target);
if !data.valid() {
if data.status().is_ok() {
data.seek_to_last();
}
} else if (self.compare)(data.key(), target) == Ordering::Greater {
data.prev();
}
false
}
};
self.data = Some(data);
if forward {
self.forward();
} else {
self.backward();
}
}
fn forward(&mut self) {
while self.finished() {
self.index.next();
self.load(Want::First);
}
}
fn backward(&mut self) {
while self.finished() {
self.index.prev();
self.load(Want::Last);
}
}
fn finished(&self) -> bool {
match &self.data {
Some(data) => !data.valid() && data.status().is_ok(),
None => false,
}
}
}