use lora_store::GraphStorage;
use crate::errors::ExecResult;
use crate::executor::sort_rows_with_top_k;
use crate::value::Row;
use super::{drain, RowSource, StreamCtx};
pub struct LimitSource<'a> {
upstream: Box<dyn RowSource + 'a>,
skip: usize,
limit: Option<usize>,
skipped: usize,
emitted: usize,
}
impl<'a> LimitSource<'a> {
pub(super) fn new(
upstream: Box<dyn RowSource + 'a>,
skip: usize,
limit: Option<usize>,
) -> Self {
Self {
upstream,
skip,
limit,
skipped: 0,
emitted: 0,
}
}
}
impl<'a> RowSource for LimitSource<'a> {
fn next_row(&mut self) -> ExecResult<Option<Row>> {
while self.skipped < self.skip {
match self.upstream.next_row()? {
Some(_) => self.skipped += 1,
None => return Ok(None),
}
}
if let Some(lim) = self.limit {
if self.emitted >= lim {
return Ok(None);
}
}
match self.upstream.next_row()? {
Some(row) => {
self.emitted += 1;
Ok(Some(row))
}
None => Ok(None),
}
}
}
pub struct SortSource<'a, S: GraphStorage> {
state: SortState<'a, S>,
}
enum SortState<'a, S: GraphStorage> {
Pending {
upstream: Box<dyn RowSource + 'a>,
ctx: StreamCtx<'a, S>,
items: &'a [lora_analyzer::ResolvedSortItem],
top_k: Option<usize>,
},
Yielding(std::vec::IntoIter<Row>),
}
impl<'a, S: GraphStorage> SortSource<'a, S> {
pub(super) fn new_with_top_k(
upstream: Box<dyn RowSource + 'a>,
ctx: StreamCtx<'a, S>,
items: &'a [lora_analyzer::ResolvedSortItem],
top_k: Option<usize>,
) -> Self {
Self {
state: SortState::Pending {
upstream,
ctx,
items,
top_k,
},
}
}
fn materialize(
upstream: &mut Box<dyn RowSource + 'a>,
ctx: &StreamCtx<'a, S>,
items: &[lora_analyzer::ResolvedSortItem],
top_k: Option<usize>,
) -> ExecResult<Vec<Row>> {
let mut rows = drain(upstream.as_mut())?;
let eval_ctx = ctx.eval_ctx();
sort_rows_with_top_k(&mut rows, items, &eval_ctx, top_k);
Ok(rows)
}
}
impl<'a, S: GraphStorage> RowSource for SortSource<'a, S> {
fn next_row(&mut self) -> ExecResult<Option<Row>> {
loop {
match &mut self.state {
SortState::Pending {
upstream,
ctx,
items,
top_k,
} => {
let rows = Self::materialize(upstream, ctx, items, *top_k)?;
self.state = SortState::Yielding(rows.into_iter());
}
SortState::Yielding(it) => return Ok(it.next()),
}
}
}
}