blind_pool/
pooled_mut.rs

1use std::fmt;
2use std::ops::{Deref, DerefMut};
3use std::pin::Pin;
4
5use crate::{BlindPool, Pooled, RawPooled};
6
7/// A mutable reference to a value stored in a [`BlindPool`].
8///
9/// This type provides automatic lifetime management for values in the pool with exclusive access.
10/// When the [`PooledMut`] instance is dropped, the value is automatically removed from the pool.
11///
12/// Unlike [`Pooled<T>`], this type does not implement [`Clone`] and provides exclusive access
13/// through [`DerefMut`], making it suitable for scenarios where mutable access is required
14/// and shared ownership is not needed.
15///
16/// # Thread Safety
17///
18/// [`PooledMut<T>`] implements thread safety traits conditionally based on the stored type `T`:
19///
20/// - **Send**: [`PooledMut<T>`] is [`Send`] if and only if `T` is [`Send`]. This allows moving
21///   pooled mutable references between threads when the referenced type can be moved between threads.
22///
23/// - **Sync**: [`PooledMut<T>`] does NOT implement [`Sync`] because it provides exclusive mutable
24///   access via [`DerefMut`]. Allowing multiple threads to share references to the same
25///   [`PooledMut<T>`] instance would violate Rust's borrowing rules and lead to data races.
26///
27/// # Example
28///
29/// ```rust
30/// use blind_pool::BlindPool;
31///
32/// let pool = BlindPool::new();
33/// let mut value_handle = pool.insert_mut("Test".to_string());
34///
35/// // Mutably access the value.
36/// value_handle.push_str(" - Modified");
37/// assert_eq!(*value_handle, "Test - Modified");
38///
39/// // Value is automatically cleaned up when handle is dropped.
40/// ```
41pub struct PooledMut<T: ?Sized> {
42    /// The inner data containing the actual pooled item and pool handle.
43    inner: PooledMutInner<T>,
44}
45
46/// Internal data structure that manages the lifetime of a mutably pooled item.
47struct PooledMutInner<T: ?Sized> {
48    /// The typed handle to the actual item in the pool.
49    pooled: RawPooled<T>,
50
51    /// A handle to the pool that keeps it alive as long as this item exists.
52    pool: BlindPool,
53}
54
55impl<T: ?Sized> PooledMut<T> {
56    /// Creates a new [`PooledMut<T>`] from a pooled item and pool handle.
57    ///
58    /// This is an internal constructor used by [`BlindPool::insert_mut`] and
59    /// [`BlindPool::insert_with_mut`].
60    #[must_use]
61    pub(crate) fn new(pooled: RawPooled<T>, pool: BlindPool) -> Self {
62        let inner = PooledMutInner { pooled, pool };
63        Self { inner }
64    }
65
66    /// Provides access to the internal raw pooled handle for type casting operations.
67    ///
68    /// This method is used internally by the casting macro system and should not be
69    /// used directly by user code.
70    #[doc(hidden)]
71    pub fn __private_cast_dyn_with_fn<U: ?Sized, F>(self, cast_fn: F) -> PooledMut<U>
72    where
73        F: FnOnce(&mut T) -> &mut U,
74    {
75        // We need to prevent the Drop from running on the original handle while still
76        // extracting its fields. This is safe because we're transferring ownership
77        // to the new handle.
78        let this = std::mem::ManuallyDrop::new(self);
79        // SAFETY: We are reading from ManuallyDrop wrapped value to transfer ownership.
80        // The field is guaranteed to be initialized and we prevent Drop from running.
81        let pooled = unsafe { std::ptr::read(&raw const this.inner.pooled) };
82        // SAFETY: We are reading from ManuallyDrop wrapped value to transfer ownership.
83        // The field is guaranteed to be initialized and we prevent Drop from running.
84        let pool = unsafe { std::ptr::read(&raw const this.inner.pool) };
85
86        // Cast the RawPooled to the trait object using the provided function
87        // SAFETY: The lifetime management logic of this pool guarantees that the target item is
88        // still alive in the pool for as long as any handle exists, which it clearly does.
89        let cast_pooled = unsafe { pooled.__private_cast_dyn_with_fn_mut(cast_fn) };
90
91        // Create the new PooledMut with the cast handle and the same pool
92        PooledMut {
93            inner: PooledMutInner {
94                pooled: cast_pooled,
95                pool,
96            },
97        }
98    }
99
100    /// Returns a pinned reference to the value stored in the pool.
101    ///
102    /// Since values in the pool are always pinned (they never move once inserted),
103    /// this method provides safe access to `Pin<&T>` without requiring unsafe code.
104    ///
105    /// # Example
106    ///
107    /// ```rust
108    /// use std::pin::Pin;
109    ///
110    /// use blind_pool::BlindPool;
111    ///
112    /// let pool = BlindPool::new();
113    /// let handle = pool.insert_mut("hello".to_string());
114    ///
115    /// let pinned: Pin<&String> = handle.as_pin();
116    /// assert_eq!(pinned.len(), 5);
117    /// ```
118    #[must_use]
119    #[inline]
120    pub fn as_pin(&self) -> Pin<&T> {
121        // Delegate to the underlying opaque_pool Pooled<T> as_pin implementation.
122        // This is safe and efficient since opaque_pool now provides safe as_pin.
123        self.inner.pooled.opaque_handle().as_pin()
124    }
125
126    /// Returns a pinned mutable reference to the value stored in the pool.
127    ///
128    /// Since values in the pool are always pinned (they never move once inserted),
129    /// this method provides safe access to `Pin<&mut T>` without requiring unsafe code.
130    ///
131    /// # Example
132    ///
133    /// ```rust
134    /// use std::pin::Pin;
135    ///
136    /// use blind_pool::BlindPool;
137    ///
138    /// let pool = BlindPool::new();
139    /// let mut handle = pool.insert_mut("hello".to_string());
140    ///
141    /// let mut pinned: Pin<&mut String> = handle.as_pin_mut();
142    /// // Can use Pin methods or deref to &mut String
143    /// ```
144    #[must_use]
145    #[inline]
146    pub fn as_pin_mut(&mut self) -> Pin<&mut T> {
147        // SAFETY: We have exclusive access through PooledMut and the pooled handle contains
148        // a valid value. We can safely create a mutable reference to convert the shared
149        // RawPooled to provide mutable access for our exclusive PooledMut.
150        let mutable_ref = unsafe { self.inner.pooled.ptr().as_mut() };
151        // SAFETY: Values in the pool are always pinned - they never move once inserted.
152        unsafe { Pin::new_unchecked(mutable_ref) }
153    }
154
155    /// Converts this exclusive [`PooledMut<T>`] handle into a shared [`Pooled<T>`] handle.
156    ///
157    /// This operation consumes the [`PooledMut<T>`] and returns a [`Pooled<T>`] that allows
158    /// multiple shared references to the same pooled value. Once converted, you can no longer
159    /// obtain exclusive (mutable) references to the value, but you can create multiple
160    /// shared references through cloning.
161    ///
162    /// The returned [`Pooled<T>`] maintains the same lifetime management semantics -
163    /// the value will be automatically removed from the pool when all references
164    /// (including the returned [`Pooled<T>`]) are dropped.
165    ///
166    /// # Example
167    ///
168    /// ```rust
169    /// use blind_pool::BlindPool;
170    ///
171    /// let pool = BlindPool::new();
172    /// let mut exclusive_handle = pool.insert_mut("Test".to_string());
173    ///
174    /// // Modify the value while we have exclusive access.
175    /// exclusive_handle.push_str(" - Modified");
176    /// assert_eq!(*exclusive_handle, "Test - Modified");
177    ///
178    /// // Convert to shared access.
179    /// let shared_handle = exclusive_handle.into_shared();
180    ///
181    /// // Now we can create multiple shared references.
182    /// let cloned_handle = shared_handle.clone();
183    /// assert_eq!(*shared_handle, "Test - Modified");
184    /// assert_eq!(*cloned_handle, "Test - Modified");
185    ///
186    /// // Value is automatically cleaned up when all handles are dropped.
187    /// ```
188    #[must_use]
189    #[inline]
190    pub fn into_shared(self) -> Pooled<T> {
191        // We need to prevent the Drop from running on the original handle while still
192        // extracting its fields. This is safe because we're transferring ownership
193        // to the new shared handle.
194        let this = std::mem::ManuallyDrop::new(self);
195        // SAFETY: We are reading from ManuallyDrop wrapped value to transfer ownership.
196        // The fields are guaranteed to be initialized and we prevent Drop from running.
197        let pooled = unsafe { std::ptr::read(&raw const this.inner.pooled) };
198        // SAFETY: We are reading from ManuallyDrop wrapped value to transfer ownership.
199        // The field is guaranteed to be initialized and we prevent Drop from running.
200        let pool = unsafe { std::ptr::read(&raw const this.inner.pool) };
201
202        // Create the new shared handle with the same pooled item and pool
203        Pooled::new(pooled, pool)
204    }
205}
206
207impl<T: Unpin> PooledMut<T> {
208    /// Moves the value out of the pool, returning it to the caller and consuming the [`PooledMut<T>`].
209    ///
210    /// This method extracts the value from the pool and transfers ownership to the caller.
211    /// The item is removed from the pool, but the value is not dropped - instead, it is
212    /// returned to the caller who becomes responsible for its lifetime management.
213    ///
214    /// This method is only available for types that implement [`Unpin`], as moving a value
215    /// out of the pool would break the pinning guarantee for `!Unpin` types.
216    ///
217    /// # Example
218    ///
219    /// ```rust
220    /// use blind_pool::BlindPool;
221    ///
222    /// let pool = BlindPool::new();
223    /// let mut pooled_string = pool.insert_mut("Hello".to_string());
224    ///
225    /// // Modify the value while it is in the pool.
226    /// pooled_string.push_str(" World");
227    /// assert_eq!(*pooled_string, "Hello World");
228    /// assert_eq!(pool.len(), 1);
229    ///
230    /// // Extract the value from the pool.
231    /// let extracted_string = pooled_string.into_inner();
232    /// assert_eq!(extracted_string, "Hello World");
233    /// assert_eq!(pool.len(), 0); // Pool is now empty.
234    ///
235    /// // The caller now owns the value and is responsible for its lifetime.
236    /// println!("Extracted: {}", extracted_string);
237    /// ```
238    #[must_use]
239    #[inline]
240    pub fn into_inner(self) -> T {
241        // We need to prevent the Drop from running on the original handle while still
242        // extracting the pooled item information to remove it from the pool.
243        let this = std::mem::ManuallyDrop::new(self);
244
245        // SAFETY: We are reading from ManuallyDrop wrapped value to access fields.
246        // The fields are guaranteed to be initialized and we prevent Drop from running.
247        let pooled = unsafe { std::ptr::read(&raw const this.inner.pooled) };
248        // SAFETY: We are reading from ManuallyDrop wrapped value to access fields.
249        // The field is guaranteed to be initialized and we prevent Drop from running.
250        let pool = unsafe { std::ptr::read(&raw const this.inner.pool) };
251
252        // Remove the item from the pool and move the value out.
253        // SAFETY: T: Unpin is guaranteed by the impl constraint, and this pooled handle
254        // is consumed by this operation, ensuring it cannot be used again.
255        unsafe { pool.remove_unpin(&pooled) }
256    }
257}
258
259impl<T: ?Sized> Deref for PooledMut<T> {
260    type Target = T;
261
262    /// Provides direct access to the value stored in the pool.
263    ///
264    /// This allows the handle to be used as if it were a reference to the stored value.
265    ///
266    /// # Example
267    ///
268    /// ```rust
269    /// use blind_pool::BlindPool;
270    ///
271    /// let pool = BlindPool::new();
272    /// let string_handle = pool.insert_mut("hello".to_string());
273    ///
274    /// // Access string methods directly.
275    /// assert_eq!(string_handle.len(), 5);
276    /// assert!(string_handle.starts_with("he"));
277    /// ```
278    #[inline]
279    fn deref(&self) -> &Self::Target {
280        // Delegate to the underlying opaque_pool Pooled<T> Deref implementation.
281        // This is safe and efficient since opaque_pool now provides safe Deref.
282        self.inner.pooled.opaque_handle()
283    }
284}
285
286impl<T: ?Sized> DerefMut for PooledMut<T> {
287    /// Provides direct mutable access to the value stored in the pool.
288    ///
289    /// This allows the handle to be used as if it were a mutable reference to the stored value.
290    ///
291    /// # Example
292    ///
293    /// ```rust
294    /// use blind_pool::BlindPool;
295    ///
296    /// let pool = BlindPool::new();
297    /// let mut string_handle = pool.insert_mut("hello".to_string());
298    ///
299    /// // Mutate the string directly.
300    /// string_handle.push_str(" world");
301    /// assert_eq!(*string_handle, "hello world");
302    /// ```
303    #[inline]
304    fn deref_mut(&mut self) -> &mut Self::Target {
305        // We cannot delegate to opaque_pool's DerefMut because our pooled handle is shared,
306        // but we provide exclusive access through PooledMut's ownership semantics.
307        // SAFETY: The pooled handle is valid and contains initialized memory of type T.
308        // We have exclusive ownership through PooledMut, so no other references can exist.
309        unsafe { self.inner.pooled.ptr().as_mut() }
310    }
311}
312
313impl<T: ?Sized> Drop for PooledMut<T> {
314    /// Automatically removes the item from the pool when the handle is dropped.
315    ///
316    /// This ensures that resources are properly cleaned up without requiring manual intervention.
317    #[inline]
318    fn drop(&mut self) {
319        // We have exclusive ownership, so we can safely remove the item from the pool.
320        // SAFETY: This pooled handle is being consumed by Drop, ensuring it cannot be used again.
321        unsafe {
322            self.inner.pool.remove(&self.inner.pooled.erase());
323        }
324    }
325}
326
327// SAFETY: PooledMut<T> can be Send if T is Send, because we can move the exclusive
328// mutable access between threads when T can be moved between threads.
329unsafe impl<T: ?Sized + Send> Send for PooledMut<T> {}
330
331// Note: PooledMut<T> does NOT implement Sync because it provides mutable access
332// via DerefMut. Allowing multiple threads to share references to the same
333// PooledMut<T> instance would violate Rust's borrowing rules and lead to data races.
334
335impl<T: ?Sized> fmt::Debug for PooledMut<T> {
336    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
337        f.debug_struct("PooledMut")
338            .field("type_name", &std::any::type_name::<T>())
339            .field("ptr", &self.inner.pooled.ptr())
340            .finish()
341    }
342}
343
344impl<T: ?Sized> fmt::Debug for PooledMutInner<T> {
345    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
346        f.debug_struct("PooledMutInner")
347            .field("type_name", &std::any::type_name::<T>())
348            .field("ptr", &self.pooled.ptr())
349            .field("pool", &self.pool)
350            .finish()
351    }
352}
353
354#[cfg(test)]
355mod tests {
356    use static_assertions::{assert_impl_all, assert_not_impl_any};
357
358    use super::PooledMut;
359    use crate::BlindPool;
360
361    #[test]
362    fn thread_safety_assertions() {
363        // PooledMut<T> should be Send if T is Send, but never Sync
364        assert_impl_all!(PooledMut<u32>: Send);
365        assert_impl_all!(PooledMut<String>: Send);
366        assert_impl_all!(PooledMut<Vec<u8>>: Send);
367
368        // PooledMut should NOT be Clone
369        assert_not_impl_any!(PooledMut<u32>: Clone);
370        assert_not_impl_any!(PooledMut<String>: Clone);
371        assert_not_impl_any!(PooledMut<Vec<u8>>: Clone);
372
373        // PooledMut should NOT be Sync (regardless of T's Sync status)
374        // We only test with types that are known to not be Sync to avoid type inference issues
375        use std::cell::RefCell;
376        use std::rc::Rc;
377        assert_not_impl_any!(PooledMut<RefCell<u32>>: Sync); // RefCell is not Sync
378        assert_not_impl_any!(PooledMut<Rc<u32>>: Sync); // Rc is not Sync
379
380        // With non-Send types, PooledMut should also not be Send
381        assert_not_impl_any!(PooledMut<Rc<u32>>: Send); // Rc is not Send
382
383        // RefCell<T> is Send if T is Send
384        assert_impl_all!(PooledMut<RefCell<u32>>: Send); // RefCell<u32> is Send
385
386        // PooledMut should implement Unpin
387        assert_impl_all!(PooledMut<u32>: Unpin);
388        assert_impl_all!(PooledMut<String>: Unpin);
389        assert_impl_all!(PooledMut<Vec<u8>>: Unpin);
390    }
391
392    #[test]
393    fn automatic_cleanup() {
394        let pool = BlindPool::new();
395
396        {
397            let _handle = pool.insert_mut(42_u32);
398            assert_eq!(pool.len(), 1);
399        }
400
401        // Item should be automatically removed after drop
402        assert_eq!(pool.len(), 0);
403        assert!(pool.is_empty());
404    }
405
406    #[test]
407    fn mutable_access() {
408        let pool = BlindPool::new();
409        let mut handle = pool.insert_mut("hello".to_string());
410
411        // Test mutable access
412        handle.push_str(" world");
413        assert_eq!(*handle, "hello world");
414
415        // Test that the modification persists
416        assert_eq!(handle.len(), 11);
417    }
418
419    #[test]
420    fn deref_and_deref_mut_work() {
421        let pool = BlindPool::new();
422        let mut handle = pool.insert_mut(vec![1, 2, 3]);
423
424        // Test Deref
425        assert_eq!(handle.len(), 3);
426        assert_eq!(*handle.first().expect("vec should not be empty"), 1);
427
428        // Test DerefMut
429        handle.push(4);
430        *handle.get_mut(0).expect("index 0 should exist") = 10;
431
432        assert_eq!(*handle, vec![10, 2, 3, 4]);
433    }
434
435    #[test]
436    fn works_with_drop_types() {
437        use std::sync::Arc;
438        use std::sync::atomic::{AtomicBool, Ordering};
439
440        struct DropTracker {
441            dropped: Arc<AtomicBool>,
442        }
443
444        impl Drop for DropTracker {
445            fn drop(&mut self) {
446                self.dropped.store(true, Ordering::Relaxed);
447            }
448        }
449
450        let pool = BlindPool::new();
451        let dropped = Arc::new(AtomicBool::new(false));
452
453        {
454            let _handle = pool.insert_mut(DropTracker {
455                dropped: Arc::clone(&dropped),
456            });
457            assert!(!dropped.load(Ordering::Relaxed));
458        }
459
460        // Item's Drop should have been called when pool handle was dropped
461        assert!(dropped.load(Ordering::Relaxed));
462    }
463
464    #[test]
465    fn double_remove_bug_reproduction() {
466        use std::task::{Context, Poll, Waker};
467
468        #[allow(
469            clippy::unused_async,
470            reason = "Need async fn to create Future for testing"
471        )]
472        async fn echo(val: u32) -> u32 {
473            val
474        }
475
476        let pool = BlindPool::new();
477        let mut future_handle = pool.insert_mut(echo(10));
478
479        // Create a context for polling
480        let waker = Waker::noop();
481        let mut context = Context::from_waker(waker);
482
483        // Poll the future
484        let pinned_future = future_handle.as_pin_mut();
485        match pinned_future.poll(&mut context) {
486            Poll::Ready(result) => {
487                assert_eq!(result, 10);
488            }
489            Poll::Pending => {
490                // Should not happen for this simple future
491                panic!("Future should complete immediately");
492            }
493        }
494
495        // The handle should be dropped normally here without panicking
496    }
497
498    #[test]
499    fn detailed_future_test() {
500        use std::task::{Context, Poll, Waker};
501
502        // A simple async function that should complete immediately
503        #[allow(
504            clippy::unused_async,
505            reason = "Need async fn to create Future for testing"
506        )]
507        async fn echo(val: u32) -> u32 {
508            val
509        }
510
511        let pool = BlindPool::new();
512
513        // Insert the future into the pool
514        let mut future_handle = pool.insert_mut(echo(42));
515        assert_eq!(pool.len(), 1);
516
517        // Create a context for polling
518        let waker = Waker::noop();
519        let mut context = Context::from_waker(waker);
520
521        // Poll the future through the pinned reference
522        let pinned_future = future_handle.as_pin_mut();
523        let result = match pinned_future.poll(&mut context) {
524            Poll::Ready(value) => value,
525            Poll::Pending => panic!("Simple future should complete immediately"),
526        };
527
528        assert_eq!(result, 42);
529        assert_eq!(pool.len(), 1); // Future should still be in pool
530
531        // Drop the handle - this should cleanly remove the future from pool
532        drop(future_handle);
533        assert_eq!(pool.len(), 0); // Should be removed now
534    }
535
536    #[test]
537    fn unpin_with_non_unpin_type() {
538        use std::marker::PhantomPinned;
539
540        // Create a type that is !Unpin
541        struct NotUnpin {
542            _pinned: PhantomPinned,
543            value: u32,
544        }
545
546        // Verify that NotUnpin is indeed !Unpin
547        assert_not_impl_any!(NotUnpin: Unpin);
548
549        // PooledMut<NotUnpin> should still be Unpin because the wrapper implements Unpin
550        // regardless of T's Unpin status - the pooled data is always pinned in place
551        assert_impl_all!(PooledMut<NotUnpin>: Unpin);
552
553        let pool = BlindPool::new();
554        let handle = pool.insert_mut(NotUnpin {
555            _pinned: PhantomPinned,
556            value: 42,
557        });
558
559        // Can access the value normally
560        assert_eq!(handle.value, 42);
561    }
562
563    #[test]
564    #[allow(
565        dead_code,
566        reason = "Macro-generated trait only used for casting in this test"
567    )]
568    fn casting_with_futures() {
569        use std::future::Future;
570        use std::task::{Context, Poll, Waker};
571
572        /// Custom trait for futures returning u32.
573        pub(crate) trait MyFuture: Future<Output = u32> {}
574
575        /// Blanket implementation for any Future<Output = u32>.
576        impl<T> MyFuture for T where T: Future<Output = u32> {}
577
578        // Generate casting methods for MyFuture.
579        crate::define_pooled_dyn_cast!(MyFuture);
580
581        #[allow(
582            clippy::unused_async,
583            reason = "Need async fn to create Future for testing"
584        )]
585        async fn echo(val: u32) -> u32 {
586            val
587        }
588
589        let pool = BlindPool::new();
590
591        // Create the future handle first, then cast it (separate operations)
592        let original_handle = pool.insert_mut(echo(10));
593        let mut future_handle = original_handle.cast_my_future();
594
595        // After casting, the pool should still have the item
596        assert_eq!(pool.len(), 1);
597
598        // Poll the future using the safe pinning method from PooledMut
599        let waker = Waker::noop();
600        let mut context = Context::from_waker(waker);
601
602        // Use the as_pin_mut method to get a properly pinned reference
603        let pinned_future = future_handle.as_pin_mut();
604        match pinned_future.poll(&mut context) {
605            Poll::Ready(result) => {
606                assert_eq!(result, 10);
607            }
608            Poll::Pending => {
609                panic!("Simple future should complete immediately");
610            }
611        }
612
613        assert_eq!(pool.len(), 1); // Should still be 1 after polling
614
615        // Drop should work fine
616        drop(future_handle);
617        assert_eq!(pool.len(), 0);
618    }
619
620    #[test]
621    fn explicit_double_drop_test() {
622        // Try to create a scenario where something might be dropped twice
623        let pool = BlindPool::new();
624        let handle = pool.insert_mut(42_u32);
625
626        // Ensure the pool has the item
627        assert_eq!(pool.len(), 1);
628        assert_eq!(*handle, 42);
629
630        // Normal drop should work
631        drop(handle);
632        assert_eq!(pool.len(), 0);
633    }
634
635    #[test]
636    fn into_shared_conversion() {
637        let pool = BlindPool::new();
638        let mut exclusive_handle = pool.insert_mut("Test".to_string());
639
640        // Modify the value while we have exclusive access
641        exclusive_handle.push_str(" - Modified");
642        assert_eq!(*exclusive_handle, "Test - Modified");
643        assert_eq!(pool.len(), 1);
644
645        // Convert to shared access
646        let shared_handle = exclusive_handle.into_shared();
647        assert_eq!(*shared_handle, "Test - Modified");
648        assert_eq!(pool.len(), 1); // Should still be 1 item
649
650        // Now we can create multiple shared references
651        let cloned_handle = shared_handle.clone();
652        assert_eq!(*shared_handle, "Test - Modified");
653        assert_eq!(*cloned_handle, "Test - Modified");
654        assert_eq!(pool.len(), 1); // Still 1 item
655
656        // Value is automatically cleaned up when all handles are dropped
657        drop(shared_handle);
658        assert_eq!(pool.len(), 1); // Still alive due to cloned_handle
659        assert_eq!(*cloned_handle, "Test - Modified"); // Still accessible
660
661        drop(cloned_handle);
662        assert_eq!(pool.len(), 0); // Now cleaned up
663    }
664
665    #[test]
666    fn into_shared_with_different_types() {
667        let pool = BlindPool::new();
668
669        // Test with a Vec
670        let mut vec_handle = pool.insert_mut(vec![1, 2, 3]);
671        vec_handle.push(4);
672        let shared_vec = vec_handle.into_shared();
673        assert_eq!(*shared_vec, vec![1, 2, 3, 4]);
674
675        // Test with a u64
676        let mut_handle = pool.insert_mut(42_u64);
677        let shared_u64 = mut_handle.into_shared();
678        assert_eq!(*shared_u64, 42);
679
680        assert_eq!(pool.len(), 2);
681        drop(shared_vec);
682        drop(shared_u64);
683        assert_eq!(pool.len(), 0);
684    }
685
686    #[test]
687    fn into_inner_basic() {
688        let pool = BlindPool::new();
689        let mut handle = pool.insert_mut("Test".to_string());
690
691        // Modify the value while it is in the pool
692        handle.push_str(" - Modified");
693        assert_eq!(*handle, "Test - Modified");
694        assert_eq!(pool.len(), 1);
695
696        // Extract the value from the pool
697        let extracted = handle.into_inner();
698        assert_eq!(extracted, "Test - Modified");
699        assert_eq!(pool.len(), 0); // Pool should be empty now
700    }
701
702    #[test]
703    fn into_inner_with_different_types() {
704        #[derive(Debug, Eq, PartialEq)]
705        struct TestStruct {
706            value: i32,
707            text: String,
708        }
709
710        let pool = BlindPool::new();
711
712        // Test with a Vec (which is Unpin)
713        let mut vec_handle = pool.insert_mut(vec![1, 2, 3]);
714        vec_handle.push(4);
715        let extracted_vec = vec_handle.into_inner();
716        assert_eq!(extracted_vec, vec![1, 2, 3, 4]);
717
718        // Test with a u64 (which is Unpin)
719        let u64_handle = pool.insert_mut(42_u64);
720        let extracted_u64 = u64_handle.into_inner();
721        assert_eq!(extracted_u64, 42);
722
723        // Test with a custom struct (which is Unpin by default)
724        let struct_handle = pool.insert_mut(TestStruct {
725            value: 100,
726            text: "hello".to_string(),
727        });
728        let extracted_struct = struct_handle.into_inner();
729        assert_eq!(
730            extracted_struct,
731            TestStruct {
732                value: 100,
733                text: "hello".to_string(),
734            }
735        );
736
737        assert_eq!(pool.len(), 0); // All items should be extracted
738    }
739
740    #[test]
741    fn into_inner_preserves_value_ownership() {
742        let pool = BlindPool::new();
743        let handle = pool.insert_mut("Hello World".to_string());
744
745        // Extract the value
746        let extracted = handle.into_inner();
747
748        // Verify the extracted value is fully owned and can be modified
749        let mut owned_string = extracted;
750        owned_string.push_str(" - Owned");
751        assert_eq!(owned_string, "Hello World - Owned");
752
753        assert_eq!(pool.len(), 0);
754    }
755
756    #[test]
757    fn into_inner_with_drop_types() {
758        use std::sync::Arc;
759        use std::sync::atomic::{AtomicBool, Ordering};
760
761        struct DropTracker {
762            dropped: Arc<AtomicBool>,
763        }
764
765        impl Drop for DropTracker {
766            fn drop(&mut self) {
767                self.dropped.store(true, Ordering::Relaxed);
768            }
769        }
770
771        let pool = BlindPool::new();
772        let dropped = Arc::new(AtomicBool::new(false));
773
774        let handle = pool.insert_mut(DropTracker {
775            dropped: Arc::clone(&dropped),
776        });
777
778        // Value should not be dropped yet
779        assert!(!dropped.load(Ordering::Relaxed));
780
781        // Extract the value - this should not drop it
782        let extracted = handle.into_inner();
783        assert!(!dropped.load(Ordering::Relaxed));
784
785        assert_eq!(pool.len(), 0); // Pool should be empty
786
787        // Value should only be dropped when we drop the extracted value
788        drop(extracted);
789        assert!(dropped.load(Ordering::Relaxed));
790    }
791
792    #[test]
793    fn into_inner_with_copy_types() {
794        let pool = BlindPool::new();
795
796        // Test with a Copy type
797        let handle = pool.insert_mut(42_i32);
798        let extracted = handle.into_inner();
799        assert_eq!(extracted, 42);
800
801        // Test with arrays (which are Copy if elements are Copy)
802        let array_handle = pool.insert_mut([1, 2, 3, 4]);
803        let extracted_array = array_handle.into_inner();
804        assert_eq!(extracted_array, [1, 2, 3, 4]);
805
806        assert_eq!(pool.len(), 0);
807    }
808
809    #[test]
810    fn into_inner_pool_count_updates() {
811        let pool = BlindPool::new();
812
813        // Insert multiple items
814        let handle1 = pool.insert_mut("First".to_string());
815        let handle2 = pool.insert_mut("Second".to_string());
816        let handle3 = pool.insert_mut("Third".to_string());
817
818        assert_eq!(pool.len(), 3);
819
820        // Extract one item
821        let extracted1 = handle1.into_inner();
822        assert_eq!(extracted1, "First");
823        assert_eq!(pool.len(), 2);
824
825        // Extract another item
826        let extracted2 = handle2.into_inner();
827        assert_eq!(extracted2, "Second");
828        assert_eq!(pool.len(), 1);
829
830        // Extract the last item
831        let extracted3 = handle3.into_inner();
832        assert_eq!(extracted3, "Third");
833        assert_eq!(pool.len(), 0);
834        assert!(pool.is_empty());
835    }
836}