dtypes/redis/rwlock/
writer.rs1use crate::redis::rwlock::constants::{LOAD_SCRIPT, STORE_SCRIPT, WRITER_LOCK_DROP};
2use crate::redis::rwlock::RwLockError;
3use crate::redis::{sync::RwLock, types::Generic};
4use serde::de::DeserializeOwned;
5use serde::Serialize;
6use std::ops::{Deref, DerefMut};
7
8pub struct RwLockWriteGuard<'a, T> {
9 lock: &'a mut RwLock<T>,
10 conn: redis::Connection,
11 uuid: usize,
12}
13
14impl<'a, T> RwLockWriteGuard<'a, T>
15where
16 T: Serialize + DeserializeOwned,
17{
18 pub(crate) fn new(lock: &'a mut RwLock<T>, uuid: usize, conn: redis::Connection) -> Self {
19 Self { lock, uuid, conn }
20 }
21
22 pub fn store(&mut self, value: T) -> Result<(), RwLockError>
26 where
27 T: Serialize,
28 {
29 let script = redis::Script::new(STORE_SCRIPT);
30 let result: i8 = script
31 .arg(&self.lock.data.key)
32 .arg(self.uuid)
33 .arg(serde_json::to_string(&value).expect("Failed to serialize value"))
34 .invoke(&mut self.conn)
35 .expect("Failed to store value. You should not see this!");
36 if result == 0 {
37 return Err(RwLockError::LockExpired(self.uuid));
38 }
39 self.lock.data.cache = Some(value);
40 Ok(())
41 }
42
43 pub fn acquire(&mut self) -> &T {
47 self.lock.data.cache = self.try_get();
48 self.lock.data.cache.as_ref().unwrap()
49 }
50
51 fn try_get(&mut self) -> Option<T> {
52 let script = redis::Script::new(LOAD_SCRIPT);
53 let result: Option<String> = script
54 .arg(&self.lock.data.key)
55 .arg(self.uuid)
56 .invoke(&mut self.conn)
57 .expect("Failed to load value. You should not see this!");
58 let result = result?;
59
60 if result == "nil" {
61 return None;
62 }
63 Some(serde_json::from_str(&result).expect("Failed to deserialize value"))
64 }
65}
66
67impl<'a, T> Deref for RwLockWriteGuard<'a, T> {
68 type Target = Generic<T>;
69
70 fn deref(&self) -> &Self::Target {
71 &self.lock.data
72 }
73}
74
75impl<'a, T> DerefMut for RwLockWriteGuard<'a, T> {
76 fn deref_mut(&mut self) -> &mut Self::Target {
77 &mut self.lock.data
78 }
79}
80
81impl<'a, T> Drop for RwLockWriteGuard<'a, T> {
82 fn drop(&mut self) {
83 let mut conn = self.client.get_connection().unwrap();
84 let _: () = redis::Script::new(WRITER_LOCK_DROP)
85 .arg(&self.lock.data.key)
86 .arg(self.uuid)
87 .invoke(&mut conn)
88 .unwrap();
89 }
90}