Skip to content

Commit 42d4953

Browse files
committed
review comments
1 parent af85a30 commit 42d4953

File tree

4 files changed

+44
-28
lines changed

4 files changed

+44
-28
lines changed

examples/scan_keys.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
// This example shows the usage of the scan functionality of the Rust Redis Module API Wrapper.
2-
//
2+
//
33
// The example implements three commands:
4-
//
4+
//
55
// 1. `scan_keys` - scans all keys in the database and returns their names as an array of RedisString.
66
// 2. `scan_key <key>` - scans all fields by using a closure and a while loop, thus allowing an early stop. Don't use the early stop but collects all the field/value pairs as an array of RedisString.
77
// 3. `scan_key_for_each <key>` - scans all fields and values in a hash key using a closure that stores the field/value pairs as an array of RedisString.
88

99
use redis_module::{
10-
key::{KeyFlags, RedisKey}, redis_module, Context, KeysCursor, RedisError, RedisResult, RedisString, RedisValue, ScanKeyCursor
10+
key::{KeyFlags, RedisKey},
11+
redis_module, Context, KeysCursor, RedisError, RedisResult, RedisString, RedisValue,
12+
ScanKeyCursor,
1113
};
1214

1315
/// Scans all keys in the database and returns their names as an array of RedisString.
@@ -32,8 +34,11 @@ fn scan_key(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
3234
}
3335

3436
let key_name = &args[1];
35-
let key = ctx.open_key_with_flags(key_name, KeyFlags::NOEFFECTS | KeyFlags::NOEXPIRE | KeyFlags::ACCESS_EXPIRED );
36-
let cursor = ScanKeyCursor::new(key);
37+
let key = ctx.open_key_with_flags(
38+
key_name,
39+
KeyFlags::NOEFFECTS | KeyFlags::NOEXPIRE | KeyFlags::ACCESS_EXPIRED,
40+
);
41+
let cursor = ScanKeyCursor::new(key);
3742

