1 #[macro_export] 2 macro_rules! redis_command { 3 ($ctx:expr, 4 $command_name:expr, 5 $command_handler:expr, 6 $command_flags:expr, 7 $firstkey:expr, 8 $lastkey:expr, 9 $keystep:expr) => {{ 10 let name = CString::new($command_name).unwrap(); 11 let flags = CString::new($command_flags).unwrap(); 12 13 ///////////////////// 14 extern "C" fn __do_command( 15 ctx: *mut $crate::raw::RedisModuleCtx, 16 argv: *mut *mut $crate::raw::RedisModuleString, 17 argc: c_int, 18 ) -> c_int { 19 let context = $crate::Context::new(ctx); 20 21 let args = $crate::decode_args(ctx, argv, argc); 22 let response = $command_handler(&context, args); 23 context.reply(response) as c_int 24 } 25 ///////////////////// 26 27 if unsafe { 28 $crate::raw::RedisModule_CreateCommand.unwrap()( 29 $ctx, 30 name.as_ptr(), 31 Some(__do_command), 32 flags.as_ptr(), 33 $firstkey, 34 $lastkey, 35 $keystep, 36 ) 37 } == $crate::raw::Status::Err as c_int 38 { 39 return $crate::raw::Status::Err as c_int; 40 } 41 }}; 42 } 43 44 #[cfg(feature = "experimental-api")] 45 #[macro_export] 46 macro_rules! redis_event_handler { 47 ( 48 $ctx: expr, 49 $event_type: expr, 50 $event_handler: expr 51 ) => {{ 52 extern "C" fn __handle_event( 53 ctx: *mut $crate::raw::RedisModuleCtx, 54 event_type: c_int, 55 event: *const c_char, 56 key: *mut $crate::raw::RedisModuleString, 57 ) -> c_int { 58 let context = $crate::Context::new(ctx); 59 60 let redis_key = $crate::RedisString::from_ptr(key).unwrap(); 61 let event_str = unsafe { CStr::from_ptr(event) }; 62 $event_handler( 63 &context, 64 $crate::NotifyEvent::from_bits_truncate(event_type), 65 event_str.to_str().unwrap(), 66 redis_key, 67 ); 68 69 $crate::raw::Status::Ok as c_int 70 } 71 72 if unsafe { 73 $crate::raw::RedisModule_SubscribeToKeyspaceEvents.unwrap()( 74 $ctx, 75 $event_type.bits(), 76 Some(__handle_event), 77 ) 78 } == $crate::raw::Status::Err as c_int 79 { 80 return $crate::raw::Status::Err as c_int; 81 } 82 }}; 83 } 84 85 #[macro_export] 86 macro_rules! redis_module { 87 ( 88 name: $module_name:expr, 89 version: $module_version:expr, 90 data_types: [ 91 $($data_type:ident),* $(,)* 92 ], 93 $(init: $init_func:ident,)* $(,)* 94 $(deinit: $deinit_func:ident,)* $(,)* 95 commands: [ 96 $([ 97 $name:expr, 98 $command:expr, 99 $flags:expr, 100 $firstkey:expr, 101 $lastkey:expr, 102 $keystep:expr 103 ]),* $(,)* 104 ] $(,)* 105 $(event_handlers: [ 106 $([ 107 $(@$event_type:ident) +: 108 $event_handler:expr 109 ]),* $(,)* 110 ])? 111 ) => { 112 extern "C" fn __info_func( 113 ctx: *mut $crate::raw::RedisModuleInfoCtx, 114 for_crash_report: i32, 115 ) { 116 $crate::base_info_func(ctx, for_crash_report == 1); 117 } 118 119 #[no_mangle] 120 #[allow(non_snake_case)] 121 pub extern "C" fn RedisModule_OnLoad( 122 ctx: *mut $crate::raw::RedisModuleCtx, 123 argv: *mut *mut $crate::raw::RedisModuleString, 124 argc: std::os::raw::c_int, 125 ) -> std::os::raw::c_int { 126 use std::os::raw::{c_int, c_char}; 127 use std::ffi::{CString, CStr}; 128 129 use $crate::raw; 130 use $crate::RedisString; 131 132 // We use a statically sized buffer to avoid allocating. 133 // This is needed since we use a custom allocator that relies on the Redis allocator, 134 // which isn't yet ready at this point. 135 let mut name_buffer = [0; 64]; 136 unsafe { 137 std::ptr::copy( 138 $module_name.as_ptr(), 139 name_buffer.as_mut_ptr(), 140 $module_name.len(), 141 ); 142 } 143 144 let module_version = $module_version as c_int; 145 146 if unsafe { raw::Export_RedisModule_Init( 147 ctx, 148 name_buffer.as_ptr() as *const c_char, 149 module_version, 150 raw::REDISMODULE_APIVER_1 as c_int, 151 ) } == raw::Status::Err as c_int { return raw::Status::Err as c_int; } 152 153 let context = $crate::Context::new(ctx); 154 let args = $crate::decode_args(ctx, argv, argc); 155 156 $( 157 if $init_func(&context, &args) == $crate::Status::Err { 158 return $crate::Status::Err as c_int; 159 } 160 )* 161 162 $( 163 if (&$data_type).create_data_type(ctx).is_err() { 164 return raw::Status::Err as c_int; 165 } 166 )* 167 168 $( 169 redis_command!(ctx, $name, $command, $flags, $firstkey, $lastkey, $keystep); 170 )* 171 172 $( 173 $( 174 redis_event_handler!(ctx, $(raw::NotifyEvent::$event_type |)+ raw::NotifyEvent::empty(), $event_handler); 175 )* 176 )? 177 178 raw::register_info_function(ctx, Some(__info_func)); 179 180 raw::Status::Ok as c_int 181 } 182 183 #[no_mangle] 184 #[allow(non_snake_case)] 185 pub extern "C" fn RedisModule_OnUnload( 186 ctx: *mut $crate::raw::RedisModuleCtx 187 ) -> std::os::raw::c_int { 188 use std::os::raw::c_int; 189 190 let context = $crate::Context::new(ctx); 191 $( 192 if $deinit_func(&context) == $crate::Status::Err { 193 return $crate::Status::Err as c_int; 194 } 195 )* 196 197 $crate::raw::Status::Ok as c_int 198 } 199 } 200 } 201