use vibesql_storage::Row;
#[allow(dead_code)]
pub trait RowIterator: Iterator<Item = Row> {
fn try_clone(&self) -> Option<Box<dyn RowIterator>>;
fn size_hint_rows(&self) -> (usize, Option<usize>) {
self.size_hint()
}
}
#[derive(Clone)]
pub struct VecRowIterator {
rows: Vec<Row>,
pos: usize,
}
impl VecRowIterator {
pub fn new(rows: Vec<Row>) -> Self {
Self { rows, pos: 0 }
}
#[allow(dead_code)]
pub fn into_vec(self) -> Vec<Row> {
self.rows
}
pub fn as_slice(&self) -> &[Row] {
&self.rows[self.pos..]
}
}
impl Iterator for VecRowIterator {
type Item = Row;
fn next(&mut self) -> Option<Self::Item> {
if self.pos < self.rows.len() {
let row = self.rows[self.pos].clone();
self.pos += 1;
Some(row)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.rows.len() - self.pos;
(remaining, Some(remaining))
}
}
impl RowIterator for VecRowIterator {
fn try_clone(&self) -> Option<Box<dyn RowIterator>> {
Some(Box::new(self.clone()))
}
fn size_hint_rows(&self) -> (usize, Option<usize>) {
self.size_hint()
}
}
#[derive(Clone)]
pub struct TableScanIterator {
rows: Vec<Row>,
pos: usize,
}
impl TableScanIterator {
pub fn new(rows: Vec<Row>) -> Self {
Self { rows, pos: 0 }
}
}
impl Iterator for TableScanIterator {
type Item = Row;
fn next(&mut self) -> Option<Self::Item> {
if self.pos < self.rows.len() {
let row = self.rows[self.pos].clone();
self.pos += 1;
Some(row)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.rows.len() - self.pos;
(remaining, Some(remaining))
}
}
impl RowIterator for TableScanIterator {
fn try_clone(&self) -> Option<Box<dyn RowIterator>> {
Some(Box::new(self.clone()))
}
fn size_hint_rows(&self) -> (usize, Option<usize>) {
self.size_hint()
}
}
pub enum FromIterator {
Materialized(VecRowIterator),
TableScan(TableScanIterator),
}
impl FromIterator {
pub fn from_vec(rows: Vec<Row>) -> Self {
Self::Materialized(VecRowIterator::new(rows))
}
pub fn from_table_scan(rows: Vec<Row>) -> Self {
Self::TableScan(TableScanIterator::new(rows))
}
pub fn collect_vec(self) -> Vec<Row> {
match self {
Self::Materialized(iter) => iter.collect(),
Self::TableScan(iter) => iter.collect(),
}
}
pub fn as_slice(&self) -> &[Row] {
match self {
Self::Materialized(iter) => iter.as_slice(),
Self::TableScan(iter) => &iter.rows[iter.pos..],
}
}
#[allow(dead_code)]
pub fn size_hint(&self) -> (usize, Option<usize>) {
match self {
Self::Materialized(iter) => iter.size_hint(),
Self::TableScan(iter) => iter.size_hint(),
}
}
}
impl Iterator for FromIterator {
type Item = Row;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::Materialized(iter) => iter.next(),
Self::TableScan(iter) => iter.next(),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
Self::Materialized(iter) => iter.size_hint(),
Self::TableScan(iter) => iter.size_hint(),
}
}
}
#[cfg(test)]
mod tests {
use vibesql_types::SqlValue;
use super::*;
fn test_row(id: i32) -> Row {
Row::new(vec![SqlValue::Integer(id as i64)])
}
#[test]
fn test_vec_row_iterator() {
let rows = vec![test_row(1), test_row(2), test_row(3)];
let mut iter = VecRowIterator::new(rows.clone());
assert_eq!(iter.size_hint(), (3, Some(3)));
assert_eq!(iter.next().unwrap(), rows[0]);
assert_eq!(iter.next().unwrap(), rows[1]);
assert_eq!(iter.size_hint(), (1, Some(1)));
assert_eq!(iter.next().unwrap(), rows[2]);
assert!(iter.next().is_none());
}
#[test]
fn test_table_scan_iterator() {
let rows = vec![test_row(10), test_row(20)];
let mut iter = TableScanIterator::new(rows.clone());
assert_eq!(iter.size_hint(), (2, Some(2)));
assert_eq!(iter.next().unwrap(), rows[0]);
assert_eq!(iter.next().unwrap(), rows[1]);
assert!(iter.next().is_none());
}
#[test]
fn test_from_iterator_materialized() {
let rows = vec![test_row(1), test_row(2)];
let mut iter = FromIterator::from_vec(rows.clone());
assert_eq!(iter.size_hint(), (2, Some(2)));
assert_eq!(iter.next().unwrap(), rows[0]);
assert_eq!(iter.next().unwrap(), rows[1]);
assert!(iter.next().is_none());
}
#[test]
fn test_from_iterator_table_scan() {
let rows = vec![test_row(100)];
let mut iter = FromIterator::from_table_scan(rows.clone());
assert_eq!(iter.next().unwrap(), rows[0]);
assert!(iter.next().is_none());
}
#[test]
fn test_from_iterator_collect() {
let rows = vec![test_row(1), test_row(2), test_row(3)];
let iter = FromIterator::from_vec(rows.clone());
let collected = iter.collect_vec();
assert_eq!(collected, rows);
}
}