Returning a value from inside a cloned Arc<T>


#1

Hi,
while working on a project of mine, I came across an issue, that can be reduced to the following code:

use std::sync::Arc;
use std::sync::RwLock;

fn main() {
    let x = Arc::new(RwLock::new(123));
    // This works
    let ref1 = {
        x.read().unwrap()
    };
    // This doesn't
    let ref2 = {
        x.clone().read().unwrap()
    };
    assert_eq!(123, *ref1);
    assert_eq!(123, *ref2);
}

This does not work, because the new Arc<T> created by x.clone() goes out of scope, while I try to return a reference to something inside it.

How can keep the Arc<T> alive until ref2 is dropped, without exposing implementation details (think of the code inside the {} as being some methods in a library interface)? Is it possible to write a wrapper like RwLockReadGuard?


#2

Not sure if this is what you’re looking for, but you can bind the clone at a higher level:

use std::sync::Arc;
use std::sync::RwLock;

fn main() {
    let x = Arc::new(RwLock::new(123));
    // This works
    let ref1 = {
        x.read().unwrap()
    };
    // This doesn't

    let arc;
    let ref2 = {
        arc=x.clone();
        arc.read().unwrap()
    };
    assert_eq!(123, *ref1);
    assert_eq!(123, *ref2);
}

#3

@jethrogb Not really. That would expose implementation detail. Maybe this example is better:

use std::sync::Arc;
use std::sync::RwLock;
use std::sync::RwLockWriteGuard;

struct Struct(Arc<RwLock<i32>>);

impl Struct {
    pub fn get<'a>(&'a self) -> RwLockWriteGuard<'a, i32> {
        // I have to clone here because in the real application, the Arc 
        // is inside another Arc<RwLock<HashMap<>>> and I want
        // to give the user a reference, that does not lock the whole
        // HashMap
        self.0.clone().write().unwrap()
    }
}

fn main() {
    let s = Struct(Arc::new(RwLock::new(123)));
    assert_eq!(123, *s.get());
}

#4

You can’t do that without unsafe code: you can’t return a value (Arc) and a reference to that value (RwLockWriteGuard) from a function. A common pattern is to have a function return a value that implements Deref for the actual result you want to return. Also, you might be able to adapt https://github.com/jethrogb/namedlock-rs/blob/master/src/ownedmutexguard.rs to your purposes.