Skip to main content

redis_module/context/
keys_cursor.rs

1use 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        // Safety: The returned `RedisKey` does not outlive this callbacks and so by necessity
25        // the pointers passed in as parameters are valid for its entire lifetime.
26        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    // We don't own any of the passed in pointers and have just created "temporary RAII types".
32    // We must ensure we don't run their destructors here.
33    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}