I am wanting to expose a struct (S) that wraps an Arc<RwLock<T>> and allow for getting a reference to T's private fields through methods on S. It doesn't look like this is possible through safe code but I was able to accomplish it using the code below.
Rather than pulling the value out and unsafely storing it next to the guard, just store the guard in ValueRef and pull the value out of it in Deref. No unsafety required.
That is true, but would require a struct for each field that I want to reference. I updated the question to better reflect my intention so ValueRef contains a NonNull to a generic T.
My Inner is actually significantly more complicated than the one from the example. Creating a struct for each field isn't ideal, even with macros.
@Hyeonu this is really interesting and seems very similar to what I want to accomplish. Unfortunately, I was planning on using an async RwLock via async-std.
@2e71828 If I proceed with the ValueRef<'a, T>, do you know if this is a situation that would require returning a pinned ValueRef? Also, I appreciate the accessor suggestion; if it turns out I expose UB, this is very likely the solution I'll use.
This is unlikely to require pinning. A reference &’a T already ensures that the T will not be moved inside the region ’a. Because ValueRef carries the same lifetime annotation, the compiler won’t allow it to exist beyond the scope of this protection.
Note also that the Tokio async rwlock can also be mapped with the RwLockReadGuard::map method. Interestingly, it is implemented in a very similar way to your ValueRef.
As for pinning, no it is not necessary. The lifetime ensures that the pointer is not invalidated in this case.