How can I get the reference of a field inside a lock struct?

Hi guys. I am dealing with a problem about returning a reference inside mutex.
For example, there is a struct called Foo. Inside the struct is a lock with a composite struct.

struct FooInner<Payload>{
    field1 : u32,
    field2 : Option<Payload>,
}

struct Foo<Payload>(Arc<Mutex<FooInner<Payload>>>);

And my question is, can I get the reference to the field2(maybe with a Lockguard)? My current solution is to implement this function only for the type with the trait Clone. So that I can return a new copy instead of a reference. But I still wonder if there is any way to return a reference.

impl<Payload> Foo<Payload> {
    pub fn new() -> Self{
        Foo(Arc::new(Mutex::new(FooInner{
            field1 : 0,
            field2 : None,
        })))
    }

    pub fn set_payload(&self, payload : Payload){
        let mut inner = self.0.lock().unwrap();
        inner.field2 = Some(payload);
    }

    pub fn get_payload(&self) -> Option<&Payload>{
        let inner = self.0.lock().unwrap();
        // How can I return the reference to the payload here?
        todo!()
    }
}

You can see the above code in Rust Playground.
Any help is appreciated!

You can't. To reference value inside mutex, corresponding guard must be in scope, but here it is dropped at the end of get_payload. Just return the MutexGuard itself.

3 Likes

If you use a parking_lot mutex instead, you can map it to show the correct subvalue:

    pub fn get_payload(&self) -> Option<impl '_ + std::ops::Deref<Target=Payload>>{
        let inner = self.0.lock();
        MutexGuard::try_map(inner, |inner| inner.field2.as_mut()).ok()
    }

Alternatively, you can provide an accessor that takes a closure to run while the lock is held:

    pub fn with_payload<Out>(&self, f: impl FnOnce(&Payload)->Out) -> Option<Out>{
        let inner = self.0.lock().unwrap();
        Some(f(inner.field2.as_ref()?))
    }
3 Likes

Thanks. I haven't used the parking_lot but it looks good for me. I will check it further.

The stdlib's Mutex also supports try_map with the mapped_lock_guards unstable feature.

3 Likes

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.