Reputation: 115
I'm trying to use a static HashMap<String, Object> to store some data that I want to use and modify globally in the future. I found out that some way of declaring such a global map is by using lazy_static and mutex in order to share data safely. However, I'm getting some ownership troubles when I want to return these objects as reference, as I do in the code above:
use std::error::Error;
use std::collections::HashMap;
use std::sync::Mutex;
use super::domain::{Session, SessionRepository}; // object and trait declaration
lazy_static! {
static ref REPOSITORY: Mutex<HashMap<String, Session>> = {
let mut repo = HashMap::new();
Mutex::new(repo)
};
}
impl SessionRepository for REPOSITORY {
fn find(cookie: &str) -> Result<&mut Session, Box<dyn Error>> {
let mut repo = REPOSITORY.lock()?;
if let Some(sess) = repo.get_mut(cookie) {
return Ok(sess);
}
Err("Not found".into())
}
}
So the question is: Is there any way of doing this correctly? Does it exists any design pattern in Rust I could use in order to reach this behavior?
Thank you very much!
Upvotes: 0
Views: 747
Reputation: 43743
What you're trying to do is correctly rejected by the compiler, because if you could return a reference, then bad things can happen. Since after the function returns, the mutex is no longer locked,
Solution: each session should be in its own Arc<Mutex<_>>
. That is:
lazy_static! {
static ref REPOSITORY: Mutex<HashMap<String, Arc<Mutex<Session>>>> = {
...
impl SessionRepository for REPOSITORY {
fn find(cookie: &str) -> Result<Arc<Mutex<Session>>, Box<dyn Error>> {
let mut repo = REPOSITORY.lock()?;
if let Some(sess) = repo.get(cookie) {
return Ok(Arc::clone(sess));
}
...
}
The Arc
allows the session to be kept alive both by the repository and whichever threads have called find()
on it and thus gotten their own clone of the Arc
reference-counted pointer. The Mutex
allows each session to be independently mutated.
Upvotes: 5