Skip to content

Commit 80ae411

Browse files
committed
documentation
1 parent 08fe601 commit 80ae411

File tree

1 file changed

+60
-19
lines changed

1 file changed

+60
-19
lines changed

src/context/key_scan_cursor.rs

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,70 @@ use std::{
55

66
use crate::{key::RedisKey, raw, Context, RedisString};
77

8-
/// A cursor to scan fields and values in a hash key.
8+
/// A cursor to scan field/value pairs of a (hash) key.
99
///
10-
/// This is a wrapper around the RedisModule_ScanKey function from the C API. It provides access via [`ScanKeyCursor::foreach] and provides
11-
/// a Rust iterator.
10+
/// This is a wrapper around the [RedisModule_ScanKey](https://redis.io/docs/latest/develop/reference/modules/modules-api-ref/#redismodule_scankey)
11+
/// function from the C API. It provides access via [`ScanKeyCursor::foreach`] and provides a Rust iterator via [`ScanKeyCursor::iter`].
12+
///
13+
/// Use the former if the operation can be performed in the callback, as it is more efficient. Use the latter if you need to collect the results and/or
14+
/// want to have access to the Rust iterator API.
1215
///
13-
/// Example usage:
16+
/// ## Example usage
17+
///
18+
/// Here we show how to extract values to communicate them back to the Redis client. We assume that the following hash key is setup:
19+
///
1420
/// ```no_run
15-
///
21+
/// HSET user:123 name Alice age 29 location Austin
1622
/// ```
23+
///
24+
/// For using the `foreach` method:
25+
///
26+
/// ```no_run
27+
/// fn example_scan_key_foreach(ctx: &Context) -> RedisResult {
28+
/// let key = ctx.open_key_with_flags("user:123", KeyFlags::NOEFFECTS | KeyFlags::NOEXPIRE | KeyFlags::ACCESS_EXPIRED );
29+
/// let cursor = ScanKeyCursor::new(key);
30+
///
31+
/// let res = RefCell::new(Vec::new());
32+
/// cursor.foreach(|_key, field, value| {
33+
/// let mut res = res.borrow_mut();
34+
/// res.push(RedisValue::BulkRedisString(field.clone()));
35+
/// res.push(RedisValue::BulkRedisString(value.clone()));
36+
/// });
1737
///
18-
/// The iterator yields tuples of (field: RedisString, value: RedisString).
19-
///
20-
/// ## Implementation notes
21-
///
22-
/// The `RedisModule_ScanKey` function from the C API uses a callback to return the field and value strings. We
23-
/// distinguish two cases:
24-
///
25-
/// 1. Either the callback is called once,
26-
/// 2. or multiple times
27-
///
28-
/// and this depends if a rehash happens during the scan.
38+
/// Ok(RedisValue::Array(res.take()))
39+
/// }
40+
/// ```
41+
///
42+
/// For using the `iter` method:
43+
///
44+
/// ```no_run
45+
/// fn example_scan_key_foreach(ctx: &Context) -> RedisResult {
46+
/// let mut res = Vec::new();
47+
/// let key = ctx.open_key_with_flags("user:123", KeyFlags::NOEFFECTS | KeyFlags::NOEXPIRE | KeyFlags::ACCESS_EXPIRED );
48+
/// let cursor = ScanKeyCursor::new(key);
49+
/// for (field, value) in cursor.iter().enumerate() {
50+
/// res.push(RedisValue::BulkRedisString(field));
51+
/// res.push(RedisValue::BulkRedisString(value));
52+
/// }
53+
/// Ok(RedisValue::Array(res))
54+
/// }
55+
/// ```
56+
///
57+
/// Both methods will produce the following output:
58+
///
59+
/// ```text
60+
/// 1) "name"
61+
/// 2) "Alice"
62+
/// 3) "age"
63+
/// 4) "29"
64+
/// 5) "location"
65+
/// 6) "Austin"
66+
/// ```
2967
pub struct ScanKeyCursor {
3068
key: RedisKey,
3169
inner_cursor: *mut raw::RedisModuleScanCursor,
3270
}
3371

34-
//type ScanKeyCallback<F> = F where F: FnMut(&RedisKey, &RedisString, &RedisString);
35-
3672
impl ScanKeyCursor {
3773
pub fn new(key: RedisKey) -> Self {
3874
let inner_cursor = unsafe { raw::RedisModule_ScanCursorCreate.unwrap()() };
@@ -85,20 +121,25 @@ pub struct ScanKeyCursorIterator<'a> {
85121
/// The cursor that is used for the iteration
86122
cursor: &'a ScanKeyCursor,
87123

124+
// todo: use a vector with stack allocation for better performance
88125
/// Buffer to hold the uninitialized data if the C callback is called multiple times.
89126
buf: Vec<ScanKeyIteratorItem>,
90127

91128
/// Stores a flag that indicates if scan_key needs to be called again
92129
last_call: bool,
93130
}
94131

132+
/// The state machine for the iterator
95133
enum IteratorState {
96134
NeedToCallScanKey,
97135
HasBufferedItems,
98136
Done,
99137
}
138+
139+
/// A stack slot that is used to pass data from the C callback to the iterator.
140+
///
141+
/// It is mainly used to access the context and to store the buffered items.
100142
struct StackSlot<'a> {
101-
//state: StackSlotState,
102143
ctx: Context,
103144
buf: &'a mut Vec<ScanKeyIteratorItem>,
104145
}

0 commit comments

Comments
 (0)