3843
let mut res = Vec::new();
3944
while cursor.scan(|_key, field, value| {
@@ -55,9 +60,12 @@ fn scan_key_for_each(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
5560
}
5661

5762
let key_name = &args[1];
58-
let key = ctx.open_key_with_flags(key_name, KeyFlags::NOEFFECTS | KeyFlags::NOEXPIRE | KeyFlags::ACCESS_EXPIRED );
59-
let cursor = ScanKeyCursor::new(key);
60-
63+
let key = ctx.open_key_with_flags(
64+
key_name,
65+
KeyFlags::NOEFFECTS | KeyFlags::NOEXPIRE | KeyFlags::ACCESS_EXPIRED,
66+
);
67+
let cursor = ScanKeyCursor::new(key);
68+
6169
let mut res = Vec::new();
6270
cursor.for_each(|_key, field, value| {
6371
res.push(RedisValue::BulkRedisString(field.clone()));
@@ -67,7 +75,6 @@ fn scan_key_for_each(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
6775
Ok(RedisValue::Array(res))
6876
}
6977

70-
7178
//////////////////////////////////////////////////////
7279

7380
redis_module! {

src/context/key_cursor.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,21 @@ impl ScanKeyCursor {
6363
unsafe { raw::RedisModule_ScanCursorRestart.unwrap()(self.inner_cursor) };
6464
}
6565

66+
/// Implements a call to `RedisModule_ScanKey` and calls the given closure for each callback invocation by ScanKey.
67+
/// Returns `true` if there are more fields to scan, `false` otherwise.
68+
///
69+
/// The callback may be called multiple times per `RedisModule_ScanKey` invocation.
70+
///
71+
/// ## Example
72+
///
73+
/// ```
74+
/// while cursor.scan(|_key, field, value| {
75+
/// // do something with field and value
76+
/// }) {
77+
/// // do something between scans if needed, like an early stop
78+
/// }
6679
pub fn scan<F: FnMut(&RedisKey, &RedisString, &RedisString)>(&self, f: F) -> bool {
67-
// The following is the callback definition. The callback may be called multiple times per `RedisModule_ScanKey` invocation.
68-
// The callback is used by [`ScanKeyCursor::scan`] and [`ScanKeyCursor::for_each`] as argument to `RedisModule_ScanKey`.
69-
//
70-
// The `data` pointer is the closure given to [`ScanKeyCursor::scan`] or [`ScanKeyCursor::for_each`].
71-
// The callback forwards references to the key, field and value to that closure.
72-
unsafe extern "C" fn scan_callback<
73-
F: FnMut(&RedisKey, &RedisString, &RedisString),
74-
>(
80+
unsafe extern "C" fn scan_callback<F: FnMut(&RedisKey, &RedisString, &RedisString)>(
7581
key: *mut raw::RedisModuleKey,
7682
field: *mut raw::RedisModuleString,
7783
value: *mut raw::RedisModuleString,
@@ -95,8 +101,10 @@ impl ScanKeyCursor {
95101

96102
// Safety: The c-side initialized the function ptr and it is is never changed,
97103
// i.e. after module initialization the function pointers stay valid till the end of the program.
104+
let scan_key = unsafe { raw::RedisModule_ScanKey.unwrap() };
105+
98106
let res = unsafe {
99-
raw::RedisModule_ScanKey.unwrap()(
107+
scan_key(
100108
self.key.key_inner,
101109
self.inner_cursor,
102110
Some(scan_callback::<F>),
@@ -107,7 +115,8 @@ impl ScanKeyCursor {
107115
res != 0
108116
}
109117

110-
/// Implements a callback based for_each loop over all fields and values in the hash key, use that for optimal performance.
118+
/// Implements a callback based for_each loop over all fields and values in the hash key.
119+
/// If you need more control, e.g. stopping after a scan invocation, then use [`ScanKeyCursor::scan`] directly.
111120
pub fn for_each<F: FnMut(&RedisKey, &RedisString, &RedisString)>(&self, mut f: F) {
112121
while self.scan(&mut f) {
113122
// do nothing, the callback does the work

src/redismodule.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,19 @@ impl RedisString {
162162
}
163163

164164
/// Create a RedisString from a raw C string and length. The String will be copied.
165-
///
165+
///
166166
/// # Safety
167-
/// The caller must ensure that the provided pointer is valid and points to a memory region
167+
/// The caller must ensure that the provided pointer is valid and points to a memory region
168168
/// that is at least `len` bytes long.
169169
#[allow(clippy::not_unsafe_ptr_arg_deref)]
170-
pub unsafe fn from_raw_parts(ctx: Option<NonNull<raw::RedisModuleCtx>>, s: *const c_char, len: libc::size_t) -> Self {
170+
pub unsafe fn from_raw_parts(
171+
ctx: Option<NonNull<raw::RedisModuleCtx>>,
172+
s: *const c_char,
173+
len: libc::size_t,
174+
) -> Self {
171175
let ctx = ctx.map_or(std::ptr::null_mut(), |v| v.as_ptr());
172176

173-
let inner = unsafe {
174-
raw::RedisModule_CreateString.unwrap()(ctx, s, len)
175-
};
177+
let inner = unsafe { raw::RedisModule_CreateString.unwrap()(ctx, s, len) };
176178

177179
Self { ctx, inner }
178180
}

tests/integration.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,7 @@ fn test_scan_key() -> Result<()> {
210210
.query::<()>(&mut con)
211211
.with_context(|| "failed to hset")?;
212212

213-
let res: Vec<String> = redis::cmd("scan_key")
214-
.arg(&["user:123"])
215-
.query(&mut con)?;
213+
let res: Vec<String> = redis::cmd("scan_key").arg(&["user:123"]).query(&mut con)?;
216214
assert_eq!(&res, &["name", "Alice", "age", "29", "location", "Austin"]);
217215
Ok(())
218216
}

0 commit comments

Comments
 (0)