use std::{
ffi::c_void,
mem,
ptr::{self},
};
use crate::{key::RedisKey, raw, RedisString};
pub struct ScanKeyCursor {
key: RedisKey,
inner_cursor: *mut raw::RedisModuleScanCursor,
}
impl ScanKeyCursor {
pub fn new(key: RedisKey) -> Self {
let inner_cursor = unsafe { raw::RedisModule_ScanCursorCreate.unwrap()() };
Self { key, inner_cursor }
}
pub fn restart(&self) {
unsafe { raw::RedisModule_ScanCursorRestart.unwrap()(self.inner_cursor) };
}
pub fn scan<F: FnMut(&RedisKey, &RedisString, &RedisString)>(&self, f: F) -> bool {
unsafe extern "C" fn scan_callback<F: FnMut(&RedisKey, &RedisString, &RedisString)>(
key: *mut raw::RedisModuleKey,
field: *mut raw::RedisModuleString,
value: *mut raw::RedisModuleString,
data: *mut c_void,
) {
let ctx = ptr::null_mut();
let key = RedisKey::from_raw_parts(ctx, key);
let field = RedisString::from_redis_module_string(ctx, field);
let value = RedisString::from_redis_module_string(ctx, value);
let callback = unsafe { &mut *(data.cast::<F>()) };
callback(&key, &field, &value);
mem::forget(field);
mem::forget(value);
mem::forget(key);
}
let scan_key = unsafe { raw::RedisModule_ScanKey.unwrap() };
let res = unsafe {
scan_key(
self.key.key_inner,
self.inner_cursor,
Some(scan_callback::<F>),
&f as *const F as *mut c_void,
)
};
res != 0
}
pub fn for_each<F: FnMut(&RedisKey, &RedisString, &RedisString)>(&self, mut f: F) {
while self.scan(&mut f) {
}
}
}
impl Drop for ScanKeyCursor {
fn drop(&mut self) {
unsafe { raw::RedisModule_ScanCursorDestroy.unwrap()(self.inner_cursor) };
}
}