I'm currently implementing a multi client Key-Value Store (like redis or memcached) and it allows the clients to gain exclusive access to the store.
Now I have the problem that when getting values from the shared store, it can either be protected by a RwLockWriteGoard (when exclusive access is active) or a RwLockReadGuard when not.
I did not find a ways of saving the store in a variable to perform operations later on it in a way that doesn't care about whether it's protected by a read or write guard.
Here is the simplified solution I use at the moment.
// Assume Store is like this
let store = Arc::new(RwLock::new(HashMap::new()));
// --snip--
let mut exclusive_access: Option<RwLockWriteGuard<HashMap<String, String>>> = None;
while !is_finished {
// --snip--
let response = match parse_command(&command) {
Command::Get(key) => {
let read_result = match exclusive_access {
Some(exclusive_store) => match exclusive_store.get(&key) {
Some(x) => Some(x.clone()),
None => None,
},
None => match store.read().unwrap().get(&key) {
Some(x) => Some(x.clone()),
None => None,
},
};
// simplified
read_result
}
// --snip--
};
if gain_exclusive_access {
exclusive_access = Some(store.write().unwrap());
} else {
exclusive_access = None;
}
}
If possible, I'd like to write the Command::Get(key) arm as something like this:
let store = match exclusive_access {
Some(store) => store,
None => store.read().unwrap()
};
store.get(&key)
But this doesn't work, because the two arms of that match return different Types (RwLockWriteGuard and RwLockReadGuard).
Is there a way around this, which I'm just too blind to see?
Use enum as tagged union.
use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
enum LockWrapper<'a, T>{
Read(RwLockReadGuard<'a, T>),
Write(RwLockWriteGuard<'a, T>)
}
impl<'a, T> Deref for LockWrapper<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
LockWrapper::Read(read_guard) => read_guard.deref(),
LockWrapper::Write(write_guard) => write_guard.deref()
}
}
}
fn main() {
let lock: RwLock<i32> = RwLock::new(0);
let condition = false;
let guard = match condition{
true=>LockWrapper::Read(lock.read().unwrap()),
false=>LockWrapper::Write(lock.write().unwrap())
};
// Now guard holds either read or write lock.
}