rustrwlock

Getting a read-only version of an Arc<RwLock<Foo>>?


I have an Arc<RwLock<Foo>>.

Is there a way to make something out of this, on which the RwLock's write() does not exist? i.e. Is there some form of RLock which I can make from an RwLock.

Use case: I have a Foo. More than one part of my code needs to mutate the Foo (hence the RwLock), but the majority of my code must only ever have read-only access to the Foo.

Is there a way of achieving this? Or is there a way of doing this without RwLock?


Solution

  • Write your own struct that contains the Arc<RwLock<Foo>>.

    #[derive(Clone, Debug)]
    pub struct FooReadOnly(Arc<RwLock<Foo>>);
    
    impl FooReadOnly {
        pub fn read(&self) -> LockResult<RwLockReadGuard<'_, Foo>> {
            self.0.read()
        }
    
    }
    

    (A fully fleshed-out version would also contain a wrapper for try_read().)

    The general pattern worth noting here is: instead of your data type being visibly inside an Arc<RwLock<...>>, your public type contains the Arc. This allows much more flexibility in what kind of “handles” you can offer than exposing the Arc. This is a fairly common pattern in Rust — if you've ever used a library type that notes you can clone it and get another handle to the same thing, there's a good chance it's doing the same thing inside (if it's not actually a handle to an OS resource like a file descriptor).

    If you wanted to fully hide the implementation details, you would also wrap the RwLockReadGuard — all it needs to do is implement Deref<Target = Foo> and forward that to the guard. Such wrappers can also do things like Derefing to some part of the Foo rather than an &Foo exactly.