Get reference to boxed value in vec using Arc and RwLock

I'm running against a wall since days, hopefully somebody of you can help me.

The DatastoreInner is needed because I'm serializing and deserializing the data and it's easier to just do this to the inner struct.

It should be accessible from multiple threads where one calls 'get_item_by_name()' and gets a mutable reference back to the Item to work with.

No matter how I try to solve it, I always get a compiler error.
Even tried lifetime bounds without success.

use std::fmt::Debug;
use std::sync::{Arc, RwLock};

#[derive(Default)]
struct Datastore {
    inner: Arc<RwLock<DatastoreInner>>,
}

impl Datastore {
    fn get_item_by_name(&self, name: impl AsRef<str>) -> Option<&Box<dyn ItemTrait>> {
        self.inner.read().unwrap().items.iter()
        .find(|e| e.get_name() == name.as_ref())
    }
}

#[derive(Default)]
struct DatastoreInner{
    items: Vec<Box<dyn ItemTrait>>,
}

trait ItemTrait: Debug {
    fn get_name(&self) -> &str;
}
#[derive(Debug)]
struct Item {name: String}
impl ItemTrait for Item {fn get_name(&self) -> &str {&self.name}}

fn main() {
    let ds = Datastore::default();
}


The Error:

error[E0515]: cannot return value referencing temporary value
  --> src/main.rs:11:9
   |
11 |           self.inner.read().unwrap().items.iter()
   |           ^-------------------------
   |           |
   |  _________temporary value created here
   | |
12 | |         .find(|e| e.get_name() == name.as_ref())
   | |________________________________________________^ returns a value referencing data owned by the current function

What am I missing?

You are missing the fact that your wish is impossible.

Being able to return a reference to the value inside the lock without a guard object would violate the very purpose of the lock. There has to be some mechanism (a lock guard) by which the lock knows at all times whether someone is accessing the locked object, and whether that is for reading or writing.

The whole point of these locks is that you can only ever access the underlying value through the lock guards. You will have to return the guard object itself. There's no way around that, and no amount of lifetime annotations can force the lock to work in a different way.

(The immediate concrete reason for the compiler errors is the fact that the Deref impl of guard objects ties the lifetime of the returned reference to the lifetime of the guard object itself.)

1 Like

When something is held under a lock or refcell, you're explicitly forbidden from leaking references to it outside of the scope of the lock guard (and if you do nothing to keep the lock guard alive, it will be automatically destroyed before the function returns). This restriction is critical for safety of the lock.

Instead of returning a bare unprotected reference, you can return the lock guard:

1 Like

Makes sense, thanks for clarifying that. Should have spent more time reading the docs on Locks.
Thank you both.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.