redis_module/context/
thread_safe.rs1use std::borrow::Borrow;
2use std::cell::UnsafeCell;
3use std::ops::{Deref, DerefMut};
4use std::ptr;
5
6use crate::context::blocked::BlockedClient;
7use crate::{raw, Context, RedisResult};
8
9pub struct RedisGILGuardScope<'ctx, 'mutex, T, G: RedisLockIndicator> {
10 _context: &'ctx G,
11 mutex: &'mutex RedisGILGuard<T>,
12}
13
14impl<'ctx, 'mutex, T, G: RedisLockIndicator> Deref for RedisGILGuardScope<'ctx, 'mutex, T, G> {
15 type Target = T;
16
17 fn deref(&self) -> &Self::Target {
18 unsafe { &*self.mutex.obj.get() }
19 }
20}
21
22impl<'ctx, 'mutex, T, G: RedisLockIndicator> DerefMut for RedisGILGuardScope<'ctx, 'mutex, T, G> {
23 fn deref_mut(&mut self) -> &mut Self::Target {
24 unsafe { &mut *self.mutex.obj.get() }
25 }
26}
27
28pub unsafe trait RedisLockIndicator {}
49
50pub struct RedisGILGuard<T> {
58 obj: UnsafeCell<T>,
59}
60
61impl<T> RedisGILGuard<T> {
62 pub fn new(obj: T) -> RedisGILGuard<T> {
63 RedisGILGuard {
64 obj: UnsafeCell::new(obj),
65 }
66 }
67
68 pub fn lock<'mutex, 'ctx, G: RedisLockIndicator>(
69 &'mutex self,
70 context: &'ctx G,
71 ) -> RedisGILGuardScope<'ctx, 'mutex, T, G> {
72 RedisGILGuardScope {
73 _context: context,
74 mutex: self,
75 }
76 }
77}
78
79impl<T: Default> Default for RedisGILGuard<T> {
80 fn default() -> Self {
81 Self::new(T::default())
82 }
83}
84
85unsafe impl<T> Sync for RedisGILGuard<T> {}
86unsafe impl<T> Send for RedisGILGuard<T> {}
87
88pub struct ContextGuard {
89 ctx: Context,
90}
91
92unsafe impl RedisLockIndicator for ContextGuard {}
93
94impl Drop for ContextGuard {
95 fn drop(&mut self) {
96 unsafe {
97 raw::RedisModule_ThreadSafeContextUnlock.unwrap()(self.ctx.ctx);
98 raw::RedisModule_FreeThreadSafeContext.unwrap()(self.ctx.ctx);
99 };
100 }
101}
102
103impl Deref for ContextGuard {
104 type Target = Context;
105
106 fn deref(&self) -> &Self::Target {
107 &self.ctx
108 }
109}
110
111impl Borrow<Context> for ContextGuard {
112 fn borrow(&self) -> &Context {
113 &self.ctx
114 }
115}
116
117pub struct DetachedFromClient;
119
120pub struct ThreadSafeContext<B: Send> {
121 pub(crate) ctx: *mut raw::RedisModuleCtx,
122
123 #[allow(dead_code)]
125 blocked_client: B,
126}
127
128unsafe impl<B: Send> Send for ThreadSafeContext<B> {}
129unsafe impl<B: Send> Sync for ThreadSafeContext<B> {}
130
131impl ThreadSafeContext<DetachedFromClient> {
132 #[must_use]
133 pub fn new() -> Self {
134 let ctx = unsafe { raw::RedisModule_GetThreadSafeContext.unwrap()(ptr::null_mut()) };
135 Self {
136 ctx,
137 blocked_client: DetachedFromClient,
138 }
139 }
140}
141
142impl Default for ThreadSafeContext<DetachedFromClient> {
143 fn default() -> Self {
144 Self::new()
145 }
146}
147
148impl ThreadSafeContext<BlockedClient> {
149 #[must_use]
150 pub fn with_blocked_client(blocked_client: BlockedClient) -> Self {
151 let ctx = unsafe { raw::RedisModule_GetThreadSafeContext.unwrap()(blocked_client.inner) };
152 Self {
153 ctx,
154 blocked_client,
155 }
156 }
157
158 #[allow(clippy::must_use_candidate)]
161 pub fn reply(&self, r: RedisResult) -> raw::Status {
162 let ctx = Context::new(self.ctx);
163 ctx.reply(r)
164 }
165}
166
167impl<B: Send> ThreadSafeContext<B> {
168 pub fn lock(&self) -> ContextGuard {
171 unsafe { raw::RedisModule_ThreadSafeContextLock.unwrap()(self.ctx) };
172 let ctx = unsafe { raw::RedisModule_GetThreadSafeContext.unwrap()(ptr::null_mut()) };
173 let ctx = Context::new(ctx);
174 ContextGuard { ctx }
175 }
176}
177
178impl<B: Send> Drop for ThreadSafeContext<B> {
179 fn drop(&mut self) {
180 unsafe { raw::RedisModule_FreeThreadSafeContext.unwrap()(self.ctx) };
181 }
182}