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