redis_module_ext/data_type/
methods.rs1use std::borrow::Borrow;
2use std::ffi::{CStr, CString};
3use std::ops::Add;
4use std::ptr::NonNull;
5
6use redis_module::defrag::DefragContext;
7use redis_module::{RedisResult, RedisString, raw};
8
9use crate::data_type::io::{AofRewriteIo, RdbLoadIo, RdbSaveIo, RedisModuleDigest, RedisModuleKeyOptCtx};
10
11#[doc(hidden)]
12pub trait CStrConv {
13 fn into_cstr(self) -> Option<impl Borrow<std::ffi::CStr>>;
14}
15
16impl CStrConv for String {
17 fn into_cstr(self) -> Option<impl Borrow<std::ffi::CStr>> {
18 std::ffi::CString::new(self).ok()
19 }
20}
21
22impl CStrConv for &String {
23 fn into_cstr(self) -> Option<impl Borrow<std::ffi::CStr>> {
24 std::ffi::CString::new(self.as_bytes()).ok()
25 }
26}
27
28impl CStrConv for &str {
29 fn into_cstr(self) -> Option<impl Borrow<std::ffi::CStr>> {
30 std::ffi::CString::new(self.as_bytes()).ok()
31 }
32}
33
34impl CStrConv for CString {
35 fn into_cstr(self) -> Option<impl Borrow<std::ffi::CStr>> {
36 Some(self)
37 }
38}
39
40impl CStrConv for &CString {
41 fn into_cstr(self) -> Option<impl Borrow<std::ffi::CStr>> {
42 Some(self.as_ref())
43 }
44}
45
46impl CStrConv for &CStr {
47 fn into_cstr(self) -> Option<impl Borrow<std::ffi::CStr>> {
48 Some(self)
49 }
50}
51
52impl<'a, T> CStrConv for &&'a T
53where
54 &'a T: CStrConv,
55{
56 fn into_cstr(self) -> Option<impl Borrow<std::ffi::CStr>> {
57 (**self).into_cstr()
58 }
59}
60
61pub type RdbLoadFn<T> = fn(&mut RdbLoadIo, i32) -> RedisResult<T>;
62
63pub trait RdbLoad<T>: Sized {
64 const FN: RdbLoadFn<Self>;
65
66 fn extern_fn() -> raw::RedisModuleTypeLoadFunc {
67 unsafe extern "C" fn rdb_load<T, S: RdbLoad<T>>(
68 rdb: *mut raw::RedisModuleIO,
69 encver: ::std::os::raw::c_int,
70 ) -> *mut ::std::os::raw::c_void {
71 let Some(rdb) = NonNull::new(rdb) else {
72 return std::ptr::null_mut();
73 };
74
75 let mut io = unsafe { RdbLoadIo::new(rdb) };
76 match S::FN(&mut io, encver) {
77 Err(err) => {
78 io.log_warning(err.to_string());
79 std::ptr::null_mut()
80 }
81 Ok(v) => Box::into_raw(Box::new(v)).cast(),
82 }
83 }
84
85 Some(rdb_load::<T, Self>)
86 }
87}
88
89pub type RdbSaveFn<T> = fn(&mut T, &mut RdbSaveIo);
90
91pub trait RdbSave<T>: Sized {
92 const FN: RdbSaveFn<Self>;
93
94 fn extern_fn() -> raw::RedisModuleTypeSaveFunc {
95 unsafe extern "C" fn rdb_save<T, S: RdbSave<T>>(rdb: *mut raw::RedisModuleIO, value: *mut ::std::os::raw::c_void) {
96 let Some(rdb) = NonNull::new(rdb) else {
97 return;
98 };
99
100 if let Some(value) = unsafe { value.cast::<S>().as_mut() } {
101 let mut io = unsafe { RdbSaveIo::new(rdb) };
102 S::FN(value, &mut io)
103 }
104 }
105
106 Some(rdb_save::<T, Self>)
107 }
108}
109
110pub type AofRewriteFn<T> = fn(&mut T, &mut AofRewriteIo, RedisString) -> RedisResult<()>;
111
112pub trait AofRewrite<T>: Sized {
113 const FN: AofRewriteFn<Self>;
114
115 fn extern_fn() -> raw::RedisModuleTypeRewriteFunc {
116 unsafe extern "C" fn aof_rewrite<T, S: AofRewrite<T>>(
117 aof: *mut raw::RedisModuleIO,
118 key: *mut raw::RedisModuleString,
119 value: *mut ::std::os::raw::c_void,
120 ) {
121 let Some(aof) = NonNull::new(aof) else {
122 return;
123 };
124
125 if let Some(value) = unsafe { value.cast::<S>().as_mut() } {
126 let mut io = unsafe { AofRewriteIo::new(aof) };
127 if let Err(err) = S::FN(value, &mut io, RedisString::new(None, key)) {
128 io.log_warning(err.to_string());
129 }
130 }
131 }
132
133 Some(aof_rewrite::<T, Self>)
134 }
135}
136
137pub type MemUsageFn<T> = fn(&T) -> usize;
138
139pub trait MemUsage<T>: Sized {
140 const FN: MemUsageFn<Self>;
141
142 fn extern_fn() -> raw::RedisModuleTypeMemUsageFunc {
143 unsafe extern "C" fn mem_usage<T, S: MemUsage<T>>(value: *const ::std::os::raw::c_void) -> usize {
144 if let Some(value) = unsafe { value.cast::<S>().as_ref() } {
145 S::FN(value)
146 } else {
147 0
148 }
149 }
150
151 Some(mem_usage::<T, Self>)
152 }
153}
154
155pub type DigestFn<T> = fn(&mut T, &mut RedisModuleDigest);
156
157pub trait Digest<T>: Sized {
158 const FN: DigestFn<Self>;
159
160 fn extern_fn() -> raw::RedisModuleTypeDigestFunc {
161 unsafe extern "C" fn digest<T, S: Digest<T>>(
162 digest: *mut raw::RedisModuleDigest,
163 value: *mut ::std::os::raw::c_void,
164 ) {
165 let Some(digest) = NonNull::new(digest) else {
166 return;
167 };
168
169 if let Some(value) = unsafe { value.cast::<S>().as_mut() } {
170 let mut io = unsafe { RedisModuleDigest::new(digest) };
171 S::FN(value, &mut io)
172 }
173 }
174
175 Some(digest::<T, Self>)
176 }
177}
178
179pub type AuxLoadFn = fn(&mut RdbLoadIo, i32, i32) -> RedisResult<i32>;
180
181pub trait AuxLoad<T>: Sized {
182 const FN: AuxLoadFn;
183
184 fn extern_fn() -> raw::RedisModuleTypeAuxLoadFunc {
185 unsafe extern "C" fn aux_load<T, S: AuxLoad<T>>(rdb: *mut raw::RedisModuleIO, version: i32, when: i32) -> i32 {
186 let Some(rdb) = NonNull::new(rdb) else {
187 return 0;
188 };
189
190 let mut io = unsafe { RdbLoadIo::new(rdb) };
191 match S::FN(&mut io, version, when) {
192 Ok(v) => v,
193 Err(err) => {
194 io.log_warning(err.to_string());
195 0
196 }
197 }
198 }
199
200 Some(aux_load::<T, Self>)
201 }
202}
203
204pub type AuxSaveFn = fn(&mut RdbSaveIo, i32);
205
206pub trait AuxSave<T>: Sized {
207 const FN: AuxSaveFn;
208
209 fn extern_fn() -> raw::RedisModuleTypeAuxSaveFunc {
210 unsafe extern "C" fn aux_save<T, S: AuxSave<T>>(rdb: *mut raw::RedisModuleIO, when: i32) {
211 let Some(rdb) = NonNull::new(rdb) else {
212 return;
213 };
214
215 let mut io = unsafe { RdbSaveIo::new(rdb) };
216 S::FN(&mut io, when)
217 }
218
219 Some(aux_save::<T, Self>)
220 }
221}
222
223pub type FreeEffortFn<T> = fn(&T, RedisString) -> usize;
224
225pub trait FreeEffort<T>: Sized {
226 const FN: FreeEffortFn<Self>;
227
228 fn extern_fn() -> raw::RedisModuleTypeFreeEffortFunc {
229 unsafe extern "C" fn free_effort<T, S: FreeEffort<T>>(
230 key: *mut raw::RedisModuleString,
231 value: *const ::std::os::raw::c_void,
232 ) -> usize {
233 if let Some(value) = unsafe { value.cast::<S>().as_ref() } {
234 S::FN(value, RedisString::new(None, key))
235 } else {
236 0
237 }
238 }
239
240 Some(free_effort::<T, Self>)
241 }
242}
243
244pub type UnlinkFn<T> = fn(&T, RedisString);
245
246pub trait Unlink<T>: Sized {
247 const FN: UnlinkFn<Self>;
248
249 fn extern_fn() -> raw::RedisModuleTypeUnlinkFunc {
250 unsafe extern "C" fn unlink<T, S: Unlink<T>>(
251 key: *mut raw::RedisModuleString,
252 value: *const ::std::os::raw::c_void,
253 ) {
254 if let Some(value) = unsafe { value.cast::<S>().as_ref() } {
255 S::FN(value, RedisString::new(None, key))
256 }
257 }
258
259 Some(unlink::<T, Self>)
260 }
261}
262
263pub type CopyFn<T> = fn(&T, RedisString, RedisString) -> Option<T>;
264
265pub trait Copy<T>: Sized {
266 const FN: CopyFn<Self>;
267
268 fn extern_fn() -> raw::RedisModuleTypeCopyFunc {
269 unsafe extern "C" fn copy<T, S: Copy<T>>(
270 from_key: *mut raw::RedisModuleString,
271 to_key: *mut raw::RedisModuleString,
272 value: *const ::std::os::raw::c_void,
273 ) -> *mut ::std::os::raw::c_void {
274 let value = if let Some(value) = unsafe { value.cast::<S>().as_ref() } {
275 S::FN(value, RedisString::new(None, from_key), RedisString::new(None, to_key))
276 } else {
277 None
278 };
279
280 value.map(Box::new).map(Box::into_raw).unwrap_or(std::ptr::null_mut()).cast()
281 }
282
283 Some(copy::<T, Self>)
284 }
285}
286
287pub type DefragFn<T> = fn(&mut T, DefragContext, RedisString) -> i32;
288
289pub trait Defrag<T>: Sized {
290 const FN: DefragFn<Self>;
291
292 fn extern_fn() -> raw::RedisModuleTypeDefragFunc {
293 unsafe extern "C" fn defrag<T, S: Defrag<T>>(
294 ctx: *mut raw::RedisModuleDefragCtx,
295 key: *mut raw::RedisModuleString,
296 value: *mut *mut ::std::os::raw::c_void,
297 ) -> i32 {
298 if value.is_null() {
299 return 0;
300 }
301
302 let value = value as *mut *mut S;
303
304 let ctx = unsafe { DefragContext::new(ctx) };
305 unsafe { value.write(ctx.defrag_realloc(*value)) };
306
307 if let Some(value) = unsafe { (*value).as_mut() } {
308 S::FN(value, ctx, RedisString::new(None, key))
309 } else {
310 0
311 }
312 .add(1)
313 }
314
315 Some(defrag::<T, Self>)
316 }
317}
318
319pub type MemUsage2Fn<T> = fn(&T, &mut RedisModuleKeyOptCtx, usize) -> usize;
320
321pub trait MemUsage2<T>: Sized {
322 const FN: MemUsage2Fn<Self>;
323
324 fn extern_fn() -> raw::RedisModuleTypeMemUsageFunc2 {
325 unsafe extern "C" fn mem_usage2<T, S: MemUsage2<T>>(
326 ctx: *mut raw::RedisModuleKeyOptCtx,
327 value: *const ::std::os::raw::c_void,
328 sample_size: usize,
329 ) -> usize {
330 let Some(ctx) = NonNull::new(ctx) else {
331 return 0;
332 };
333
334 if let Some(value) = unsafe { value.cast::<S>().as_ref() } {
335 let mut io = unsafe { RedisModuleKeyOptCtx::new(ctx) };
336 S::FN(value, &mut io, sample_size)
337 } else {
338 0
339 }
340 }
341
342 Some(mem_usage2::<T, Self>)
343 }
344}
345
346pub type FreeEffort2Fn<T> = fn(&T, &mut RedisModuleKeyOptCtx) -> usize;
347
348pub trait FreeEffort2<T>: Sized {
349 const FN: FreeEffort2Fn<Self>;
350
351 fn extern_fn() -> raw::RedisModuleTypeFreeEffortFunc2 {
352 unsafe extern "C" fn free_effort2<T, S: FreeEffort2<T>>(
353 ctx: *mut raw::RedisModuleKeyOptCtx,
354 value: *const ::std::os::raw::c_void,
355 ) -> usize {
356 let Some(ctx) = NonNull::new(ctx) else {
357 return 0;
358 };
359
360 if let Some(value) = unsafe { value.cast::<S>().as_ref() } {
361 let mut io = unsafe { RedisModuleKeyOptCtx::new(ctx) };
362 S::FN(value, &mut io)
363 } else {
364 0
365 }
366 }
367
368 Some(free_effort2::<T, Self>)
369 }
370}
371
372pub type Unlink2Fn<T> = fn(&T, &mut RedisModuleKeyOptCtx);
373
374pub trait Unlink2<T>: Sized {
375 const FN: Unlink2Fn<Self>;
376
377 fn extern_fn() -> raw::RedisModuleTypeUnlinkFunc2 {
378 unsafe extern "C" fn unlink2<T, S: Unlink2<T>>(
379 ctx: *mut raw::RedisModuleKeyOptCtx,
380 value: *const ::std::os::raw::c_void,
381 ) {
382 let Some(ctx) = NonNull::new(ctx) else {
383 return;
384 };
385
386 if let Some(value) = unsafe { value.cast::<S>().as_ref() } {
387 let mut io = unsafe { RedisModuleKeyOptCtx::new(ctx) };
388 S::FN(value, &mut io)
389 }
390 }
391
392 Some(unlink2::<T, Self>)
393 }
394}
395
396pub type Copy2Fn<T> = fn(&T, &mut RedisModuleKeyOptCtx) -> Option<T>;
397
398pub trait Copy2<T>: Sized {
399 const FN: Copy2Fn<Self>;
400
401 fn extern_fn() -> raw::RedisModuleTypeCopyFunc2 {
402 unsafe extern "C" fn copy2<T, S: Copy2<T>>(
403 ctx: *mut raw::RedisModuleKeyOptCtx,
404 value: *const ::std::os::raw::c_void,
405 ) -> *mut ::std::os::raw::c_void {
406 let Some(ctx) = NonNull::new(ctx) else {
407 return std::ptr::null_mut();
408 };
409
410 let value = if let Some(value) = unsafe { value.cast::<S>().as_ref() } {
411 let mut io = unsafe { RedisModuleKeyOptCtx::new(ctx) };
412 S::FN(value, &mut io)
413 } else {
414 None
415 };
416
417 value.map(Box::new).map(Box::into_raw).unwrap_or(std::ptr::null_mut()).cast()
418 }
419
420 Some(copy2::<T, Self>)
421 }
422}
423
424pub type AuxSave2Fn = fn(&mut RdbSaveIo, i32);
425
426pub trait AuxSave2<T>: Sized {
427 const FN: AuxSave2Fn;
428
429 fn extern_fn() -> raw::RedisModuleTypeAuxSaveFunc {
430 unsafe extern "C" fn aux_save2<T, S: AuxSave2<T>>(rdb: *mut raw::RedisModuleIO, when: i32) {
431 let Some(rdb) = NonNull::new(rdb) else {
432 return;
433 };
434
435 let mut io = unsafe { RdbSaveIo::new(rdb) };
436 S::FN(&mut io, when)
437 }
438
439 Some(aux_save2::<T, Self>)
440 }
441}