Skip to main content

rust_key_paths/
async_lock.rs

1//! # Async Lock Keypath Module
2//!
3//! This module provides `AsyncLockKp` for safely navigating through async locked/synchronized data structures.
4//!
5//! # Naming convention (aligned with [crate::lock::LockKp] and [crate::Kp])
6//!
7//! - **`then`** – chain with a plain [crate::Kp]
8//! - **`then_lock`** – chain with a sync [crate::lock::LockKp]
9//! - **`then_async`** – chain with another async keypath (e.g. tokio RwLock)
10//! - **`then_pin_future`** – chain with a #[pin] Future field await ([crate::pin])
11//!
12//! Example: `root_lock.then_lock(parking_kp).then_async(async_kp).then_lock(std_lock_kp)`
13//!
14//! # SHALLOW CLONING GUARANTEE
15//!
16//! **IMPORTANT**: All cloning operations in this module are SHALLOW (reference-counted) clones:
17//!
18//! 1. **`AsyncLockKp` derives `Clone`**: Clones function pointers and PhantomData only
19//!    - `prev` and `next` fields contain function pointers (cheap to copy)
20//!    - `mid` field is typically just `PhantomData<T>` (zero-sized, zero-cost)
21//!    - No heap allocations or deep data copies
22//!
23//! 2. **`Lock: Clone` bound** (e.g., `Arc<tokio::sync::Mutex<T>>`):
24//!    - For `Arc<T>`: Only increments the atomic reference count (one atomic operation)
25//!    - The actual data `T` inside is **NEVER** cloned
26//!    - This is the whole point of Arc - shared ownership without copying data
27//!
28//! 3. **`L: Clone` bound** (e.g., `TokioMutexAccess<T>`):
29//!    - Only clones `PhantomData<T>` which is zero-sized
30//!    - Compiled away completely - zero runtime cost
31
32use crate::Kp;
33use async_trait::async_trait;
34use std::sync::Arc;
35
36// Re-export tokio sync types for convenience
37#[cfg(feature = "tokio")]
38pub use tokio::sync::{Mutex as TokioMutex, RwLock as TokioRwLock};
39
40// =============================================================================
41// Why two traits: AsyncLockLike and AsyncKeyPathLike
42// =============================================================================
43//
44// - AsyncLockLike<Lock, Inner>: One "step" through a lock. Given a Lock (e.g.
45//   Arc<Mutex<T>>), it async yields Inner (e.g. &T). Used by the `mid` field of
46//   AsyncLockKp to go from "container" to "value inside the lock". Implemented
47//   by TokioMutexAccess, TokioRwLockAccess, etc.
48//
49// - AsyncKeyPathLike<Root, MutRoot>: A full keypath from Root to a value. Used
50//   so we can chain at any depth: both AsyncLockKp and ComposedAsyncLockKp
51//   implement it, so we can write `kp1.then_async(kp2).then_async(kp3).get(&root)`.
52//   Without this trait we could not express "first and second can be either a
53//   single AsyncLockKp or another ComposedAsyncLockKp" in the type system.
54
55/// Async trait for types that can provide async lock/unlock behavior
56/// Converts from a Lock type to Inner or InnerMut value asynchronously
57#[async_trait]
58pub trait AsyncLockLike<Lock, Inner>: Send + Sync {
59    /// Get immutable access to the inner value asynchronously
60    async fn lock_read(&self, lock: &Lock) -> Option<Inner>;
61
62    /// Get mutable access to the inner value asynchronously
63    async fn lock_write(&self, lock: &mut Lock) -> Option<Inner>;
64}
65
66/// Sync keypath that can be used as the "second" in [AsyncLockKpThenLockKp] for blanket impls.
67/// Also implemented for [crate::Kp] so [crate::Kp::then_lock] and [crate::Kp::then_async] can chain.
68pub trait SyncKeyPathLike<Root, Value, MutRoot, MutValue> {
69    /// Get an immutable reference through the keypath (sync, non-blocking).
70    ///
71    /// For [crate::lock::LockKp], this acquires a read/write lock and returns the value.
72    /// For plain [crate::Kp], this navigates to the field directly.
73    ///
74    /// # Example
75    /// ```
76    /// use rust_key_paths::async_lock::SyncKeyPathLike;
77    /// use rust_key_paths::{KpType, LockKp};
78    /// use std::sync::Mutex;
79    ///
80    /// #[derive(key_paths_derive::Kp)]
81    /// struct WithLocks {
82    ///     std_mutex: std::sync::Mutex<i32>,
83    ///     std_rwlock: std::sync::RwLock<String>,
84    /// }
85    ///
86    /// let locks = WithLocks {
87    ///     std_mutex: Mutex::new(99),
88    ///     std_rwlock: std::sync::RwLock::new("hello".to_string()),
89    /// };
90    /// let mutex_kp = WithLocks::std_mutex();
91    /// let rwlock_kp = WithLocks::std_rwlock();
92    /// let next: KpType<i32, i32> = rust_key_paths::Kp::new(|i: &i32| Some(i), |i: &mut i32| Some(i));
93    /// let lock_kp = LockKp::new(mutex_kp, rust_key_paths::StdMutexAccess::new(), next);
94    ///
95    /// // sync_get works with LockKp (same as .get())
96    /// let value = lock_kp.sync_get(&locks).unwrap();
97    /// assert_eq!(*value, 99);
98    /// ```
99    fn sync_get(&self, root: Root) -> Option<Value>;
100
101    /// Get a mutable reference through the keypath (sync, non-blocking).
102    ///
103    /// For [crate::lock::LockKp], this acquires a write lock and returns a mutable reference.
104    /// For plain [crate::Kp], this navigates to the field mutably.
105    ///
106    /// # Example
107    /// ```
108    /// use rust_key_paths::async_lock::SyncKeyPathLike;
109    /// use rust_key_paths::{KpType, LockKp};
110    /// use std::sync::Mutex;
111    ///
112    /// #[derive(key_paths_derive::Kp)]
113    /// struct WithLocks {
114    ///     std_mutex: std::sync::Mutex<i32>,
115    ///     std_rwlock: std::sync::RwLock<String>,
116    /// }
117    ///
118    /// let mut locks = WithLocks {
119    ///     std_mutex: Mutex::new(99),
120    ///     std_rwlock: std::sync::RwLock::new("hello".to_string()),
121    /// };
122    /// let mutex_kp = WithLocks::std_mutex();
123    /// let next: KpType<i32, i32> = rust_key_paths::Kp::new(|i: &i32| Some(i), |i: &mut i32| Some(i));
124    /// let lock_kp = LockKp::new(mutex_kp, rust_key_paths::StdMutexAccess::new(), next);
125    ///
126    /// // sync_get_mut works with LockKp (same as .get_mut())
127    /// let value = lock_kp.sync_get_mut(&mut locks).unwrap();
128    /// *value = 42;
129    /// assert_eq!(*locks.std_mutex.lock().unwrap(), 42);
130    /// ```
131    fn sync_get_mut(&self, root: MutRoot) -> Option<MutValue>;
132}
133
134impl<R, V, Root, Value, MutRoot, MutValue, G, S> SyncKeyPathLike<Root, Value, MutRoot, MutValue>
135    for crate::Kp<R, V, Root, Value, MutRoot, MutValue, G, S>
136where
137    Root: std::borrow::Borrow<R>,
138    Value: std::borrow::Borrow<V>,
139    MutRoot: std::borrow::BorrowMut<R>,
140    MutValue: std::borrow::BorrowMut<V>,
141    G: Fn(Root) -> Option<Value>,
142    S: Fn(MutRoot) -> Option<MutValue>,
143{
144    fn sync_get(&self, root: Root) -> Option<Value> {
145        self.get(root)
146    }
147    fn sync_get_mut(&self, root: MutRoot) -> Option<MutValue> {
148        self.get_mut(root)
149    }
150}
151
152impl<
153        R,
154        Lock,
155        Mid,
156        V,
157        Root,
158        LockValue,
159        MidValue,
160        Value,
161        MutRoot,
162        MutLock,
163        MutMid,
164        MutValue,
165        G1,
166        S1,
167        L,
168        G2,
169        S2,
170    >
171    SyncKeyPathLike<Root, Value, MutRoot, MutValue> for crate::lock::LockKp<
172        R,
173        Lock,
174        Mid,
175        V,
176        Root,
177        LockValue,
178        MidValue,
179        Value,
180        MutRoot,
181        MutLock,
182        MutMid,
183        MutValue,
184        G1,
185        S1,
186        L,
187        G2,
188        S2,
189    >
190where
191    Root: std::borrow::Borrow<R>,
192    LockValue: std::borrow::Borrow<Lock>,
193    MidValue: std::borrow::Borrow<Mid>,
194    Value: std::borrow::Borrow<V>,
195    MutRoot: std::borrow::BorrowMut<R>,
196    MutLock: std::borrow::BorrowMut<Lock>,
197    MutMid: std::borrow::BorrowMut<Mid>,
198    MutValue: std::borrow::BorrowMut<V>,
199    G1: Fn(Root) -> Option<LockValue>,
200    S1: Fn(MutRoot) -> Option<MutLock>,
201    L: crate::lock::LockAccess<Lock, MidValue> + crate::lock::LockAccess<Lock, MutMid>,
202    G2: Fn(MidValue) -> Option<Value>,
203    S2: Fn(MutMid) -> Option<MutValue>,
204    V: Clone,
205{
206    #[inline]
207    fn sync_get(&self, root: Root) -> Option<Value> {
208        self.get(root)
209    }
210    #[inline]
211    fn sync_get_mut(&self, root: MutRoot) -> Option<MutValue> {
212        self.get_mut(root)
213    }
214}
215
216/// Trait for async keypaths (both [AsyncLockKp] and [ComposedAsyncLockKp]) so composition can be any depth.
217///
218/// # Why MutRoot? (RwLock/Mutex interior mutability)
219///
220/// RwLock and Mutex provide **interior mutability**—their `lock()` / `write()` methods take `&self`,
221/// so you can mutate through an immutable reference. For **async lock keypaths**, the mutation
222/// happens inside the lock; you do *not* need a mutable root. `MutRoot` exists for composition
223/// with sync keypaths (e.g. [Kp]) that may require `&mut` along the path. When the path goes
224/// entirely through locks (RwLock/Mutex), `Root` and `MutRoot` are typically the same type
225/// (e.g. `&Root` for both).
226#[async_trait(?Send)]
227pub trait AsyncKeyPathLike<Root, MutRoot> {
228    /// Value type at the end of the keypath.
229    type Value;
230    /// Mutable value type at the end of the keypath.
231    type MutValue;
232    /// Get the value at the end of the keypath.
233    async fn get(&self, root: Root) -> Option<Self::Value>;
234    /// Get mutable access to the value at the end of the keypath.
235    async fn get_mut(&self, root: MutRoot) -> Option<Self::MutValue>;
236}
237
238/// An async keypath that handles async locked values (e.g., Arc<tokio::sync::Mutex<T>>)
239///
240/// Structure:
241/// - `prev`: Keypath from Root to Lock container (e.g., Arc<tokio::sync::Mutex<Mid>>)
242/// - `mid`: Async lock access handler that goes from Lock to Inner value
243/// - `next`: Keypath from Inner value to final Value
244///
245/// # Type Parameters
246/// - `R`: Root type (base)
247/// - `Lock`: Lock container type (e.g., Arc<tokio::sync::Mutex<Mid>>)
248/// - `Mid`: The type inside the lock
249/// - `V`: Final value type
250/// - Rest are the same generic parameters as Kp
251///
252/// # Cloning Behavior
253///
254/// **IMPORTANT**: All `Clone` operations in this struct are SHALLOW clones:
255///
256/// - `AsyncLockKp` itself derives `Clone` - this clones the three field references/closures
257/// - `prev` and `next` fields are `Kp` structs containing function pointers (cheap to clone)
258/// - `mid` field implements `AsyncLockLike` trait - typically just `PhantomData` (zero-cost clone)
259/// - When `Lock: Clone` (e.g., `Arc<tokio::sync::Mutex<T>>`), cloning is just incrementing reference count
260/// - NO deep data cloning occurs - all clones are pointer/reference increments
261#[derive(Clone)] // SHALLOW: Clones function pointers and PhantomData only
262pub struct AsyncLockKp<
263    R,
264    Lock,
265    Mid,
266    V,
267    Root,
268    LockValue,
269    MidValue,
270    Value,
271    MutRoot,
272    MutLock,
273    MutMid,
274    MutValue,
275    G1,
276    S1,
277    L,
278    G2,
279    S2,
280> where
281    Root: std::borrow::Borrow<R>,
282    LockValue: std::borrow::Borrow<Lock>,
283    MidValue: std::borrow::Borrow<Mid>,
284    Value: std::borrow::Borrow<V>,
285    MutRoot: std::borrow::BorrowMut<R>,
286    MutLock: std::borrow::BorrowMut<Lock>,
287    MutMid: std::borrow::BorrowMut<Mid>,
288    MutValue: std::borrow::BorrowMut<V>,
289    G1: Fn(Root) -> Option<LockValue> + Clone,
290    S1: Fn(MutRoot) -> Option<MutLock> + Clone,
291    L: AsyncLockLike<Lock, MidValue> + AsyncLockLike<Lock, MutMid> + Clone,
292    G2: Fn(MidValue) -> Option<Value> + Clone,
293    S2: Fn(MutMid) -> Option<MutValue> + Clone,
294{
295    /// Keypath from Root to Lock container
296    pub(crate) prev: Kp<R, Lock, Root, LockValue, MutRoot, MutLock, G1, S1>,
297
298    /// Async lock access handler (converts Lock -> Inner)
299    pub(crate) mid: L,
300
301    /// Keypath from Inner to final Value
302    pub(crate) next: Kp<Mid, V, MidValue, Value, MutMid, MutValue, G2, S2>,
303}
304
305impl<
306    R,
307    Lock,
308    Mid,
309    V,
310    Root,
311    LockValue,
312    MidValue,
313    Value,
314    MutRoot,
315    MutLock,
316    MutMid,
317    MutValue,
318    G1,
319    S1,
320    L,
321    G2,
322    S2,
323>
324    AsyncLockKp<
325        R,
326        Lock,
327        Mid,
328        V,
329        Root,
330        LockValue,
331        MidValue,
332        Value,
333        MutRoot,
334        MutLock,
335        MutMid,
336        MutValue,
337        G1,
338        S1,
339        L,
340        G2,
341        S2,
342    >
343where
344    Root: std::borrow::Borrow<R>,
345    LockValue: std::borrow::Borrow<Lock>,
346    MidValue: std::borrow::Borrow<Mid>,
347    Value: std::borrow::Borrow<V>,
348    MutRoot: std::borrow::BorrowMut<R>,
349    MutLock: std::borrow::BorrowMut<Lock>,
350    MutMid: std::borrow::BorrowMut<Mid>,
351    MutValue: std::borrow::BorrowMut<V>,
352    G1: Fn(Root) -> Option<LockValue> + Clone,
353    S1: Fn(MutRoot) -> Option<MutLock> + Clone,
354    L: AsyncLockLike<Lock, MidValue> + AsyncLockLike<Lock, MutMid> + Clone,
355    G2: Fn(MidValue) -> Option<Value> + Clone,
356    S2: Fn(MutMid) -> Option<MutValue> + Clone,
357{
358    /// Create a new AsyncLockKp with prev, mid, and next components
359    pub fn new(
360        prev: Kp<R, Lock, Root, LockValue, MutRoot, MutLock, G1, S1>,
361        mid: L,
362        next: Kp<Mid, V, MidValue, Value, MutMid, MutValue, G2, S2>,
363    ) -> Self {
364        Self { prev, mid, next }
365    }
366
367    /// Get the value through the lock
368    ///
369    /// This will:
370    /// 1. Use `prev` to get to the Lock
371    /// 2. Use `mid` to asynchronously lock and get the Inner value
372    /// 3. Use `next` to get to the final Value
373    ///
374    /// # SHALLOW CLONING NOTE
375    ///
376    /// When `lock` is cloned (e.g., `Arc<tokio::sync::Mutex<T>>`):
377    /// - Only the Arc reference count is incremented (one atomic operation)
378    /// - The actual data `T` inside the Mutex is **NEVER** cloned
379    /// - This is safe and efficient - the whole point of Arc
380    #[inline]
381    pub async fn get(&self, root: Root) -> Option<Value>
382    where
383        Lock: Clone,
384    {
385        // SHALLOW CLONE: For Arc<Mutex<T>>, only increments Arc refcount
386        // The actual data T is NOT cloned
387        let lock_value = (self.prev.get)(root)?;
388        let lock: &Lock = lock_value.borrow();
389        let lock_clone = lock.clone(); // SHALLOW: Arc refcount++
390
391        // Async lock and get the mid value
392        let mid_value = self.mid.lock_read(&lock_clone).await?;
393
394        // Navigate from mid to final value
395        (self.next.get)(mid_value)
396    }
397
398    /// Get mutable access to the value through the lock
399    #[inline]
400    pub async fn get_mut(&self, root: MutRoot) -> Option<MutValue>
401    where
402        Lock: Clone,
403    {
404        // SHALLOW CLONE: For Arc<Mutex<T>>, only increments Arc refcount
405        let mut lock_value = (self.prev.set)(root)?;
406        let lock: &mut Lock = lock_value.borrow_mut();
407        let mut lock_clone = lock.clone(); // SHALLOW: Arc refcount++
408
409        // Async lock and get the mid value
410        let mid_value = self.mid.lock_write(&mut lock_clone).await?;
411
412        // Navigate from mid to final value
413        (self.next.set)(mid_value)
414    }
415
416    /// Like [get](AsyncLockKp::get), but takes an optional root: returns `None` if `root` is `None`, otherwise the result of the getter.
417    #[inline]
418    pub async fn get_optional(&self, root: Option<Root>) -> Option<Value>
419    where
420        Lock: Clone,
421    {
422        match root {
423            Some(r) => self.get(r).await,
424            None => None,
425        }
426    }
427
428    /// Like [get_mut](AsyncLockKp::get_mut), but takes an optional root: returns `None` if `root` is `None`, otherwise the result of the setter.
429    #[inline]
430    pub async fn get_mut_optional(&self, root: Option<MutRoot>) -> Option<MutValue>
431    where
432        Lock: Clone,
433    {
434        match root {
435            Some(r) => self.get_mut(r).await,
436            None => None,
437        }
438    }
439
440    /// Returns the value if the keypath succeeds (root is `Some` and get returns `Some`), otherwise calls `f` and returns its result.
441    #[inline]
442    pub async fn get_or_else<F>(&self, root: Option<Root>, f: F) -> Value
443    where
444        Lock: Clone,
445        F: FnOnce() -> Value,
446    {
447        self.get_optional(root).await.unwrap_or_else(f)
448    }
449
450    /// Returns the mutable value if the keypath succeeds (root is `Some` and get_mut returns `Some`), otherwise calls `f` and returns its result.
451    #[inline]
452    pub async fn get_mut_or_else<F>(&self, root: Option<MutRoot>, f: F) -> MutValue
453    where
454        Lock: Clone,
455        F: FnOnce() -> MutValue,
456    {
457        self.get_mut_optional(root).await.unwrap_or_else(f)
458    }
459
460    /// Set the value through the lock using an updater function.
461    ///
462    /// Uses interior mutability—no mutable root required. RwLock/Mutex allow mutation through
463    /// `&self` (lock().write() etc.), so `root` can be `&Root`.
464    ///
465    /// Internally uses: `prev.get` → `mid.lock_read`/`lock_write` → `next.set` (the setter path).
466    pub async fn set<F>(&self, root: Root, updater: F) -> Result<(), String>
467    where
468        Lock: Clone,
469        F: FnOnce(&mut V),
470    {
471        // SHALLOW CLONE: For Arc<Mutex<T>>, only increments Arc refcount
472        let lock_value = (self.prev.get)(root).ok_or("Failed to get lock from root")?;
473        let lock: &Lock = lock_value.borrow();
474        let lock_clone = lock.clone(); // SHALLOW: Arc refcount++
475
476        // Async lock and get the mid value
477        let mut mid_value = self
478            .mid
479            .lock_read(&lock_clone)
480            .await
481            .ok_or("Failed to lock")?;
482
483        // Get the final value
484        let mut mut_value = (self.next.set)(mid_value).ok_or("Failed to navigate to value")?;
485        let v: &mut V = mut_value.borrow_mut();
486
487        // Apply the updater
488        updater(v);
489
490        Ok(())
491    }
492
493    // ========================================================================
494    // Interoperability: then (Kp), then_lock (sync LockKp), then_async (async keypath)
495    // ========================================================================
496
497    /// Chain this AsyncLockKp with a regular [crate::Kp] (no root at call site).
498    /// Returns an AsyncLockKp that goes one step further; use [AsyncLockKp::get] or [AsyncLockKp::get_mut] with root later.
499    ///
500    /// # Example
501    /// ```ignore
502    /// // Root -> Arc<tokio::Mutex<Inner>> -> Inner -> field
503    /// let async_kp = AsyncLockKp::new(root_to_lock, TokioMutexAccess::new(), lock_to_inner);
504    /// let field_kp = Kp::new(|inner: &Inner| Some(&inner.field), |inner: &mut Inner| Some(&mut inner.field));
505    /// let chained = async_kp.then(field_kp);
506    /// let result = chained.get(&root).await;
507    /// ```
508    pub fn then<V2, Value2, MutValue2, G3, S3>(
509        self,
510        next_kp: crate::Kp<V, V2, Value, Value2, MutValue, MutValue2, G3, S3>,
511    ) -> AsyncLockKp<
512        R,
513        Lock,
514        Mid,
515        V2,
516        Root,
517        LockValue,
518        MidValue,
519        Value2,
520        MutRoot,
521        MutLock,
522        MutMid,
523        MutValue2,
524        G1,
525        S1,
526        L,
527        impl Fn(MidValue) -> Option<Value2> + Clone + use<G1, G2, G3, L, Lock, LockValue, Mid, MidValue, MutLock, MutMid, MutRoot, MutValue, MutValue2, R, Root, S1, S2, S3, Value, Value2, V, V2>,
528        impl Fn(MutMid) -> Option<MutValue2> + Clone + use<G1, G2, G3, L, Lock, LockValue, Mid, MidValue, MutLock, MutMid, MutRoot, MutValue, MutValue2, R, Root, S1, S2, S3, Value, Value2, V, V2>,
529    >
530    where
531        V: 'static,
532        V2: 'static,
533        Value: std::borrow::Borrow<V>,
534        Value2: std::borrow::Borrow<V2>,
535        MutValue: std::borrow::BorrowMut<V>,
536        MutValue2: std::borrow::BorrowMut<V2>,
537        G3: Fn(Value) -> Option<Value2> + Clone,
538        S3: Fn(MutValue) -> Option<MutValue2> + Clone,
539    {
540        let next_get = self.next.get;
541        let next_set = self.next.set;
542        let chained_kp = crate::Kp::new(
543            move |mid_value: MidValue| next_get(mid_value).and_then(|v| (next_kp.get)(v)),
544            move |mid_value: MutMid| next_set(mid_value).and_then(|v| (next_kp.set)(v)),
545        );
546        AsyncLockKp::new(self.prev, self.mid, chained_kp)
547    }
548
549    /// Chain this AsyncLockKp with a sync [crate::lock::LockKp] (no root at call site).
550    /// Returns a keypath that first goes through the async lock, then through the sync lock; use `.get(&root).await` later.
551    pub fn then_lock<
552        Lock2,
553        Mid2,
554        V2,
555        LockValue2,
556        MidValue2,
557        Value2,
558        MutLock2,
559        MutMid2,
560        MutValue2,
561        G2_1,
562        S2_1,
563        L2,
564        G2_2,
565        S2_2,
566    >(
567        self,
568        lock_kp: crate::lock::LockKp<
569            V,
570            Lock2,
571            Mid2,
572            V2,
573            Value,
574            LockValue2,
575            MidValue2,
576            Value2,
577            MutValue,
578            MutLock2,
579            MutMid2,
580            MutValue2,
581            G2_1,
582            S2_1,
583            L2,
584            G2_2,
585            S2_2,
586        >,
587    ) -> AsyncLockKpThenLockKp<
588        R,
589        V2,
590        Root,
591        Value2,
592        MutRoot,
593        MutValue2,
594        Self,
595        crate::lock::LockKp<
596            V,
597            Lock2,
598            Mid2,
599            V2,
600            Value,
601            LockValue2,
602            MidValue2,
603            Value2,
604            MutValue,
605            MutLock2,
606            MutMid2,
607            MutValue2,
608            G2_1,
609            S2_1,
610            L2,
611            G2_2,
612            S2_2,
613        >,
614    >
615    where
616        V: 'static,
617        V2: 'static,
618        Value: std::borrow::Borrow<V>,
619        Value2: std::borrow::Borrow<V2>,
620        MutValue: std::borrow::BorrowMut<V>,
621        MutValue2: std::borrow::BorrowMut<V2>,
622        LockValue2: std::borrow::Borrow<Lock2>,
623        MidValue2: std::borrow::Borrow<Mid2>,
624        MutLock2: std::borrow::BorrowMut<Lock2>,
625        MutMid2: std::borrow::BorrowMut<Mid2>,
626        G2_1: Fn(Value) -> Option<LockValue2>,
627        S2_1: Fn(MutValue) -> Option<MutLock2>,
628        L2: crate::lock::LockAccess<Lock2, MidValue2> + crate::lock::LockAccess<Lock2, MutMid2>,
629        G2_2: Fn(MidValue2) -> Option<Value2>,
630        S2_2: Fn(MutMid2) -> Option<MutValue2>,
631    {
632        AsyncLockKpThenLockKp {
633            first: self,
634            second: lock_kp,
635            _p: std::marker::PhantomData,
636        }
637    }
638
639    /// Chain with another async keypath (like [crate::lock::LockKp::then_lock] for sync locks).
640    ///
641    /// Chain with another async keypath (e.g. tokio RwLock). Use [ComposedAsyncLockKp::get] or
642    /// [ComposedAsyncLockKp::get_mut] with root later.
643    ///
644    /// Root -> AsyncLock1 -> Container -> AsyncLock2 -> Value
645    ///
646    /// # Example
647    /// ```ignore
648    /// // Root -> Arc<tokio::Mutex<Container>> -> Container -> Arc<tokio::Mutex<Value>> -> Value
649    /// let async_kp1 = AsyncLockKp::new(...); // Root -> Container
650    /// let async_kp2 = AsyncLockKp::new(...); // Container -> Value
651    /// let chained = async_kp1.then_async(async_kp2);
652    /// let result = chained.get(&root).await;
653    /// ```
654    pub fn then_async<
655        Lock2,
656        Mid2,
657        V2,
658        LockValue2,
659        MidValue2,
660        Value2,
661        MutLock2,
662        MutMid2,
663        MutValue2,
664        G2_1,
665        S2_1,
666        L2,
667        G2_2,
668        S2_2,
669    >(
670        self,
671        other: AsyncLockKp<
672            V,
673            Lock2,
674            Mid2,
675            V2,
676            Value,
677            LockValue2,
678            MidValue2,
679            Value2,
680            MutValue,
681            MutLock2,
682            MutMid2,
683            MutValue2,
684            G2_1,
685            S2_1,
686            L2,
687            G2_2,
688            S2_2,
689        >,
690    ) -> ComposedAsyncLockKp<
691        R,
692        V2,
693        Root,
694        Value2,
695        MutRoot,
696        MutValue2,
697        Self,
698        AsyncLockKp<
699            V,
700            Lock2,
701            Mid2,
702            V2,
703            Value,
704            LockValue2,
705            MidValue2,
706            Value2,
707            MutValue,
708            MutLock2,
709            MutMid2,
710            MutValue2,
711            G2_1,
712            S2_1,
713            L2,
714            G2_2,
715            S2_2,
716        >,
717    >
718    where
719        Lock: Clone,
720        Lock2: Clone,
721        V: 'static,
722        V2: 'static,
723        Value: std::borrow::Borrow<V>,
724        LockValue2: std::borrow::Borrow<Lock2>,
725        MidValue2: std::borrow::Borrow<Mid2>,
726        Value2: std::borrow::Borrow<V2>,
727        MutValue: std::borrow::BorrowMut<V>,
728        MutLock2: std::borrow::BorrowMut<Lock2>,
729        MutMid2: std::borrow::BorrowMut<Mid2>,
730        MutValue2: std::borrow::BorrowMut<V2>,
731        G2_1: Fn(Value) -> Option<LockValue2> + Clone,
732        S2_1: Fn(MutValue) -> Option<MutLock2> + Clone,
733        L2: AsyncLockLike<Lock2, MidValue2> + AsyncLockLike<Lock2, MutMid2> + Clone,
734        G2_2: Fn(MidValue2) -> Option<Value2> + Clone,
735        S2_2: Fn(MutMid2) -> Option<MutValue2> + Clone,
736    {
737        ComposedAsyncLockKp {
738            first: self,
739            second: other,
740            _p: std::marker::PhantomData,
741        }
742    }
743}
744
745// Implement AsyncKeyPathLike for AsyncLockKp so it can be used in composition at any depth.
746#[async_trait(?Send)]
747impl<
748    R,
749    Lock,
750    Mid,
751    V,
752    Root,
753    LockValue,
754    MidValue,
755    Value,
756    MutRoot,
757    MutLock,
758    MutMid,
759    MutValue,
760    G1,
761    S1,
762    L,
763    G2,
764    S2,
765> AsyncKeyPathLike<Root, MutRoot>
766    for AsyncLockKp<R, Lock, Mid, V, Root, LockValue, MidValue, Value, MutRoot, MutLock, MutMid, MutValue, G1, S1, L, G2, S2>
767where
768    Root: std::borrow::Borrow<R>,
769    LockValue: std::borrow::Borrow<Lock>,
770    MidValue: std::borrow::Borrow<Mid>,
771    Value: std::borrow::Borrow<V>,
772    MutRoot: std::borrow::BorrowMut<R>,
773    MutLock: std::borrow::BorrowMut<Lock>,
774    MutMid: std::borrow::BorrowMut<Mid>,
775    MutValue: std::borrow::BorrowMut<V>,
776    G1: Fn(Root) -> Option<LockValue> + Clone,
777    S1: Fn(MutRoot) -> Option<MutLock> + Clone,
778    L: AsyncLockLike<Lock, MidValue> + AsyncLockLike<Lock, MutMid> + Clone,
779    G2: Fn(MidValue) -> Option<Value> + Clone,
780    S2: Fn(MutMid) -> Option<MutValue> + Clone,
781    Lock: Clone,
782{
783    type Value = Value;
784    type MutValue = MutValue;
785    async fn get(&self, root: Root) -> Option<Value> {
786        AsyncLockKp::get(self, root).await
787    }
788    async fn get_mut(&self, root: MutRoot) -> Option<MutValue> {
789        AsyncLockKp::get_mut(self, root).await
790    }
791}
792
793/// Chained async lock keypath: two or more async keypaths (Root -> V -> V2 -> ...). Root is passed at get/get_mut time.
794///
795/// Use [AsyncLockKp::then_async] to create (or [ComposedAsyncLockKp::then_async] for more levels). Then call [ComposedAsyncLockKp::get] or
796/// [ComposedAsyncLockKp::get_mut] with root when you need the value.
797///
798/// Chain any depth: `kp1.then_async(kp2).then_async(kp3).then_async(kp4)...` then `.get(&root).await`.
799#[derive(Clone)]
800pub struct ComposedAsyncLockKp<R, V2, Root, Value2, MutRoot, MutValue2, First, Second> {
801    pub(crate) first: First,
802    pub(crate) second: Second,
803    _p: std::marker::PhantomData<(R, V2, Root, Value2, MutRoot, MutValue2)>,
804}
805
806impl<R, V2, Root, Value2, MutRoot, MutValue2, First, Second>
807    ComposedAsyncLockKp<R, V2, Root, Value2, MutRoot, MutValue2, First, Second>
808where
809    First: AsyncKeyPathLike<Root, MutRoot>,
810    Second: AsyncKeyPathLike<First::Value, First::MutValue, Value = Value2, MutValue = MutValue2>,
811{
812    /// Get through all chained async locks (root is passed here).
813    pub async fn get(&self, root: Root) -> Option<Value2> {
814        let value = self.first.get(root).await?;
815        self.second.get(value).await
816    }
817
818    /// Get mutable through all composed locks (root is passed here).
819    pub async fn get_mut(&self, root: MutRoot) -> Option<MutValue2> {
820        let mut_value = self.first.get_mut(root).await?;
821        self.second.get_mut(mut_value).await
822    }
823
824    /// Chain with another async keypath: `a.then_async(b).then_async(c).get(&root).await`.
825    pub fn then_async<
826        Lock3,
827        Mid3,
828        V3,
829        LockValue3,
830        MidValue3,
831        Value3,
832        MutLock3,
833        MutMid3,
834        MutValue3,
835        G3_1,
836        S3_1,
837        L3,
838        G3_2,
839        S3_2,
840    >(
841        self,
842        other: AsyncLockKp<
843            V2,
844            Lock3,
845            Mid3,
846            V3,
847            Value2,
848            LockValue3,
849            MidValue3,
850            Value3,
851            MutValue2,
852            MutLock3,
853            MutMid3,
854            MutValue3,
855            G3_1,
856            S3_1,
857            L3,
858            G3_2,
859            S3_2,
860        >,
861    ) -> ComposedAsyncLockKp<
862        R,
863        V3,
864        Root,
865        Value3,
866        MutRoot,
867        MutValue3,
868        Self,
869        AsyncLockKp<
870            V2,
871            Lock3,
872            Mid3,
873            V3,
874            Value2,
875            LockValue3,
876            MidValue3,
877            Value3,
878            MutValue2,
879            MutLock3,
880            MutMid3,
881            MutValue3,
882            G3_1,
883            S3_1,
884            L3,
885            G3_2,
886            S3_2,
887        >,
888    >
889    where
890        V2: 'static,
891        V3: 'static,
892        Value2: std::borrow::Borrow<V2>,
893        Value3: std::borrow::Borrow<V3>,
894        MutValue2: std::borrow::BorrowMut<V2>,
895        MutValue3: std::borrow::BorrowMut<V3>,
896        LockValue3: std::borrow::Borrow<Lock3>,
897        MidValue3: std::borrow::Borrow<Mid3>,
898        MutLock3: std::borrow::BorrowMut<Lock3>,
899        MutMid3: std::borrow::BorrowMut<Mid3>,
900        G3_1: Fn(Value2) -> Option<LockValue3> + Clone,
901        S3_1: Fn(MutValue2) -> Option<MutLock3> + Clone,
902        L3: AsyncLockLike<Lock3, MidValue3> + AsyncLockLike<Lock3, MutMid3> + Clone,
903        G3_2: Fn(MidValue3) -> Option<Value3> + Clone,
904        S3_2: Fn(MutMid3) -> Option<MutValue3> + Clone,
905        Lock3: Clone,
906    {
907        ComposedAsyncLockKp {
908            first: self,
909            second: other,
910            _p: std::marker::PhantomData,
911        }
912    }
913
914    /// Chain with a regular [crate::Kp] (no root at call site). Use `.get(&root).await` later.
915    pub fn then<V3, Value3, MutValue3, G3, S3>(
916        self,
917        next_kp: crate::Kp<V2, V3, Value2, Value3, MutValue2, MutValue3, G3, S3>,
918    ) -> AsyncKeyPathThenKp<R, V3, Root, Value3, MutRoot, MutValue3, Self, crate::Kp<V2, V3, Value2, Value3, MutValue2, MutValue3, G3, S3>>
919    where
920        V2: 'static,
921        V3: 'static,
922        Value2: std::borrow::Borrow<V2>,
923        Value3: std::borrow::Borrow<V3>,
924        MutValue2: std::borrow::BorrowMut<V2>,
925        MutValue3: std::borrow::BorrowMut<V3>,
926        G3: Fn(Value2) -> Option<Value3> + Clone,
927        S3: Fn(MutValue2) -> Option<MutValue3> + Clone,
928    {
929        AsyncKeyPathThenKp {
930            first: self,
931            second: next_kp,
932            _p: std::marker::PhantomData,
933        }
934    }
935
936    /// Chain with a sync [crate::lock::LockKp] (no root at call site). Use `.get(&root).await` later.
937    pub fn then_lock<
938        Lock3,
939        Mid3,
940        V3,
941        LockValue3,
942        MidValue3,
943        Value3,
944        MutLock3,
945        MutMid3,
946        MutValue3,
947        G3_1,
948        S3_1,
949        L3,
950        G3_2,
951        S3_2,
952    >(
953        self,
954        lock_kp: crate::lock::LockKp<V2, Lock3, Mid3, V3, Value2, LockValue3, MidValue3, Value3, MutValue2, MutLock3, MutMid3, MutValue3, G3_1, S3_1, L3, G3_2, S3_2>,
955    ) -> AsyncLockKpThenLockKp<R, V3, Root, Value3, MutRoot, MutValue3, Self, crate::lock::LockKp<V2, Lock3, Mid3, V3, Value2, LockValue3, MidValue3, Value3, MutValue2, MutLock3, MutMid3, MutValue3, G3_1, S3_1, L3, G3_2, S3_2>>
956    where
957        V2: 'static,
958        V3: 'static,
959        Value2: std::borrow::Borrow<V2>,
960        Value3: std::borrow::Borrow<V3>,
961        MutValue2: std::borrow::BorrowMut<V2>,
962        MutValue3: std::borrow::BorrowMut<V3>,
963        LockValue3: std::borrow::Borrow<Lock3>,
964        MidValue3: std::borrow::Borrow<Mid3>,
965        MutLock3: std::borrow::BorrowMut<Lock3>,
966        MutMid3: std::borrow::BorrowMut<Mid3>,
967        G3_1: Fn(Value2) -> Option<LockValue3>,
968        S3_1: Fn(MutValue2) -> Option<MutLock3>,
969        L3: crate::lock::LockAccess<Lock3, MidValue3> + crate::lock::LockAccess<Lock3, MutMid3>,
970        G3_2: Fn(MidValue3) -> Option<Value3>,
971        S3_2: Fn(MutMid3) -> Option<MutValue3>,
972    {
973        AsyncLockKpThenLockKp {
974            first: self,
975            second: lock_kp,
976            _p: std::marker::PhantomData,
977        }
978    }
979}
980
981/// Keypath that chains a sync keypath ([crate::Kp]) with an [AsyncKeyPathLike]. Use [crate::Kp::then_async] to create; then `.get(&root).await`.
982#[derive(Clone)]
983pub struct KpThenAsyncKeyPath<R, V, V2, Root, Value, Value2, MutRoot, MutValue, MutValue2, First, Second> {
984    pub(crate) first: First,
985    pub(crate) second: Second,
986    pub(crate) _p: std::marker::PhantomData<(R, V, V2, Root, Value, Value2, MutRoot, MutValue, MutValue2)>,
987}
988
989impl<R, V, V2, Root, Value, Value2, MutRoot, MutValue, MutValue2, First, Second>
990    KpThenAsyncKeyPath<R, V, V2, Root, Value, Value2, MutRoot, MutValue, MutValue2, First, Second>
991where
992    First: SyncKeyPathLike<Root, Value, MutRoot, MutValue>,
993    Second: AsyncKeyPathLike<Value, MutValue, Value = Value2, MutValue = MutValue2>,
994{
995    /// Get through sync keypath then async keypath (root is passed here).
996    #[inline]
997    pub async fn get(&self, root: Root) -> Option<Value2> {
998        let v = self.first.sync_get(root)?;
999        self.second.get(v).await
1000    }
1001    /// Get mutable through sync then async (root is passed here).
1002    #[inline]
1003    pub async fn get_mut(&self, root: MutRoot) -> Option<MutValue2> {
1004        let mut_v = self.first.sync_get_mut(root)?;
1005        self.second.get_mut(mut_v).await
1006    }
1007}
1008
1009#[async_trait(?Send)]
1010impl<R, V, V2, Root, Value, Value2, MutRoot, MutValue, MutValue2, First, Second>
1011    AsyncKeyPathLike<Root, MutRoot> for KpThenAsyncKeyPath<R, V, V2, Root, Value, Value2, MutRoot, MutValue, MutValue2, First, Second>
1012where
1013    First: SyncKeyPathLike<Root, Value, MutRoot, MutValue>,
1014    Second: AsyncKeyPathLike<Value, MutValue, Value = Value2, MutValue = MutValue2>,
1015{
1016    type Value = Value2;
1017    type MutValue = MutValue2;
1018    async fn get(&self, root: Root) -> Option<Value2> {
1019        let v = self.first.sync_get(root)?;
1020        self.second.get(v).await
1021    }
1022    async fn get_mut(&self, root: MutRoot) -> Option<MutValue2> {
1023        let mut_v = self.first.sync_get_mut(root)?;
1024        self.second.get_mut(mut_v).await
1025    }
1026}
1027
1028impl<R, V, V2, Root, Value, Value2, MutRoot, MutValue, MutValue2, First, Second>
1029    KpThenAsyncKeyPath<R, V, V2, Root, Value, Value2, MutRoot, MutValue, MutValue2, First, Second>
1030where
1031    First: SyncKeyPathLike<Root, Value, MutRoot, MutValue>,
1032    Second: AsyncKeyPathLike<Value, MutValue, Value = Value2, MutValue = MutValue2>,
1033{
1034    /// Chain with a [crate::Kp]. Use `.get(&root).await` later.
1035    pub fn then<V3, Value3, MutValue3, G3, S3>(
1036        self,
1037        next_kp: crate::Kp<V2, V3, Value2, Value3, MutValue2, MutValue3, G3, S3>,
1038    ) -> AsyncKeyPathThenKp<R, V3, Root, Value3, MutRoot, MutValue3, Self, crate::Kp<V2, V3, Value2, Value3, MutValue2, MutValue3, G3, S3>>
1039    where
1040        V3: 'static,
1041        Value2: std::borrow::Borrow<V2>,
1042        MutValue2: std::borrow::BorrowMut<V2>,
1043        Value3: std::borrow::Borrow<V3>,
1044        MutValue3: std::borrow::BorrowMut<V3>,
1045        G3: Fn(Value2) -> Option<Value3> + Clone,
1046        S3: Fn(MutValue2) -> Option<MutValue3> + Clone,
1047    {
1048        AsyncKeyPathThenKp {
1049            first: self,
1050            second: next_kp,
1051            _p: std::marker::PhantomData,
1052        }
1053    }
1054}
1055
1056/// Keypath that chains an [AsyncKeyPathLike] (async get) with a [crate::Kp] (sync step). Use `.get(&root).await` to run.
1057#[derive(Clone)]
1058pub struct AsyncKeyPathThenKp<R, V2, Root, Value2, MutRoot, MutValue2, First, Second> {
1059    pub(crate) first: First,
1060    pub(crate) second: Second,
1061    _p: std::marker::PhantomData<(R, V2, Root, Value2, MutRoot, MutValue2)>,
1062}
1063
1064/// Impl when Second is a Kp whose input type is First::Value (covers both Kp<First::Value, V2, ...> and Kp<RKp, V2, First::Value, ...>).
1065impl<R, V2, Root, Value2, MutRoot, MutValue2, First, RKp, G, S>
1066    AsyncKeyPathThenKp<R, V2, Root, Value2, MutRoot, MutValue2, First, crate::Kp<RKp, V2, First::Value, Value2, First::MutValue, MutValue2, G, S>>
1067where
1068    First: AsyncKeyPathLike<Root, MutRoot>,
1069    First::Value: std::borrow::Borrow<RKp>,
1070    First::MutValue: std::borrow::BorrowMut<RKp>,
1071    Value2: std::borrow::Borrow<V2>,
1072    MutValue2: std::borrow::BorrowMut<V2>,
1073    G: Fn(First::Value) -> Option<Value2>,
1074    S: Fn(First::MutValue) -> Option<MutValue2>,
1075{
1076    /// Get through async keypath then Kp (root is passed here).
1077    #[inline]
1078    pub async fn get(&self, root: Root) -> Option<Value2> {
1079        let value = self.first.get(root).await?;
1080        (self.second.get)(value)
1081    }
1082    /// Get mutable through async keypath then Kp (root is passed here).
1083    #[inline]
1084    pub async fn get_mut(&self, root: MutRoot) -> Option<MutValue2> {
1085        let mut_value = self.first.get_mut(root).await?;
1086        (self.second.set)(mut_value)
1087    }
1088}
1089
1090#[async_trait(?Send)]
1091impl<R, V2, Root, Value2, MutRoot, MutValue2, First, Second>
1092    AsyncKeyPathLike<Root, MutRoot> for ComposedAsyncLockKp<R, V2, Root, Value2, MutRoot, MutValue2, First, Second>
1093where
1094    First: AsyncKeyPathLike<Root, MutRoot>,
1095    Second: AsyncKeyPathLike<First::Value, First::MutValue, Value = Value2, MutValue = MutValue2>,
1096{
1097    type Value = Value2;
1098    type MutValue = MutValue2;
1099    async fn get(&self, root: Root) -> Option<Value2> {
1100        ComposedAsyncLockKp::get(self, root).await
1101    }
1102    async fn get_mut(&self, root: MutRoot) -> Option<MutValue2> {
1103        ComposedAsyncLockKp::get_mut(self, root).await
1104    }
1105}
1106
1107// =============================================================================
1108// AsyncLockKpThenLockKp: AsyncLockKp .then_lock(LockKp) — async then sync lock
1109// =============================================================================
1110
1111/// Keypath that goes through an async lock then a sync [crate::lock::LockKp].
1112/// Use [AsyncLockKp::then_lock] to create; then call [AsyncLockKpThenLockKp::get] or [AsyncLockKpThenLockKp::get_mut] with root.
1113#[derive(Clone)]
1114pub struct AsyncLockKpThenLockKp<R, V2, Root, Value2, MutRoot, MutValue2, First, Second> {
1115    pub(crate) first: First,
1116    pub(crate) second: Second,
1117    _p: std::marker::PhantomData<(R, V2, Root, Value2, MutRoot, MutValue2)>,
1118}
1119
1120impl<
1121        R,
1122        V2,
1123        Root,
1124        Value2,
1125        MutRoot,
1126        MutValue2,
1127        Lock,
1128        Mid,
1129        V,
1130        LockValue,
1131        MidValue,
1132        Value,
1133        MutLock,
1134        MutMid,
1135        MutValue,
1136        G1,
1137        S1,
1138        L,
1139        G2,
1140        S2,
1141        Lock2,
1142        Mid2,
1143        LockValue2,
1144        MidValue2,
1145        MutLock2,
1146        MutMid2,
1147        G2_1,
1148        S2_1,
1149        L2,
1150        G2_2,
1151        S2_2,
1152    >
1153    AsyncLockKpThenLockKp<
1154        R,
1155        V2,
1156        Root,
1157        Value2,
1158        MutRoot,
1159        MutValue2,
1160        AsyncLockKp<R, Lock, Mid, V, Root, LockValue, MidValue, Value, MutRoot, MutLock, MutMid, MutValue, G1, S1, L, G2, S2>,
1161        crate::lock::LockKp<V, Lock2, Mid2, V2, Value, LockValue2, MidValue2, Value2, MutValue, MutLock2, MutMid2, MutValue2, G2_1, S2_1, L2, G2_2, S2_2>,
1162    >
1163where
1164    Root: std::borrow::Borrow<R>,
1165    LockValue: std::borrow::Borrow<Lock>,
1166    MidValue: std::borrow::Borrow<Mid>,
1167    Value: std::borrow::Borrow<V>,
1168    MutRoot: std::borrow::BorrowMut<R>,
1169    MutLock: std::borrow::BorrowMut<Lock>,
1170    MutMid: std::borrow::BorrowMut<Mid>,
1171    MutValue: std::borrow::BorrowMut<V>,
1172    Value2: std::borrow::Borrow<V2>,
1173    MutValue2: std::borrow::BorrowMut<V2>,
1174    G1: Fn(Root) -> Option<LockValue> + Clone,
1175    S1: Fn(MutRoot) -> Option<MutLock> + Clone,
1176    L: AsyncLockLike<Lock, MidValue> + AsyncLockLike<Lock, MutMid> + Clone,
1177    G2: Fn(MidValue) -> Option<Value> + Clone,
1178    S2: Fn(MutMid) -> Option<MutValue> + Clone,
1179    LockValue2: std::borrow::Borrow<Lock2>,
1180    MidValue2: std::borrow::Borrow<Mid2>,
1181    MutLock2: std::borrow::BorrowMut<Lock2>,
1182    MutMid2: std::borrow::BorrowMut<Mid2>,
1183    G2_1: Fn(Value) -> Option<LockValue2>,
1184    S2_1: Fn(MutValue) -> Option<MutLock2>,
1185    L2: crate::lock::LockAccess<Lock2, MidValue2> + crate::lock::LockAccess<Lock2, MutMid2>,
1186    G2_2: Fn(MidValue2) -> Option<Value2>,
1187    S2_2: Fn(MutMid2) -> Option<MutValue2>,
1188    Lock: Clone,
1189    V: Clone,
1190    V2: Clone,
1191{
1192    /// Get through async lock then sync lock (root is passed here).
1193    pub async fn get(&self, root: Root) -> Option<Value2> {
1194        let value = self.first.get(root).await?;
1195        self.second.get(value)
1196    }
1197
1198    /// Get mutable through async lock then sync lock (root is passed here).
1199    pub async fn get_mut(&self, root: MutRoot) -> Option<MutValue2> {
1200        let mut_value = self.first.get_mut(root).await?;
1201        self.second.get_mut(mut_value)
1202    }
1203}
1204
1205// AsyncLockKpThenLockKp when First is ComposedAsyncLockKp (so ComposedAsyncLockKp::then_lock works).
1206impl<
1207        R,
1208        V2,
1209        Root,
1210        Value2,
1211        MutRoot,
1212        MutValue2,
1213        Lock3,
1214        Mid3,
1215        LockValue3,
1216        MidValue3,
1217        MutLock3,
1218        MutMid3,
1219        G3_1,
1220        S3_1,
1221        L3,
1222        G3_2,
1223        S3_2,
1224        First,
1225        Second,
1226    >
1227    AsyncLockKpThenLockKp<
1228        R,
1229        V2,
1230        Root,
1231        Value2,
1232        MutRoot,
1233        MutValue2,
1234        ComposedAsyncLockKp<R, V2, Root, Value2, MutRoot, MutValue2, First, Second>,
1235        crate::lock::LockKp<Value2, Lock3, Mid3, V2, Value2, LockValue3, MidValue3, Value2, MutValue2, MutLock3, MutMid3, MutValue2, G3_1, S3_1, L3, G3_2, S3_2>,
1236    >
1237where
1238    First: AsyncKeyPathLike<Root, MutRoot>,
1239    Second: AsyncKeyPathLike<First::Value, First::MutValue, Value = Value2, MutValue = MutValue2>,
1240    Value2: std::borrow::Borrow<V2>,
1241    MutValue2: std::borrow::BorrowMut<Value2> + std::borrow::BorrowMut<V2>,
1242    LockValue3: std::borrow::Borrow<Lock3>,
1243    MidValue3: std::borrow::Borrow<Mid3>,
1244    MutLock3: std::borrow::BorrowMut<Lock3>,
1245    MutMid3: std::borrow::BorrowMut<Mid3>,
1246    G3_1: Fn(Value2) -> Option<LockValue3>,
1247    S3_1: Fn(MutValue2) -> Option<MutLock3>,
1248    L3: crate::lock::LockAccess<Lock3, MidValue3> + crate::lock::LockAccess<Lock3, MutMid3>,
1249    G3_2: Fn(MidValue3) -> Option<Value2>,
1250    S3_2: Fn(MutMid3) -> Option<MutValue2>,
1251    Value2: Clone,
1252    V2: Clone,
1253{
1254    /// Get through composed async then sync lock (root is passed here).
1255    pub async fn get(&self, root: Root) -> Option<Value2> {
1256        let value = self.first.get(root).await?;
1257        self.second.get(value)
1258    }
1259    /// Get mutable through composed async then sync lock (root is passed here).
1260    pub async fn get_mut(&self, root: MutRoot) -> Option<MutValue2> {
1261        let mut_value = self.first.get_mut(root).await?;
1262        self.second.get_mut(mut_value)
1263    }
1264}
1265
1266// AsyncLockKpThenLockKp when First is AsyncLockKpThenLockKp (nested; enables .then_lock().then_lock() chains).
1267impl<
1268        R,
1269        V2,
1270        Root,
1271        Value2,
1272        MutRoot,
1273        MutValue2,
1274        Lock3,
1275        Mid3,
1276        LockValue3,
1277        MidValue3,
1278        MutLock3,
1279        MutMid3,
1280        G3_1,
1281        S3_1,
1282        L3,
1283        G3_2,
1284        S3_2,
1285        F,
1286        S,
1287    >
1288    AsyncLockKpThenLockKp<
1289        R,
1290        V2,
1291        Root,
1292        Value2,
1293        MutRoot,
1294        MutValue2,
1295        AsyncLockKpThenLockKp<R, V2, Root, Value2, MutRoot, MutValue2, F, S>,
1296        crate::lock::LockKp<Value2, Lock3, Mid3, V2, Value2, LockValue3, MidValue3, Value2, MutValue2, MutLock3, MutMid3, MutValue2, G3_1, S3_1, L3, G3_2, S3_2>,
1297    >
1298where
1299    F: AsyncKeyPathLike<Root, MutRoot, Value = Value2, MutValue = MutValue2>,
1300    S: SyncKeyPathLike<Value2, Value2, MutValue2, MutValue2>,
1301    Value2: std::borrow::Borrow<V2>,
1302    MutValue2: std::borrow::BorrowMut<Value2> + std::borrow::BorrowMut<V2>,
1303    LockValue3: std::borrow::Borrow<Lock3>,
1304    MidValue3: std::borrow::Borrow<Mid3>,
1305    MutLock3: std::borrow::BorrowMut<Lock3>,
1306    MutMid3: std::borrow::BorrowMut<Mid3>,
1307    G3_1: Fn(Value2) -> Option<LockValue3>,
1308    S3_1: Fn(MutValue2) -> Option<MutLock3>,
1309    L3: crate::lock::LockAccess<Lock3, MidValue3> + crate::lock::LockAccess<Lock3, MutMid3>,
1310    G3_2: Fn(MidValue3) -> Option<Value2>,
1311    S3_2: Fn(MutMid3) -> Option<MutValue2>,
1312    Value2: Clone,
1313    V2: Clone,
1314{
1315    /// Get through async then sync then sync lock (root is passed here).
1316    pub async fn get(&self, root: Root) -> Option<Value2> {
1317        let value = AsyncKeyPathLike::get(&self.first, root).await?;
1318        self.second.get(value)
1319    }
1320    /// Get mutable through async then sync then sync lock (root is passed here).
1321    pub async fn get_mut(&self, root: MutRoot) -> Option<MutValue2> {
1322        let mut_value = AsyncKeyPathLike::get_mut(&self.first, root).await?;
1323        self.second.get_mut(mut_value)
1324    }
1325}
1326
1327// Blanket AsyncKeyPathLike for AsyncLockKpThenLockKp so nested chains (then_lock().then_lock()) work.
1328#[async_trait(?Send)]
1329impl<R, V2, Root, Value2, MutRoot, MutValue2, First, Second> AsyncKeyPathLike<Root, MutRoot>
1330    for AsyncLockKpThenLockKp<R, V2, Root, Value2, MutRoot, MutValue2, First, Second>
1331where
1332    First: AsyncKeyPathLike<Root, MutRoot>,
1333    Second: SyncKeyPathLike<First::Value, Value2, First::MutValue, MutValue2>,
1334{
1335    type Value = Value2;
1336    type MutValue = MutValue2;
1337    async fn get(&self, root: Root) -> Option<Value2> {
1338        let value = AsyncKeyPathLike::get(&self.first, root).await?;
1339        SyncKeyPathLike::sync_get(&self.second, value)
1340    }
1341    async fn get_mut(&self, root: MutRoot) -> Option<MutValue2> {
1342        let mut_value = AsyncKeyPathLike::get_mut(&self.first, root).await?;
1343        SyncKeyPathLike::sync_get_mut(&self.second, mut_value)
1344    }
1345}
1346
1347// then_lock and then on AsyncLockKpThenLockKp so chains can continue.
1348impl<R, V2, Root, Value2, MutRoot, MutValue2, First, Second> AsyncLockKpThenLockKp<R, V2, Root, Value2, MutRoot, MutValue2, First, Second>
1349where
1350    First: AsyncKeyPathLike<Root, MutRoot>,
1351{
1352    /// Chain with an async keypath (e.g. tokio RwLock): ... -> Value2 -> async lock -> Value3.
1353    /// Use `.get(&root).await` or `.get_mut(...).await` on the returned [ComposedAsyncLockKp].
1354    pub fn then_async<
1355        Lock3,
1356        Mid3,
1357        V3,
1358        LockValue3,
1359        MidValue3,
1360        Value3,
1361        MutLock3,
1362        MutMid3,
1363        MutValue3,
1364        G3_1,
1365        S3_1,
1366        L3,
1367        G3_2,
1368        S3_2,
1369    >(
1370        self,
1371        other: AsyncLockKp<
1372            Value2,
1373            Lock3,
1374            Mid3,
1375            V3,
1376            Value2,
1377            LockValue3,
1378            MidValue3,
1379            Value3,
1380            MutValue2,
1381            MutLock3,
1382            MutMid3,
1383            MutValue3,
1384            G3_1,
1385            S3_1,
1386            L3,
1387            G3_2,
1388            S3_2,
1389        >,
1390    ) -> ComposedAsyncLockKp<
1391        Root,
1392        V3,
1393        Root,
1394        Value3,
1395        MutRoot,
1396        MutValue3,
1397        Self,
1398        AsyncLockKp<
1399            Value2,
1400            Lock3,
1401            Mid3,
1402            V3,
1403            Value2,
1404            LockValue3,
1405            MidValue3,
1406            Value3,
1407            MutValue2,
1408            MutLock3,
1409            MutMid3,
1410            MutValue3,
1411            G3_1,
1412            S3_1,
1413            L3,
1414            G3_2,
1415            S3_2,
1416        >,
1417    >
1418    where
1419        V2: 'static,
1420        V3: 'static,
1421        Value2: std::borrow::Borrow<V2>,
1422        Value3: std::borrow::Borrow<V3>,
1423        MutValue2: std::borrow::BorrowMut<V2> + std::borrow::BorrowMut<Value2>,
1424        MutValue3: std::borrow::BorrowMut<V3>,
1425        LockValue3: std::borrow::Borrow<Lock3>,
1426        MidValue3: std::borrow::Borrow<Mid3>,
1427        MutLock3: std::borrow::BorrowMut<Lock3>,
1428        MutMid3: std::borrow::BorrowMut<Mid3>,
1429        G3_1: Fn(Value2) -> Option<LockValue3> + Clone,
1430        S3_1: Fn(MutValue2) -> Option<MutLock3> + Clone,
1431        L3: AsyncLockLike<Lock3, MidValue3> + AsyncLockLike<Lock3, MutMid3> + Clone,
1432        G3_2: Fn(MidValue3) -> Option<Value3> + Clone,
1433        S3_2: Fn(MutMid3) -> Option<MutValue3> + Clone,
1434        Lock3: Clone,
1435    {
1436        ComposedAsyncLockKp {
1437            first: self,
1438            second: other,
1439            _p: std::marker::PhantomData,
1440        }
1441    }
1442
1443    /// Chain with another sync [crate::lock::LockKp]. Use `.get(&root).await` later.
1444    pub fn then_lock<
1445        Lock3,
1446        Mid3,
1447        V3,
1448        LockValue3,
1449        MidValue3,
1450        Value3,
1451        MutLock3,
1452        MutMid3,
1453        MutValue3,
1454        G3_1,
1455        S3_1,
1456        L3,
1457        G3_2,
1458        S3_2,
1459    >(
1460        self,
1461        lock_kp: crate::lock::LockKp<Value2, Lock3, Mid3, V3, Value2, LockValue3, MidValue3, Value3, MutValue2, MutLock3, MutMid3, MutValue3, G3_1, S3_1, L3, G3_2, S3_2>,
1462    ) -> AsyncLockKpThenLockKp<R, V3, Root, Value3, MutRoot, MutValue3, Self, crate::lock::LockKp<Value2, Lock3, Mid3, V3, Value2, LockValue3, MidValue3, Value3, MutValue2, MutLock3, MutMid3, MutValue3, G3_1, S3_1, L3, G3_2, S3_2>>
1463    where
1464        V3: 'static,
1465        Value2: std::borrow::Borrow<V2>,
1466        Value3: std::borrow::Borrow<V3>,
1467        MutValue2: std::borrow::BorrowMut<Value2>,
1468        MutValue3: std::borrow::BorrowMut<V3>,
1469        LockValue3: std::borrow::Borrow<Lock3>,
1470        MidValue3: std::borrow::Borrow<Mid3>,
1471        MutLock3: std::borrow::BorrowMut<Lock3>,
1472        MutMid3: std::borrow::BorrowMut<Mid3>,
1473        G3_1: Fn(Value2) -> Option<LockValue3>,
1474        S3_1: Fn(MutValue2) -> Option<MutLock3>,
1475        L3: crate::lock::LockAccess<Lock3, MidValue3> + crate::lock::LockAccess<Lock3, MutMid3>,
1476        G3_2: Fn(MidValue3) -> Option<Value3>,
1477        S3_2: Fn(MutMid3) -> Option<MutValue3>,
1478    {
1479        AsyncLockKpThenLockKp {
1480            first: self,
1481            second: lock_kp,
1482            _p: std::marker::PhantomData,
1483        }
1484    }
1485
1486    /// Chain with a regular [crate::Kp]. Use `.get(&root).await` later.
1487    pub fn then<V3, Value3, MutValue3, G3, S3>(
1488        self,
1489        next_kp: crate::Kp<Value2, V3, Value2, Value3, MutValue2, MutValue3, G3, S3>,
1490    ) -> AsyncKeyPathThenKp<R, V3, Root, Value3, MutRoot, MutValue3, Self, crate::Kp<Value2, V3, Value2, Value3, MutValue2, MutValue3, G3, S3>>
1491    where
1492        V3: 'static,
1493        Value2: std::borrow::Borrow<V2>,
1494        Value3: std::borrow::Borrow<V3>,
1495        MutValue2: std::borrow::BorrowMut<Value2>,
1496        MutValue3: std::borrow::BorrowMut<V3>,
1497        G3: Fn(Value2) -> Option<Value3> + Clone,
1498        S3: Fn(MutValue2) -> Option<MutValue3> + Clone,
1499    {
1500        AsyncKeyPathThenKp {
1501            first: self,
1502            second: next_kp,
1503            _p: std::marker::PhantomData,
1504        }
1505    }
1506}
1507
1508// ============================================================================
1509// Tokio Mutex Access Implementation
1510// ============================================================================
1511
1512#[cfg(feature = "tokio")]
1513/// Async lock access implementation for Arc<tokio::sync::Mutex<T>>
1514///
1515/// # Cloning Behavior
1516///
1517/// This struct only contains `PhantomData<T>`.
1518/// Cloning is a **zero-cost operation** - no data is copied.
1519#[derive(Clone)] // ZERO-COST: Only clones PhantomData (zero-sized type)
1520pub struct TokioMutexAccess<T> {
1521    _phantom: std::marker::PhantomData<T>,
1522}
1523
1524#[cfg(feature = "tokio")]
1525impl<T> TokioMutexAccess<T> {
1526    pub fn new() -> Self {
1527        Self {
1528            _phantom: std::marker::PhantomData,
1529        }
1530    }
1531}
1532
1533#[cfg(feature = "tokio")]
1534impl<T> Default for TokioMutexAccess<T> {
1535    fn default() -> Self {
1536        Self::new()
1537    }
1538}
1539
1540// Implementation for immutable access
1541#[cfg(feature = "tokio")]
1542#[async_trait]
1543impl<'a, T: 'static + Send + Sync> AsyncLockLike<Arc<tokio::sync::Mutex<T>>, &'a T>
1544    for TokioMutexAccess<T>
1545{
1546    #[inline]
1547    async fn lock_read(&self, lock: &Arc<tokio::sync::Mutex<T>>) -> Option<&'a T> {
1548        // SHALLOW CLONE: Only Arc refcount is incremented
1549        let guard = lock.lock().await;
1550        let ptr = &*guard as *const T;
1551        unsafe { Some(&*ptr) }
1552    }
1553
1554    #[inline]
1555    async fn lock_write(&self, lock: &mut Arc<tokio::sync::Mutex<T>>) -> Option<&'a T> {
1556        let guard = lock.lock().await;
1557        let ptr = &*guard as *const T;
1558        unsafe { Some(&*ptr) }
1559    }
1560}
1561
1562// Implementation for mutable access
1563#[cfg(feature = "tokio")]
1564#[async_trait]
1565impl<'a, T: 'static + Send + Sync> AsyncLockLike<Arc<tokio::sync::Mutex<T>>, &'a mut T>
1566    for TokioMutexAccess<T>
1567{
1568    #[inline]
1569    async fn lock_read(&self, lock: &Arc<tokio::sync::Mutex<T>>) -> Option<&'a mut T> {
1570        // SHALLOW CLONE: Only Arc refcount is incremented
1571        let mut guard = lock.lock().await;
1572        let ptr = &mut *guard as *mut T;
1573        unsafe { Some(&mut *ptr) }
1574    }
1575
1576    #[inline]
1577    async fn lock_write(&self, lock: &mut Arc<tokio::sync::Mutex<T>>) -> Option<&'a mut T> {
1578        let mut guard = lock.lock().await;
1579        let ptr = &mut *guard as *mut T;
1580        unsafe { Some(&mut *ptr) }
1581    }
1582}
1583
1584// ============================================================================
1585// Tokio RwLock Access Implementation
1586// ============================================================================
1587
1588#[cfg(feature = "tokio")]
1589/// Async lock access implementation for Arc<tokio::sync::RwLock<T>>
1590///
1591/// # Cloning Behavior
1592///
1593/// This struct only contains `PhantomData<T>`.
1594/// Cloning is a **zero-cost operation** - no data is copied.
1595/// Manual Clone impl so `T: Clone` is not required (e.g. for `Level3` with `RwLock<i32>`).
1596pub struct TokioRwLockAccess<T> {
1597    _phantom: std::marker::PhantomData<T>,
1598}
1599
1600#[cfg(feature = "tokio")]
1601impl<T> TokioRwLockAccess<T> {
1602    pub fn new() -> Self {
1603        Self {
1604            _phantom: std::marker::PhantomData,
1605        }
1606    }
1607}
1608
1609#[cfg(feature = "tokio")]
1610impl<T> Default for TokioRwLockAccess<T> {
1611    fn default() -> Self {
1612        Self::new()
1613    }
1614}
1615
1616#[cfg(feature = "tokio")]
1617impl<T> Clone for TokioRwLockAccess<T> {
1618    fn clone(&self) -> Self {
1619        Self {
1620            _phantom: self._phantom,
1621        }
1622    }
1623}
1624
1625// Implementation for immutable access (read lock)
1626#[cfg(feature = "tokio")]
1627#[async_trait]
1628impl<'a, T: 'static + Send + Sync> AsyncLockLike<Arc<tokio::sync::RwLock<T>>, &'a T>
1629    for TokioRwLockAccess<T>
1630{
1631    async fn lock_read(&self, lock: &Arc<tokio::sync::RwLock<T>>) -> Option<&'a T> {
1632        // SHALLOW CLONE: Only Arc refcount is incremented
1633        let guard = lock.read().await;
1634        let ptr = &*guard as *const T;
1635        unsafe { Some(&*ptr) }
1636    }
1637
1638    async fn lock_write(&self, lock: &mut Arc<tokio::sync::RwLock<T>>) -> Option<&'a T> {
1639        // For immutable access, use read lock
1640        let guard = lock.read().await;
1641        let ptr = &*guard as *const T;
1642        unsafe { Some(&*ptr) }
1643    }
1644}
1645
1646// Implementation for mutable access (write lock)
1647#[cfg(feature = "tokio")]
1648#[async_trait]
1649impl<'a, T: 'static + Send + Sync> AsyncLockLike<Arc<tokio::sync::RwLock<T>>, &'a mut T>
1650    for TokioRwLockAccess<T>
1651{
1652    async fn lock_read(&self, lock: &Arc<tokio::sync::RwLock<T>>) -> Option<&'a mut T> {
1653        // For mutable access, use write lock
1654        let mut guard = lock.write().await;
1655        let ptr = &mut *guard as *mut T;
1656        unsafe { Some(&mut *ptr) }
1657    }
1658
1659    async fn lock_write(&self, lock: &mut Arc<tokio::sync::RwLock<T>>) -> Option<&'a mut T> {
1660        // SHALLOW CLONE: Only Arc refcount is incremented
1661        let mut guard = lock.write().await;
1662        let ptr = &mut *guard as *mut T;
1663        unsafe { Some(&mut *ptr) }
1664    }
1665}
1666
1667// ============================================================================
1668// Type aliases for derive macro (return concrete type to avoid lifetime issues)
1669// ============================================================================
1670//
1671// The keypath object is 'static—references are created when get() is called
1672// with a root, not when the keypath is constructed.
1673
1674#[cfg(feature = "tokio")]
1675/// Type alias for AsyncLockKp over Arc<tokio::sync::Mutex<T>>. Use with derive macro's `_async()` methods.
1676pub type AsyncLockKpMutexFor<Root, Lock, Inner> = AsyncLockKp<
1677    Root,
1678    Lock,
1679    Inner,
1680    Inner,
1681    &'static Root,
1682    &'static Lock,
1683    &'static Inner,
1684    &'static Inner,
1685    &'static mut Root,
1686    &'static mut Lock,
1687    &'static mut Inner,
1688    &'static mut Inner,
1689    for<'b> fn(&'b Root) -> Option<&'b Lock>,
1690    for<'b> fn(&'b mut Root) -> Option<&'b mut Lock>,
1691    TokioMutexAccess<Inner>,
1692    for<'b> fn(&'b Inner) -> Option<&'b Inner>,
1693    for<'b> fn(&'b mut Inner) -> Option<&'b mut Inner>,
1694>;
1695
1696#[cfg(feature = "tokio")]
1697/// Type alias for AsyncLockKp over Arc<tokio::sync::RwLock<T>>. Use with derive macro's `_async()` methods.
1698pub type AsyncLockKpRwLockFor<Root, Lock, Inner> = AsyncLockKp<
1699    Root,
1700    Lock,
1701    Inner,
1702    Inner,
1703    &'static Root,
1704    &'static Lock,
1705    &'static Inner,
1706    &'static Inner,
1707    &'static mut Root,
1708    &'static mut Lock,
1709    &'static mut Inner,
1710    &'static mut Inner,
1711    for<'b> fn(&'b Root) -> Option<&'b Lock>,
1712    for<'b> fn(&'b mut Root) -> Option<&'b mut Lock>,
1713    TokioRwLockAccess<Inner>,
1714    for<'b> fn(&'b Inner) -> Option<&'b Inner>,
1715    for<'b> fn(&'b mut Inner) -> Option<&'b mut Inner>,
1716>;
1717
1718// ============================================================================
1719// Tests
1720// ============================================================================
1721
1722#[cfg(all(test, feature = "tokio"))]
1723mod tests {
1724    use super::*;
1725    use crate::KpType;
1726
1727    #[tokio::test]
1728    async fn test_async_lock_kp_tokio_mutex_basic() {
1729        use tokio::sync::Mutex;
1730
1731        #[derive(Clone)]
1732        struct Root {
1733            data: Arc<Mutex<String>>,
1734        }
1735
1736        let root = Root {
1737            data: Arc::new(Mutex::new("hello".to_string())),
1738        };
1739
1740        // Create AsyncLockKp
1741        let lock_kp = {
1742            let prev: KpType<Root, Arc<Mutex<String>>> =
1743                Kp::new(|r: &Root| Some(&r.data), |r: &mut Root| Some(&mut r.data));
1744            let next: KpType<String, String> =
1745                Kp::new(|s: &String| Some(s), |s: &mut String| Some(s));
1746            AsyncLockKp::new(prev, TokioMutexAccess::new(), next)
1747        };
1748
1749        // Test async get
1750        let value = lock_kp.get(&root).await;
1751        assert!(value.is_some());
1752        assert_eq!(value.unwrap(), &"hello".to_string());
1753    }
1754
1755    #[tokio::test]
1756    async fn test_async_lock_kp_get_optional_or_else() {
1757        use tokio::sync::Mutex;
1758
1759        #[derive(Clone)]
1760        struct Root {
1761            data: Arc<Mutex<i32>>,
1762        }
1763
1764        let mut root = Root {
1765            data: Arc::new(Mutex::new(42)),
1766        };
1767
1768        let lock_kp = {
1769            let prev: KpType<Root, Arc<Mutex<i32>>> =
1770                Kp::new(|r: &Root| Some(&r.data), |r: &mut Root| Some(&mut r.data));
1771            let next: KpType<i32, i32> = Kp::new(|n: &i32| Some(n), |n: &mut i32| Some(n));
1772            AsyncLockKp::new(prev, TokioMutexAccess::new(), next)
1773        };
1774
1775        // get_optional
1776        assert!(lock_kp.get_optional(None).await.is_none());
1777        assert_eq!(lock_kp.get_optional(Some(&root)).await, Some(&42));
1778
1779        // get_mut_optional
1780        assert!(lock_kp.get_mut_optional(None).await.is_none());
1781        if let Some(m) = lock_kp.get_mut_optional(Some(&mut root)).await {
1782            *m = 99;
1783        }
1784        assert_eq!(lock_kp.get(&root).await, Some(&99));
1785
1786        // get_or_else
1787        assert_eq!(*lock_kp.get_or_else(None, || &0).await, 0);
1788        assert_eq!(*lock_kp.get_or_else(Some(&root), || &0).await, 99);
1789
1790        // get_mut_or_else
1791        let m = lock_kp.get_mut_or_else(Some(&mut root), || panic!("unexpected")).await;
1792        *m = 100;
1793        assert_eq!(lock_kp.get(&root).await, Some(&100));
1794    }
1795
1796    #[tokio::test]
1797    async fn test_async_lock_kp_tokio_rwlock_basic() {
1798        use tokio::sync::RwLock;
1799
1800        #[derive(Clone)]
1801        struct Root {
1802            data: Arc<RwLock<Vec<i32>>>,
1803        }
1804
1805        let root = Root {
1806            data: Arc::new(RwLock::new(vec![1, 2, 3, 4, 5])),
1807        };
1808
1809        // Create AsyncLockKp with RwLock
1810        let lock_kp = {
1811            let prev: KpType<Root, Arc<RwLock<Vec<i32>>>> =
1812                Kp::new(|r: &Root| Some(&r.data), |r: &mut Root| Some(&mut r.data));
1813            let next: KpType<Vec<i32>, Vec<i32>> =
1814                Kp::new(|v: &Vec<i32>| Some(v), |v: &mut Vec<i32>| Some(v));
1815            AsyncLockKp::new(prev, TokioRwLockAccess::new(), next)
1816        };
1817
1818        // Test async get with RwLock (read lock)
1819        let value = lock_kp.get(&root).await;
1820        assert!(value.is_some());
1821        assert_eq!(value.unwrap().len(), 5);
1822    }
1823
1824    #[tokio::test]
1825    async fn test_async_lock_kp_concurrent_reads() {
1826        use tokio::sync::RwLock;
1827
1828        #[derive(Clone)]
1829        struct Root {
1830            data: Arc<RwLock<i32>>,
1831        }
1832
1833        let root = Root {
1834            data: Arc::new(RwLock::new(42)),
1835        };
1836
1837        // Create AsyncLockKp
1838        let lock_kp = {
1839            let prev: KpType<Root, Arc<RwLock<i32>>> =
1840                Kp::new(|r: &Root| Some(&r.data), |r: &mut Root| Some(&mut r.data));
1841            let next: KpType<i32, i32> = Kp::new(|n: &i32| Some(n), |n: &mut i32| Some(n));
1842            AsyncLockKp::new(prev, TokioRwLockAccess::new(), next)
1843        };
1844
1845        // Concurrent async reads in the same task (spawn would require 'static future;
1846        // get() returns references so we use join! instead)
1847        let lock_kp2 = {
1848            let prev: KpType<Root, Arc<RwLock<i32>>> =
1849                Kp::new(|r: &Root| Some(&r.data), |r: &mut Root| Some(&mut r.data));
1850            let next: KpType<i32, i32> = Kp::new(|n: &i32| Some(n), |n: &mut i32| Some(n));
1851            AsyncLockKp::new(prev, TokioRwLockAccess::new(), next)
1852        };
1853        let (a, b) = tokio::join!(lock_kp.get(&root), lock_kp2.get(&root));
1854        assert_eq!(a, Some(&42));
1855        assert_eq!(b, Some(&42));
1856
1857        // Test the original lock_kp as well
1858        let value = lock_kp.get(&root).await;
1859        assert_eq!(value, Some(&42));
1860    }
1861
1862    #[tokio::test]
1863    async fn test_async_lock_kp_panic_on_clone_proof() {
1864        use tokio::sync::Mutex;
1865
1866        /// This struct PANICS if cloned - proving no deep cloning occurs
1867        struct PanicOnClone {
1868            data: String,
1869        }
1870
1871        impl Clone for PanicOnClone {
1872            fn clone(&self) -> Self {
1873                panic!("❌ ASYNC DEEP CLONE DETECTED! PanicOnClone was cloned!");
1874            }
1875        }
1876
1877        #[derive(Clone)]
1878        struct Root {
1879            level1: Arc<Mutex<Level1>>,
1880        }
1881
1882        struct Level1 {
1883            panic_data: PanicOnClone,
1884            value: i32,
1885        }
1886
1887        impl Clone for Level1 {
1888            fn clone(&self) -> Self {
1889                panic!("❌ Level1 was deeply cloned in async context!");
1890            }
1891        }
1892
1893        // Create structure with PanicOnClone
1894        let root = Root {
1895            level1: Arc::new(Mutex::new(Level1 {
1896                panic_data: PanicOnClone {
1897                    data: "test".to_string(),
1898                },
1899                value: 123,
1900            })),
1901        };
1902
1903        // Create AsyncLockKp
1904        let lock_kp = {
1905            let prev: KpType<Root, Arc<Mutex<Level1>>> = Kp::new(
1906                |r: &Root| Some(&r.level1),
1907                |r: &mut Root| Some(&mut r.level1),
1908            );
1909            let next: KpType<Level1, i32> = Kp::new(
1910                |l: &Level1| Some(&l.value),
1911                |l: &mut Level1| Some(&mut l.value),
1912            );
1913            AsyncLockKp::new(prev, TokioMutexAccess::new(), next)
1914        };
1915
1916        // CRITICAL TEST: If any deep cloning occurs, PanicOnClone will trigger
1917        let value = lock_kp.get(&root).await;
1918
1919        // ✅ SUCCESS: No panic means no deep cloning!
1920        assert_eq!(value, Some(&123));
1921    }
1922
1923    #[tokio::test]
1924    async fn test_async_lock_kp_structure() {
1925        use tokio::sync::Mutex;
1926
1927        #[derive(Clone)]
1928        struct Root {
1929            data: Arc<Mutex<String>>,
1930        }
1931
1932        let lock_kp = {
1933            let prev: KpType<Root, Arc<Mutex<String>>> =
1934                Kp::new(|r: &Root| Some(&r.data), |r: &mut Root| Some(&mut r.data));
1935            let next: KpType<String, String> =
1936                Kp::new(|s: &String| Some(s), |s: &mut String| Some(s));
1937            AsyncLockKp::new(prev, TokioMutexAccess::new(), next)
1938        };
1939
1940        // Verify structure has three fields (prev, mid, next)
1941        let _ = &lock_kp.prev;
1942        let _ = &lock_kp.mid;
1943        let _ = &lock_kp.next;
1944    }
1945
1946    #[tokio::test]
1947    async fn test_async_kp_then() {
1948        use tokio::sync::Mutex;
1949
1950        #[derive(Clone)]
1951        struct Root {
1952            data: Arc<Mutex<Inner>>,
1953        }
1954
1955        #[derive(Clone)]
1956        struct Inner {
1957            value: i32,
1958        }
1959
1960        let root = Root {
1961            data: Arc::new(Mutex::new(Inner { value: 42 })),
1962        };
1963
1964        // Create AsyncLockKp to Inner
1965        let async_kp = {
1966            let prev: KpType<Root, Arc<Mutex<Inner>>> =
1967                Kp::new(|r: &Root| Some(&r.data), |r: &mut Root| Some(&mut r.data));
1968            let next: KpType<Inner, Inner> = Kp::new(|i: &Inner| Some(i), |i: &mut Inner| Some(i));
1969            AsyncLockKp::new(prev, TokioMutexAccess::new(), next)
1970        };
1971
1972        // Chain with regular Kp to get value field
1973        let value_kp: KpType<Inner, i32> = Kp::new(
1974            |i: &Inner| Some(&i.value),
1975            |i: &mut Inner| Some(&mut i.value),
1976        );
1977
1978        let chained = async_kp.then(value_kp);
1979        let result = chained.get(&root).await;
1980        assert_eq!(result, Some(&42));
1981    }
1982
1983    #[tokio::test]
1984    async fn test_async_kp_later_then() {
1985        use tokio::sync::Mutex;
1986
1987        #[derive(Clone)]
1988        struct Root {
1989            lock1: Arc<Mutex<Container>>,
1990        }
1991
1992        #[derive(Clone)]
1993        struct Container {
1994            lock2: Arc<Mutex<i32>>,
1995        }
1996
1997        let root = Root {
1998            lock1: Arc::new(Mutex::new(Container {
1999                lock2: Arc::new(Mutex::new(999)),
2000            })),
2001        };
2002
2003        // First AsyncLockKp: Root -> Container
2004        let async_kp1 = {
2005            let prev: KpType<Root, Arc<Mutex<Container>>> =
2006                Kp::new(|r: &Root| Some(&r.lock1), |r: &mut Root| Some(&mut r.lock1));
2007            let next: KpType<Container, Container> =
2008                Kp::new(|c: &Container| Some(c), |c: &mut Container| Some(c));
2009            AsyncLockKp::new(prev, TokioMutexAccess::new(), next)
2010        };
2011
2012        // Second AsyncLockKp: Container -> i32
2013        let async_kp2 = {
2014            let prev: KpType<Container, Arc<Mutex<i32>>> = Kp::new(
2015                |c: &Container| Some(&c.lock2),
2016                |c: &mut Container| Some(&mut c.lock2),
2017            );
2018            let next: KpType<i32, i32> = Kp::new(|n: &i32| Some(n), |n: &mut i32| Some(n));
2019            AsyncLockKp::new(prev, TokioMutexAccess::new(), next)
2020        };
2021
2022        // Chain with then_async; get with root
2023        let chained = async_kp1.then_async(async_kp2);
2024        let result = chained.get(&root).await;
2025        assert_eq!(result, Some(&999));
2026    }
2027
2028    #[tokio::test]
2029    async fn test_async_kp_then_async_three_levels() {
2030        use tokio::sync::Mutex;
2031
2032        #[derive(Clone)]
2033        struct Root {
2034            a: Arc<Mutex<Level1>>,
2035        }
2036        #[derive(Clone)]
2037        struct Level1 {
2038            b: Arc<Mutex<Level2>>,
2039        }
2040        #[derive(Clone)]
2041        struct Level2 {
2042            c: Arc<Mutex<i32>>,
2043        }
2044
2045        let root = Root {
2046            a: Arc::new(Mutex::new(Level1 {
2047                b: Arc::new(Mutex::new(Level2 {
2048                    c: Arc::new(Mutex::new(42)),
2049                })),
2050            })),
2051        };
2052
2053        let kp1 = {
2054            let prev: KpType<Root, Arc<Mutex<Level1>>> =
2055                Kp::new(|r: &Root| Some(&r.a), |r: &mut Root| Some(&mut r.a));
2056            let next: KpType<Level1, Level1> =
2057                Kp::new(|l: &Level1| Some(l), |l: &mut Level1| Some(l));
2058            AsyncLockKp::new(prev, TokioMutexAccess::new(), next)
2059        };
2060        let kp2 = {
2061            let prev: KpType<Level1, Arc<Mutex<Level2>>> =
2062                Kp::new(|l: &Level1| Some(&l.b), |l: &mut Level1| Some(&mut l.b));
2063            let next: KpType<Level2, Level2> =
2064                Kp::new(|l: &Level2| Some(l), |l: &mut Level2| Some(l));
2065            AsyncLockKp::new(prev, TokioMutexAccess::new(), next)
2066        };
2067        let kp3 = {
2068            let prev: KpType<Level2, Arc<Mutex<i32>>> =
2069                Kp::new(|l: &Level2| Some(&l.c), |l: &mut Level2| Some(&mut l.c));
2070            let next: KpType<i32, i32> = Kp::new(|n: &i32| Some(n), |n: &mut i32| Some(n));
2071            AsyncLockKp::new(prev, TokioMutexAccess::new(), next)
2072        };
2073
2074        let chained = kp1.then_async(kp2).then_async(kp3);
2075        let result = chained.get(&root).await;
2076        assert_eq!(result, Some(&42));
2077    }
2078}