Add `map` methods for `MutexGuard`?

I found that std::cell::Ref and std::cell::RefMut both have the methods map, filter_map, map_split, it's very useful to return the component of the wrapped object as return value.

The std::sync::MutexGuard, std::sync::RwLockReadGuard, std::sync::RwLockWriteGuard are similar with std::cell::Ref and std::cell::RefMut, but there are no such methods, I think it is very useful to add these methods. I recently encountered this problem when designing APIs.

1 Like

There is an RFC on the subject as well as a pre-RFC in the language-design section with a rather long thread.

1 Like

While that RFC is about field projection through wrapper types, it's about that for types where that projection is already possible, if not exactly convenient, through other APIs.

MutexGuard isn't covered by that RFC, as the projection isn't yet possible.

In short, while cell::Ref can be mapped fairly simply, MutexGuard cannot. You can of course map mutex guards (e.g. parking_lot's), but this requires a separate mapped guard type with a slightly different API.

The main difference between MappedMutexGuard and MutexGuard is that the former doesn’t support temporarily unlocking and re-locking, since that could introduce soundness issues if the locked object is modified by another thread.

(e.g. for condvars)

2 Likes

I once submitted a PR to crate try_rwlock, now the api map has grown like this:

https://docs.rs/try-rwlock/0.1.2/try_rwlock/struct.ReadGuard.html#method.map

These guard types really need something like a U: 'lock bound. (Or an extra lifetime argument?)

use try_rwlock::{ReadGuard, TryRwLock};

fn main() {
    let l = TryRwLock::new(());
    let x = l.try_read().unwrap();
    let z: ReadGuard<'_, (), String>;
    {
        let s = "Hello World!".to_string();
        let s_ref: &String = &s;
        let y: ReadGuard<'_, (), &String> = ReadGuard::map(x, |_| &s_ref);
        z = ReadGuard::map(y, |s: &&String| *s);
        // s deallocated here
    }
    println!("{}", &*z); // printing garbage, accessing `s` after it’s freed
}

Adapted from: `OwningRef::map` is unsound · Issue #71 · Kimundi/owning-ref-rs · GitHub

3 Likes