use crate::commands::core::AsyncCommands;
use redis::{Cmd, FromRedisValue, RedisResult, from_owned_redis_value};
#[derive(Debug)]
struct PageSpec {
prefix: Vec<Vec<u8>>,
suffix: Vec<Vec<u8>>,
}
impl PageSpec {
fn to_cmd(&self, cursor: u64) -> Cmd {
let mut cmd = Cmd::new();
for a in &self.prefix {
cmd.arg(&a[..]);
}
cmd.arg(cursor);
for a in &self.suffix {
cmd.arg(&a[..]);
}
cmd
}
}
pub struct ScanIter<'a, C: ?Sized, RV> {
con: &'a C,
spec: PageSpec,
cursor: u64,
batch: std::vec::IntoIter<RV>,
}
impl<'a, C: AsyncCommands, RV: FromRedisValue> ScanIter<'a, C, RV> {
pub(crate) async fn new(
con: &'a C,
prefix: Vec<Vec<u8>>,
suffix: Vec<Vec<u8>>,
) -> RedisResult<ScanIter<'a, C, RV>> {
let spec = PageSpec { prefix, suffix };
let (cursor, batch): (u64, Vec<RV>) =
from_owned_redis_value(con.glide_send_owned(spec.to_cmd(0)).await?)?;
Ok(ScanIter {
con,
spec,
cursor,
batch: batch.into_iter(),
})
}
pub async fn next_item(&mut self) -> Option<RV> {
loop {
if let Some(v) = self.batch.next() {
return Some(v);
}
if self.cursor == 0 {
return None;
}
let reply = self
.con
.glide_send_owned(self.spec.to_cmd(self.cursor))
.await
.ok()?;
let (cursor, batch): (u64, Vec<RV>) = from_owned_redis_value(reply).ok()?;
self.cursor = cursor;
self.batch = batch.into_iter();
}
}
}
#[cfg(feature = "sync")]
pub struct SyncScanIter<'a, C: ?Sized, RV> {
con: &'a C,
spec: PageSpec,
cursor: u64,
batch: std::vec::IntoIter<RV>,
}
#[cfg(feature = "sync")]
impl<'a, C: crate::commands::core::Commands, RV: FromRedisValue> SyncScanIter<'a, C, RV> {
pub(crate) fn new(
con: &'a C,
prefix: Vec<Vec<u8>>,
suffix: Vec<Vec<u8>>,
) -> RedisResult<SyncScanIter<'a, C, RV>> {
let spec = PageSpec { prefix, suffix };
let (cursor, batch): (u64, Vec<RV>) =
from_owned_redis_value(con.glide_send_owned_sync(spec.to_cmd(0))?)?;
Ok(SyncScanIter {
con,
spec,
cursor,
batch: batch.into_iter(),
})
}
}
#[cfg(feature = "sync")]
impl<C: crate::commands::core::Commands, RV: FromRedisValue> Iterator for SyncScanIter<'_, C, RV> {
type Item = RV;
fn next(&mut self) -> Option<RV> {
loop {
if let Some(v) = self.batch.next() {
return Some(v);
}
if self.cursor == 0 {
return None;
}
let reply = self
.con
.glide_send_owned_sync(self.spec.to_cmd(self.cursor))
.ok()?;
let (cursor, batch): (u64, Vec<RV>) = from_owned_redis_value(reply).ok()?;
self.cursor = cursor;
self.batch = batch.into_iter();
}
}
}