redis_module/context/
keys_cursor.rs1use crate::context::Context;
2use crate::key::RedisKey;
3use crate::raw;
4use crate::redismodule::RedisString;
5use std::ffi::c_void;
6use std::mem;
7use std::ptr::NonNull;
8
9pub struct KeysCursor {
10 inner_cursor: *mut raw::RedisModuleScanCursor,
11}
12
13extern "C" fn scan_callback<C: FnMut(&Context, &RedisString, Option<&RedisKey>)>(
14 ctx: *mut raw::RedisModuleCtx,
15 key_name: *mut raw::RedisModuleString,
16 key: *mut raw::RedisModuleKey,
17 private_data: *mut ::std::os::raw::c_void,
18) {
19 let context = Context::new(ctx);
20 let key_name = RedisString::new(NonNull::new(ctx), key_name);
21 let redis_key = if key.is_null() {
22 None
23 } else {
24 Some(unsafe { RedisKey::from_raw_parts(ctx, key) })
27 };
28 let callback = unsafe { &mut *(private_data.cast::<C>()) };
29 callback(&context, &key_name, redis_key.as_ref());
30
31 mem::forget(redis_key);
34 mem::forget(key_name);
35}
36
37impl KeysCursor {
38 pub fn new() -> Self {
39 let inner_cursor = unsafe { raw::RedisModule_ScanCursorCreate.unwrap()() };
40 Self { inner_cursor }
41 }
42
43 pub fn scan<F: FnMut(&Context, &RedisString, Option<&RedisKey>)>(
44 &self,
45 ctx: &Context,
46 callback: &F,
47 ) -> bool {
48 let res = unsafe {
49 raw::RedisModule_Scan.unwrap()(
50 ctx.ctx,
51 self.inner_cursor,
52 Some(scan_callback::<F>),
53 callback as *const F as *mut c_void,
54 )
55 };
56 res != 0
57 }
58
59 pub fn restart(&self) {
60 unsafe { raw::RedisModule_ScanCursorRestart.unwrap()(self.inner_cursor) };
61 }
62}
63
64impl Default for KeysCursor {
65 fn default() -> Self {
66 Self::new()
67 }
68}
69
70impl Drop for KeysCursor {
71 fn drop(&mut self) {
72 unsafe { raw::RedisModule_ScanCursorDestroy.unwrap()(self.inner_cursor) };
73 }
74}