redis_module_ext/data_type/
mod.rs

1use std::collections::HashMap;
2use std::ffi::CString;
3use std::sync::{LazyLock, RwLock};
4
5use redis_module::native_types::RedisType;
6use redis_module::raw;
7
8mod io;
9pub use io::*;
10mod methods;
11pub use methods::*;
12
13struct RedisModuleType {
14    ptr: *mut raw::RedisModuleType,
15}
16
17unsafe impl Send for RedisModuleType {}
18unsafe impl Sync for RedisModuleType {}
19
20pub trait RedisDataType: Sized {
21    #[doc(hidden)]
22    const NAME: &'static str;
23    #[doc(hidden)]
24    const VERSION: i32;
25
26    #[doc(hidden)]
27    fn module_methods(ctx: &redis_module::Context) -> raw::RedisModuleTypeMethods;
28
29    #[doc(hidden)]
30    fn register(ctx: &redis_module::Context) -> Result<(), &'static str> {
31        if Self::NAME.len() != 9 {
32            let msg = "Redis requires the length of native type names to be exactly 9 characters";
33            ctx.log_warning(&format!("{msg}, name is: '{}'", Self::NAME));
34            return Err(msg);
35        }
36
37        let name = CString::new(Self::NAME).unwrap();
38
39        let redis_type = unsafe {
40            raw::RedisModule_CreateDataType.unwrap()(
41                ctx.ctx,
42                name.as_ptr(),
43                Self::VERSION, // Encoding version
44                &mut Self::module_methods(ctx),
45            )
46        };
47
48        if Self::redis_ty(redis_type).is_none() {
49            ctx.log_warning("Error: created data type is null");
50            return Err("Error: created data type is null");
51        }
52
53        ctx.log_debug(format!("Created new data type '{}'", Self::NAME).as_str());
54
55        Ok(())
56    }
57
58    #[doc(hidden)]
59    fn redis_ty(ptr: *mut raw::RedisModuleType) -> Option<redis_module::native_types::RedisType> {
60        static TYPE_REGISTRY: LazyLock<RwLock<HashMap<&'static str, RedisModuleType>>> = LazyLock::new(Default::default);
61
62        if !ptr.is_null() {
63            TYPE_REGISTRY.write().unwrap().insert(Self::NAME, RedisModuleType { ptr });
64        }
65
66        let ptr = TYPE_REGISTRY.read().unwrap().get(Self::NAME)?.ptr;
67
68        let ty = RedisType::new(Self::NAME, Self::VERSION, unsafe { std::mem::zeroed() });
69        ty.raw_type.replace(ptr);
70        Some(ty)
71    }
72}