pub struct LockKp<R, Lock, Mid, V, Root, LockValue, MidValue, Value, MutRoot, MutLock, MutMid, MutValue, G1, S1, L, G2, S2>where
Root: Borrow<R>,
LockValue: Borrow<Lock>,
MidValue: Borrow<Mid>,
Value: Borrow<V>,
MutRoot: BorrowMut<R>,
MutLock: BorrowMut<Lock>,
MutMid: BorrowMut<Mid>,
MutValue: BorrowMut<V>,
G1: Fn(Root) -> Option<LockValue>,
S1: Fn(MutRoot) -> Option<MutLock>,
L: LockAccess<Lock, MidValue> + LockAccess<Lock, MutMid>,
G2: Fn(MidValue) -> Option<Value>,
S2: Fn(MutMid) -> Option<MutValue>,{ /* private fields */ }Expand description
A keypath that handles locked values (e.g., Arc<Mutex
Structure:
prev: Keypath from Root to Lock container (e.g., Arc<Mutex>) mid: Lock access handler that goes from Lock to Inner valuenext: Keypath from Inner value to final Value
§Type Parameters
R: Root type (base)Lock: Lock container type (e.g., Arc<Mutex>) Mid: The type inside the lockV: Final value type- Rest are the same generic parameters as Kp
§Cloning Behavior
IMPORTANT: All Clone operations in this struct are SHALLOW clones:
LockKpitself derivesClone- this clones the three field references/closuresprevandnextfields areKpstructs containing function pointers (cheap to clone)midfield implementsLockAccesstrait - typically justPhantomData(zero-cost clone)- NO
Lock: Cloneneeded for lock operations - we use&Lockdirectly via interior mutability - NO deep data cloning occurs - all clones are pointer/reference copies
§Example
use std::sync::{Arc, Mutex};
use rust_key_paths::lock::{ArcMutexAccess, LockKp};
use rust_key_paths::Kp;
struct Root {
data: Arc<Mutex<Inner>>,
}
struct Inner {
value: String,
}
// Create a LockKp that goes: Root -> Arc<Mutex<Inner>> -> String
let root_to_lock_kp = Kp::new(|r: &Root| Some(&r.data), |r: &mut Root| Some(&mut r.data));
let inner_to_value_kp = Kp::new(|i: &Inner| Some(&i.value), |i: &mut Inner| Some(&mut i.value));
let lock_kp = LockKp::new(root_to_lock_kp, ArcMutexAccess::new(), inner_to_value_kp);Implementations§
Source§impl<R, Lock, Mid, V, Root, LockValue, MidValue, Value, MutRoot, MutLock, MutMid, MutValue, G1, S1, L, G2, S2> LockKp<R, Lock, Mid, V, Root, LockValue, MidValue, Value, MutRoot, MutLock, MutMid, MutValue, G1, S1, L, G2, S2>where
Root: Borrow<R>,
LockValue: Borrow<Lock>,
MidValue: Borrow<Mid>,
Value: Borrow<V>,
MutRoot: BorrowMut<R>,
MutLock: BorrowMut<Lock>,
MutMid: BorrowMut<Mid>,
MutValue: BorrowMut<V>,
G1: Fn(Root) -> Option<LockValue>,
S1: Fn(MutRoot) -> Option<MutLock>,
L: LockAccess<Lock, MidValue> + LockAccess<Lock, MutMid>,
G2: Fn(MidValue) -> Option<Value>,
S2: Fn(MutMid) -> Option<MutValue>,
impl<R, Lock, Mid, V, Root, LockValue, MidValue, Value, MutRoot, MutLock, MutMid, MutValue, G1, S1, L, G2, S2> LockKp<R, Lock, Mid, V, Root, LockValue, MidValue, Value, MutRoot, MutLock, MutMid, MutValue, G1, S1, L, G2, S2>where
Root: Borrow<R>,
LockValue: Borrow<Lock>,
MidValue: Borrow<Mid>,
Value: Borrow<V>,
MutRoot: BorrowMut<R>,
MutLock: BorrowMut<Lock>,
MutMid: BorrowMut<Mid>,
MutValue: BorrowMut<V>,
G1: Fn(Root) -> Option<LockValue>,
S1: Fn(MutRoot) -> Option<MutLock>,
L: LockAccess<Lock, MidValue> + LockAccess<Lock, MutMid>,
G2: Fn(MidValue) -> Option<Value>,
S2: Fn(MutMid) -> Option<MutValue>,
Sourcepub fn new(
prev: Kp<R, Lock, Root, LockValue, MutRoot, MutLock, G1, S1>,
mid: L,
next: Kp<Mid, V, MidValue, Value, MutMid, MutValue, G2, S2>,
) -> Self
pub fn new( prev: Kp<R, Lock, Root, LockValue, MutRoot, MutLock, G1, S1>, mid: L, next: Kp<Mid, V, MidValue, Value, MutMid, MutValue, G2, S2>, ) -> Self
Create a new LockKp with prev, mid, and next components
Sourcepub fn get(&self, root: Root) -> Option<Value>where
V: Clone,
pub fn get(&self, root: Root) -> Option<Value>where
V: Clone,
Get an immutable reference through the lock (sync, blocking).
This will:
- Use
prevto get to the Lock - Use
midto lock and get Inner value - Use
nextto get from Inner to final Value
§Example
use rust_key_paths::{KpType, LockKp};
use std::sync::Mutex;
#[derive(key_paths_derive::Kp)]
struct WithLocks {
std_mutex: std::sync::Mutex<i32>,
std_rwlock: std::sync::RwLock<String>,
}
let locks = WithLocks {
std_mutex: Mutex::new(99),
std_rwlock: std::sync::RwLock::new("test".to_string()),
};
let mutex_kp = WithLocks::std_mutex();
let rwlock_kp = WithLocks::std_rwlock();
let next: KpType<i32, i32> = rust_key_paths::Kp::new(|i: &i32| Some(i), |i: &mut i32| Some(i));
let lock_kp = LockKp::new(mutex_kp, rust_key_paths::StdMutexAccess::new(), next);
let value = lock_kp.get(&locks);
assert_eq!(value, Some(&99));§Cloning Behavior
Only requires V: Clone for the final value.
NO Lock: Clone needed because lock_read takes &Lock.
Sourcepub fn get_mut(&self, root: MutRoot) -> Option<MutValue>
pub fn get_mut(&self, root: MutRoot) -> Option<MutValue>
Get mutable access to the value through the lock (sync, blocking).
§Example
use rust_key_paths::{KpType, LockKp};
use std::sync::Mutex;
#[derive(key_paths_derive::Kp)]
struct WithLocks {
std_mutex: std::sync::Mutex<i32>,
std_rwlock: std::sync::RwLock<String>,
}
let mut locks = WithLocks {
std_mutex: Mutex::new(99),
std_rwlock: std::sync::RwLock::new("test".to_string()),
};
let mutex_kp = WithLocks::std_mutex();
let next: KpType<i32, i32> = rust_key_paths::Kp::new(|i: &i32| Some(i), |i: &mut i32| Some(i));
let lock_kp = LockKp::new(mutex_kp, rust_key_paths::StdMutexAccess::new(), next);
let value = lock_kp.get_mut(&mut locks).unwrap();
*value = 42;
assert_eq!(*locks.std_mutex.lock().unwrap(), 42);§NO CLONING Required!
No longer needs Lock: Clone because lock_write now takes &Lock instead of &mut Lock
Sourcepub fn set<F>(&self, root: Root, updater: F) -> Result<(), String>
pub fn set<F>(&self, root: Root, updater: F) -> Result<(), String>
Set the value through the lock using an updater function
§NO CLONING Required!
Unlike the original implementation, we NO LONGER need Lock: Clone because:
- Locks like
MutexandRwLockprovide interior mutability - We only need
&Lock, not&mut Lock, to get mutable access to the inner data - This eliminates an unnecessary Arc reference count increment
Sourcepub fn then<V2, Value2, MutValue2, G3, S3>(
self,
next_kp: Kp<V, V2, Value, Value2, MutValue, MutValue2, G3, S3>,
) -> LockKp<R, Lock, Mid, V2, Root, LockValue, MidValue, Value2, MutRoot, MutLock, MutMid, MutValue2, G1, S1, L, impl Fn(MidValue) -> Option<Value2> + use<G1, G2, G3, L, Lock, LockValue, Mid, MidValue, MutLock, MutMid, MutRoot, MutValue, MutValue2, R, Root, S1, S2, S3, Value, Value2, V, V2>, impl Fn(MutMid) -> Option<MutValue2> + use<G1, G2, G3, L, Lock, LockValue, Mid, MidValue, MutLock, MutMid, MutRoot, MutValue, MutValue2, R, Root, S1, S2, S3, Value, Value2, V, V2>>
pub fn then<V2, Value2, MutValue2, G3, S3>( self, next_kp: Kp<V, V2, Value, Value2, MutValue, MutValue2, G3, S3>, ) -> LockKp<R, Lock, Mid, V2, Root, LockValue, MidValue, Value2, MutRoot, MutLock, MutMid, MutValue2, G1, S1, L, impl Fn(MidValue) -> Option<Value2> + use<G1, G2, G3, L, Lock, LockValue, Mid, MidValue, MutLock, MutMid, MutRoot, MutValue, MutValue2, R, Root, S1, S2, S3, Value, Value2, V, V2>, impl Fn(MutMid) -> Option<MutValue2> + use<G1, G2, G3, L, Lock, LockValue, Mid, MidValue, MutLock, MutMid, MutRoot, MutValue, MutValue2, R, Root, S1, S2, S3, Value, Value2, V, V2>>
Chain this LockKp with another regular Kp
This allows you to continue navigating after getting through the lock: Root -> Lock -> Mid -> Value1 -> Value2
§Cloning Behavior
No cloning occurs in this method - closures are moved into the new Kp
Sourcepub fn then_lock<Lock2, Mid2, V2, LockValue2, MidValue2, Value2, MutLock2, MutMid2, MutValue2, G2_1, S2_1, L2, G2_2, S2_2>(
self,
other: LockKp<V, Lock2, Mid2, V2, Value, LockValue2, MidValue2, Value2, MutValue, MutLock2, MutMid2, MutValue2, G2_1, S2_1, L2, G2_2, S2_2>,
) -> LockKp<R, Lock, Mid, V2, Root, LockValue, MidValue, Value2, MutRoot, MutLock, MutMid, MutValue2, G1, S1, L, impl Fn(MidValue) -> Option<Value2> + use<G1, G2, G2_1, G2_2, L, L2, Lock, Lock2, LockValue, LockValue2, Mid, Mid2, MidValue, MidValue2, MutLock, MutLock2, MutMid, MutMid2, MutRoot, MutValue, MutValue2, R, Root, S1, S2, S2_1, S2_2, Value, Value2, V, V2>, impl Fn(MutMid) -> Option<MutValue2> + use<G1, G2, G2_1, G2_2, L, L2, Lock, Lock2, LockValue, LockValue2, Mid, Mid2, MidValue, MidValue2, MutLock, MutLock2, MutMid, MutMid2, MutRoot, MutValue, MutValue2, R, Root, S1, S2, S2_1, S2_2, Value, Value2, V, V2>>where
V: 'static + Clone,
V2: 'static,
Value: Borrow<V>,
LockValue2: Borrow<Lock2>,
MidValue2: Borrow<Mid2>,
Value2: Borrow<V2>,
MutValue: BorrowMut<V>,
MutLock2: BorrowMut<Lock2>,
MutMid2: BorrowMut<Mid2>,
MutValue2: BorrowMut<V2>,
G2_1: Fn(Value) -> Option<LockValue2> + 'static,
S2_1: Fn(MutValue) -> Option<MutLock2> + 'static,
L2: LockAccess<Lock2, MidValue2> + LockAccess<Lock2, MutMid2> + Clone + 'static,
G2_2: Fn(MidValue2) -> Option<Value2> + 'static,
S2_2: Fn(MutMid2) -> Option<MutValue2> + 'static,
pub fn then_lock<Lock2, Mid2, V2, LockValue2, MidValue2, Value2, MutLock2, MutMid2, MutValue2, G2_1, S2_1, L2, G2_2, S2_2>(
self,
other: LockKp<V, Lock2, Mid2, V2, Value, LockValue2, MidValue2, Value2, MutValue, MutLock2, MutMid2, MutValue2, G2_1, S2_1, L2, G2_2, S2_2>,
) -> LockKp<R, Lock, Mid, V2, Root, LockValue, MidValue, Value2, MutRoot, MutLock, MutMid, MutValue2, G1, S1, L, impl Fn(MidValue) -> Option<Value2> + use<G1, G2, G2_1, G2_2, L, L2, Lock, Lock2, LockValue, LockValue2, Mid, Mid2, MidValue, MidValue2, MutLock, MutLock2, MutMid, MutMid2, MutRoot, MutValue, MutValue2, R, Root, S1, S2, S2_1, S2_2, Value, Value2, V, V2>, impl Fn(MutMid) -> Option<MutValue2> + use<G1, G2, G2_1, G2_2, L, L2, Lock, Lock2, LockValue, LockValue2, Mid, Mid2, MidValue, MidValue2, MutLock, MutLock2, MutMid, MutMid2, MutRoot, MutValue, MutValue2, R, Root, S1, S2, S2_1, S2_2, Value, Value2, V, V2>>where
V: 'static + Clone,
V2: 'static,
Value: Borrow<V>,
LockValue2: Borrow<Lock2>,
MidValue2: Borrow<Mid2>,
Value2: Borrow<V2>,
MutValue: BorrowMut<V>,
MutLock2: BorrowMut<Lock2>,
MutMid2: BorrowMut<Mid2>,
MutValue2: BorrowMut<V2>,
G2_1: Fn(Value) -> Option<LockValue2> + 'static,
S2_1: Fn(MutValue) -> Option<MutLock2> + 'static,
L2: LockAccess<Lock2, MidValue2> + LockAccess<Lock2, MutMid2> + Clone + 'static,
G2_2: Fn(MidValue2) -> Option<Value2> + 'static,
S2_2: Fn(MutMid2) -> Option<MutValue2> + 'static,
Chain with another LockKp for multi-level lock access (then_lock convention)
This allows you to chain through multiple lock levels: Root -> Lock1 -> Mid1 -> Lock2 -> Mid2 -> Value
§Cloning Behavior - ALL CLONES ARE SHALLOW
This method requires two types of cloning, both SHALLOW:
-
L2: Clone: Clones the lock accessor (typically PhantomData)- For
ArcMutexAccess<T>: Only clonesPhantomData(zero-cost) - No data is cloned, just the lock access behavior
- For
-
NO
Lock2: Cloneneeded: Uses&Lock2reference directly (interior mutability)
Performance: Only L2 (lock accessor) is cloned—O(1), typically zero-cost PhantomData
§Example
// Root -> Arc<Mutex<Mid1>> -> Mid1 -> Arc<Mutex<Mid2>> -> Mid2 -> String
let lock_kp1 = LockKp::new(root_to_lock1, ArcMutexAccess::new(), lock1_to_mid1);
let lock_kp2 = LockKp::new(mid1_to_lock2, ArcMutexAccess::new(), mid2_to_value);
let chained = lock_kp1.then_lock(lock_kp2);Sourcepub fn then_async<AsyncKp>(
self,
async_kp: AsyncKp,
) -> KpThenAsyncKeyPath<R, V, <AsyncKp::Value as KeyPathValueTarget>::Target, Root, Value, AsyncKp::Value, MutRoot, MutValue, AsyncKp::MutValue, Self, AsyncKp>where
V: 'static + Clone,
Value: Borrow<V>,
MutValue: BorrowMut<V>,
AsyncKp: AsyncKeyPathLike<Value, MutValue>,
AsyncKp::Value: KeyPathValueTarget + Borrow<<AsyncKp::Value as KeyPathValueTarget>::Target>,
AsyncKp::MutValue: BorrowMut<<AsyncKp::Value as KeyPathValueTarget>::Target>,
<AsyncKp::Value as KeyPathValueTarget>::Target: 'static,
pub fn then_async<AsyncKp>(
self,
async_kp: AsyncKp,
) -> KpThenAsyncKeyPath<R, V, <AsyncKp::Value as KeyPathValueTarget>::Target, Root, Value, AsyncKp::Value, MutRoot, MutValue, AsyncKp::MutValue, Self, AsyncKp>where
V: 'static + Clone,
Value: Borrow<V>,
MutValue: BorrowMut<V>,
AsyncKp: AsyncKeyPathLike<Value, MutValue>,
AsyncKp::Value: KeyPathValueTarget + Borrow<<AsyncKp::Value as KeyPathValueTarget>::Target>,
AsyncKp::MutValue: BorrowMut<<AsyncKp::Value as KeyPathValueTarget>::Target>,
<AsyncKp::Value as KeyPathValueTarget>::Target: 'static,
Chain with an async keypath. Use .get(&root).await on the returned keypath.
When AsyncKp::Value is a reference type (&T / &mut T), V2 is inferred as T via crate::KeyPathValueTarget.