Guard objects are only necessary when there is something that ought to happen when the guard object is dropped. If you start with a &RwLockWriteGuard<'_, T> borrow then that's unnecessary, as that write guard takes care of any on locking logic eventually, and the mutable (re-)borrow can be completely understood by the borrow checker alone; so you can directly get a normal &T reference with the same lifetime as the &RwLockWriteGuard.... Hence the first question here is "why do you want a guard instead of a normal reference?"
My guards have time information in addition to the usual things. So for some methods a &T isn't enough.
But that definitely explains why std and other RwLocks don't need a function like this, Deref is enough.
It violates the "sharing xor mutability" principle, causing memory unsafety. Just think about it: if you can read and write the "locked" value at the same time, why do you need a lock in the first place? Having both a read and a write guard at the same time is exactly as bad as having no lock around the value at all.
But I'm borrowing the write lock so I can't write with it, it's like a reborrow.
let mut foo = "foo".to_string();
let rm = &mut foo;
let r: &String = rm;
// here I have both a &mut and & to foo
dbg!(rm.len()); // can still use rm immutably but not exclusively
dbg!(r);
I don't think it's easily implementable though – the lock likely assumes that the existence of read guard(s) prevents the existence of a write guard and vice versa. Then all sorts of internal invariants regarding the number of readers and writers will not be upheld.
I can imagine wrapping the write guard so that it only hands out immutable borrows, though – that way you can add your own timing information:
The goal is to be able to call a function that takes a RwLockReadGuard.
The time info would not change, the ones from the RwLockWriteGuard can be reused.
The implementation should work.
The main thing would be that either the reborrowed RwLockReadGuard can't be cloned. Or cloning a RwLockReadGuard doesn't check for write.
The read/write counter sets the highest bit for writes and increments for reads.
At the end of a read the counter decrements and for writes it sets it at 0.
So reborrow should work, it would force a read and the counter would end up at highest bit + 1.
As long as the write lock exists it would be impossible to get any new guards from the RwLock. But new reborrow could be made and maybe new clones of the shared guard.
View and ViewMut are the read and write locks. &View and &ViewMut both implement a Get trait with an associated type &T. Get can also be used to get a &mut T, that's why the associated type is not T.
What the user wants should work in theory but I'm guessing the invariant lifetime on ViewMut with the lifetime on Get associated type prevent the compiler from finding a lifetime that works.
My solution to the issue is to not use impl Get but View in inner_func.
This means that you can't call it with a ViewMut, except if there is a way to get a View from a ViewMut.
But of course it seems wrong, that's why we're here