1use std::alloc::Layout;
2use std::iter::FusedIterator;
3use std::mem::MaybeUninit;
4use std::ptr::NonNull;
5use std::sync::Arc;
6
7use parking_lot::Mutex;
8
9use crate::opaque::pool_raw::RawOpaquePoolIterator;
10use crate::{PooledMut, RawOpaquePool, RawOpaquePoolSend};
11
12#[doc = include_str!("../../doc/snippets/managed_pool_lifetimes.md")]
19#[doc = include_str!("../../doc/snippets/managed_pool_is_thread_safe.md")]
20#[derive(Debug)]
55pub struct OpaquePool {
56 inner: Arc<Mutex<RawOpaquePoolSend>>,
69}
70
71impl OpaquePool {
72 #[must_use]
80 pub fn with_layout(object_layout: Layout) -> Self {
81 let inner = RawOpaquePool::with_layout(object_layout);
82
83 let inner = unsafe { RawOpaquePoolSend::new(inner) };
85
86 Self {
87 inner: Arc::new(Mutex::new(inner)),
88 }
89 }
90
91 #[must_use]
99 pub fn with_layout_of<T: Sized + Send>() -> Self {
100 Self::with_layout(Layout::new::<T>())
101 }
102
103 #[doc = include_str!("../../doc/snippets/opaque_pool_layout.md")]
104 #[must_use]
105 #[inline]
106 pub fn object_layout(&self) -> Layout {
107 self.inner.lock().object_layout()
108 }
109
110 #[doc = include_str!("../../doc/snippets/pool_len.md")]
111 #[must_use]
112 #[inline]
113 pub fn len(&self) -> usize {
114 self.inner.lock().len()
115 }
116
117 #[doc = include_str!("../../doc/snippets/pool_capacity.md")]
118 #[must_use]
119 #[inline]
120 pub fn capacity(&self) -> usize {
121 self.inner.lock().capacity()
122 }
123
124 #[doc = include_str!("../../doc/snippets/pool_is_empty.md")]
125 #[must_use]
126 #[inline]
127 pub fn is_empty(&self) -> bool {
128 self.inner.lock().is_empty()
129 }
130
131 #[doc = include_str!("../../doc/snippets/pool_reserve.md")]
132 #[inline]
133 pub fn reserve(&self, additional: usize) {
134 self.inner.lock().reserve(additional);
135 }
136
137 #[doc = include_str!("../../doc/snippets/pool_shrink_to_fit.md")]
138 #[inline]
139 pub fn shrink_to_fit(&self) {
140 self.inner.lock().shrink_to_fit();
141 }
142
143 #[doc = include_str!("../../doc/snippets/pool_insert.md")]
144 #[doc = include_str!("../../doc/snippets/panic_on_pool_t_layout_mismatch.md")]
147 #[inline]
174 #[must_use]
175 pub fn insert<T: Send + 'static>(&self, value: T) -> PooledMut<T> {
176 let inner = self.inner.lock().insert(value);
177
178 PooledMut::new(inner, Arc::clone(&self.inner))
179 }
180
181 #[doc = include_str!("../../doc/snippets/pool_insert.md")]
182 #[doc = include_str!("../../doc/snippets/safety_pool_t_layout_must_match.md")]
184 #[inline]
185 #[must_use]
186 pub unsafe fn insert_unchecked<T: Send + 'static>(&self, value: T) -> PooledMut<T> {
187 let inner = unsafe { self.inner.lock().insert_unchecked(value) };
189
190 PooledMut::new(inner, Arc::clone(&self.inner))
191 }
192
193 #[doc = include_str!("../../doc/snippets/pool_insert_with.md")]
194 #[doc = include_str!("../../doc/snippets/panic_on_pool_t_layout_mismatch.md")]
228 #[doc = include_str!("../../doc/snippets/safety_closure_must_initialize_object.md")]
231 #[inline]
232 #[must_use]
233 pub unsafe fn insert_with<T, F>(&self, f: F) -> PooledMut<T>
234 where
235 T: Send + 'static,
236 F: FnOnce(&mut MaybeUninit<T>),
237 {
238 let inner = unsafe { self.inner.lock().insert_with(f) };
240
241 PooledMut::new(inner, Arc::clone(&self.inner))
242 }
243
244 #[doc = include_str!("../../doc/snippets/pool_insert_with.md")]
245 #[doc = include_str!("../../doc/snippets/safety_pool_t_layout_must_match.md")]
279 #[doc = include_str!("../../doc/snippets/safety_closure_must_initialize_object.md")]
280 #[inline]
281 #[must_use]
282 pub unsafe fn insert_with_unchecked<T, F>(&self, f: F) -> PooledMut<T>
283 where
284 T: Send + 'static,
285 F: FnOnce(&mut MaybeUninit<T>),
286 {
287 let inner = unsafe { self.inner.lock().insert_with_unchecked(f) };
289
290 PooledMut::new(inner, Arc::clone(&self.inner))
291 }
292
293 pub fn with_iter<F, R>(&self, f: F) -> R
326 where
327 F: FnOnce(OpaquePoolIterator<'_>) -> R,
328 {
329 let guard = self.inner.lock();
330 let iter = OpaquePoolIterator::new(&guard);
331 f(iter)
332 }
333}
334
335impl Clone for OpaquePool {
336 #[inline]
337 fn clone(&self) -> Self {
338 Self {
339 inner: Arc::clone(&self.inner),
340 }
341 }
342}
343
344#[derive(Debug)]
359pub struct OpaquePoolIterator<'p> {
360 raw_iter: RawOpaquePoolIterator<'p>,
361}
362
363impl<'p> OpaquePoolIterator<'p> {
364 fn new(pool: &'p RawOpaquePoolSend) -> Self {
365 Self {
366 raw_iter: pool.iter(),
367 }
368 }
369}
370
371impl Iterator for OpaquePoolIterator<'_> {
372 type Item = NonNull<()>;
373
374 fn next(&mut self) -> Option<Self::Item> {
375 self.raw_iter.next()
376 }
377
378 fn size_hint(&self) -> (usize, Option<usize>) {
379 self.raw_iter.size_hint()
380 }
381}
382
383impl DoubleEndedIterator for OpaquePoolIterator<'_> {
384 fn next_back(&mut self) -> Option<Self::Item> {
385 self.raw_iter.next_back()
386 }
387}
388
389impl ExactSizeIterator for OpaquePoolIterator<'_> {
390 fn len(&self) -> usize {
391 self.raw_iter.len()
392 }
393}
394
395impl FusedIterator for OpaquePoolIterator<'_> {}
396
397#[cfg(test)]
398mod tests {
399 use super::*;
400
401 #[test]
402 fn new_pool_with_layout_of_is_empty() {
403 let pool = OpaquePool::with_layout_of::<u64>();
404
405 assert_eq!(pool.len(), 0);
406 assert!(pool.is_empty());
407 assert_eq!(pool.capacity(), 0);
408 assert_eq!(pool.object_layout(), Layout::new::<u64>());
409 }
410
411 #[test]
412 fn new_pool_with_layout_is_empty() {
413 let layout = Layout::new::<i64>();
414 let pool = OpaquePool::with_layout(layout);
415
416 assert_eq!(pool.object_layout(), layout);
417 assert_eq!(pool.len(), 0);
418 assert!(pool.is_empty());
419 assert_eq!(pool.capacity(), 0);
420 }
421
422 #[test]
423 fn insert_and_length() {
424 let pool = OpaquePool::with_layout_of::<u32>();
425
426 let _handle1 = pool.insert(42_u32);
427 assert_eq!(pool.len(), 1);
428 assert!(!pool.is_empty());
429
430 let _handle2 = pool.insert(100_u32);
431 assert_eq!(pool.len(), 2);
432 }
433
434 #[test]
435 fn capacity_grows_when_needed() {
436 let pool = OpaquePool::with_layout_of::<u64>();
437
438 assert_eq!(pool.capacity(), 0);
439
440 let _handle = pool.insert(123_u64);
441
442 assert!(pool.capacity() > 0);
444 let initial_capacity = pool.capacity();
445
446 #[expect(
448 clippy::collection_is_never_read,
449 reason = "handles are used for ownership"
450 )]
451 let mut handles = Vec::new();
452 for i in 1..initial_capacity {
453 handles.push(pool.insert(i as u64));
454 }
455
456 let _handle = pool.insert(999_u64);
458
459 assert!(pool.capacity() >= initial_capacity);
460 }
461
462 #[test]
463 fn reserve_creates_capacity() {
464 let pool = OpaquePool::with_layout_of::<u8>();
465
466 pool.reserve(100);
467 assert!(pool.capacity() >= 100);
468
469 let initial_capacity = pool.capacity();
470 pool.reserve(50); assert_eq!(pool.capacity(), initial_capacity);
472
473 pool.reserve(200); assert!(pool.capacity() >= 200);
475 }
476
477 #[test]
478 fn insert_with_closure() {
479 let pool = OpaquePool::with_layout_of::<u64>();
480
481 let handle = unsafe {
483 pool.insert_with(|uninit: &mut MaybeUninit<u64>| {
484 uninit.write(42);
485 })
486 };
487
488 assert_eq!(pool.len(), 1);
489 assert_eq!(*handle, 42);
490 }
491
492 #[test]
493 fn shrink_to_fit_removes_unused_capacity() {
494 let pool = OpaquePool::with_layout_of::<u8>();
495
496 pool.reserve(100);
498
499 let _handle1 = pool.insert(1_u8);
501 let _handle2 = pool.insert(2_u8);
502
503 pool.shrink_to_fit();
505
506 assert_eq!(pool.len(), 2);
508 let _handle3 = pool.insert(3_u8);
509 assert_eq!(pool.len(), 3);
510 }
511
512 #[test]
513 fn shrink_to_fit_with_zero_items_shrinks_to_zero_capacity() {
514 let pool = OpaquePool::with_layout_of::<u8>();
515
516 let handle1 = pool.insert(1_u8);
518 let handle2 = pool.insert(2_u8);
519 let handle3 = pool.insert(3_u8);
520
521 assert!(pool.capacity() > 0);
523
524 drop(handle1);
526 drop(handle2);
527 drop(handle3);
528
529 assert!(pool.is_empty());
530
531 pool.shrink_to_fit();
532
533 assert_eq!(pool.capacity(), 0);
537 }
538
539 #[test]
540 fn handle_provides_access_to_object() {
541 let pool = OpaquePool::with_layout_of::<u64>();
542
543 let handle = pool.insert(12345_u64);
544
545 assert_eq!(*handle, 12345);
546 }
547
548 #[test]
549 fn multiple_handles_to_same_type() {
550 let pool = OpaquePool::with_layout_of::<String>();
551
552 let handle1 = pool.insert("hello".to_string());
553 let handle2 = pool.insert("world".to_string());
554
555 assert_eq!(pool.len(), 2);
556
557 assert_eq!(&*handle1, "hello");
558 assert_eq!(&*handle2, "world");
559
560 drop(handle1);
562 assert_eq!(pool.len(), 1);
563
564 drop(handle2);
565 assert_eq!(pool.len(), 0);
566 assert!(pool.is_empty());
567 }
568
569 #[test]
570 fn handle_drop_removes_objects_both_exclusive_and_shared() {
571 let pool = OpaquePool::with_layout_of::<String>();
572
573 let exclusive_handle = pool.insert("exclusive".to_string());
575 assert_eq!(pool.len(), 1);
576 drop(exclusive_handle);
577 assert_eq!(pool.len(), 0);
578
579 let mut_handle = pool.insert("shared".to_string());
581 let shared_handle = mut_handle.into_shared();
582 assert_eq!(pool.len(), 1);
583
584 assert_eq!(&*shared_handle, "shared");
586
587 drop(shared_handle);
589 assert_eq!(pool.len(), 0);
590 assert!(pool.is_empty());
591 }
592
593 #[test]
594 fn iter_empty_pool() {
595 let pool = OpaquePool::with_layout_of::<u32>();
596
597 pool.with_iter(|mut iter| {
598 assert_eq!(iter.size_hint(), (0, Some(0)));
599 assert_eq!(iter.len(), 0);
600
601 assert_eq!(iter.next(), None);
602 assert_eq!(iter.size_hint(), (0, Some(0)));
603 assert_eq!(iter.len(), 0);
604 });
605 }
606
607 #[test]
608 fn iter_single_item() {
609 let pool = OpaquePool::with_layout_of::<u32>();
610
611 let _handle = pool.insert(42_u32);
612
613 pool.with_iter(|mut iter| {
614 assert_eq!(iter.len(), 1);
615
616 let ptr = iter.next().expect("should have one item");
618
619 let value = unsafe { ptr.cast::<u32>().as_ref() };
621 assert_eq!(*value, 42);
622
623 assert_eq!(iter.next(), None);
625 assert_eq!(iter.len(), 0);
626 });
627 }
628
629 #[test]
630 fn iter_multiple_items() {
631 let pool = OpaquePool::with_layout_of::<u32>();
632
633 let _handle1 = pool.insert(100_u32);
634 let _handle2 = pool.insert(200_u32);
635 let _handle3 = pool.insert(300_u32);
636
637 pool.with_iter(|iter| {
638 let values: Vec<u32> = iter
639 .map(|ptr| {
640 unsafe { *ptr.cast::<u32>().as_ref() }
642 })
643 .collect();
644
645 assert_eq!(values, vec![100, 200, 300]);
646 });
647 }
648
649 #[test]
650 fn iter_double_ended_basic() {
651 let pool = OpaquePool::with_layout_of::<u32>();
652
653 let _handle1 = pool.insert(100_u32);
654 let _handle2 = pool.insert(200_u32);
655 let _handle3 = pool.insert(300_u32);
656
657 pool.with_iter(|mut iter| {
658 let last_ptr = iter.next_back().expect("should have last item");
660 let last_value = unsafe { *last_ptr.cast::<u32>().as_ref() };
662 assert_eq!(last_value, 300);
663
664 let middle_ptr = iter.next_back().expect("should have middle item");
665 let middle_value = unsafe { *middle_ptr.cast::<u32>().as_ref() };
667 assert_eq!(middle_value, 200);
668
669 let first_ptr = iter.next().expect("should have first item");
670 let first_value = unsafe { *first_ptr.cast::<u32>().as_ref() };
672 assert_eq!(first_value, 100);
673
674 assert_eq!(iter.next(), None);
676 assert_eq!(iter.next_back(), None);
677 });
678 }
679
680 #[test]
681 fn with_iter_scoped_access() {
682 let pool = OpaquePool::with_layout_of::<u32>();
683
684 let _handle1 = pool.insert(100_u32);
685 let _handle2 = pool.insert(200_u32);
686 let _handle3 = pool.insert(300_u32);
687
688 let result = pool.with_iter(|iter| {
690 let mut values = Vec::new();
691 for ptr in iter {
692 let value = unsafe { *ptr.cast::<u32>().as_ref() };
694 values.push(value);
695 }
696 values
697 });
698
699 assert_eq!(result, vec![100, 200, 300]);
700 }
701
702 #[test]
703 fn with_iter_holds_lock() {
704 let pool = OpaquePool::with_layout_of::<u32>();
705
706 let _handle1 = pool.insert(100_u32);
707 let _handle2 = pool.insert(200_u32);
708
709 pool.with_iter(|iter| {
711 assert_eq!(iter.len(), 2);
712
713 let values: Vec<u32> = iter
714 .map(|ptr| {
715 unsafe { *ptr.cast::<u32>().as_ref() }
717 })
718 .collect();
719
720 assert_eq!(values, vec![100, 200]);
721 });
722
723 let _handle3 = pool.insert(300_u32);
725
726 pool.with_iter(|iter| {
728 assert_eq!(iter.len(), 3);
729 });
730 }
731
732 #[test]
733 fn iter_size_hint_and_exact_size() {
734 let pool = OpaquePool::with_layout_of::<u32>();
735
736 pool.with_iter(|iter| {
738 assert_eq!(iter.size_hint(), (0, Some(0)));
739 assert_eq!(iter.len(), 0);
740 });
741
742 let _handle1 = pool.insert(100_u32);
744 let _handle2 = pool.insert(200_u32);
745
746 pool.with_iter(|mut iter| {
747 assert_eq!(iter.size_hint(), (2, Some(2)));
748 assert_eq!(iter.len(), 2);
749
750 let first_item = iter.next();
752 assert!(first_item.is_some());
753 assert_eq!(iter.size_hint(), (1, Some(1)));
754 assert_eq!(iter.len(), 1);
755
756 let second_item = iter.next();
758 assert!(second_item.is_some());
759 assert_eq!(iter.size_hint(), (0, Some(0)));
760 assert_eq!(iter.len(), 0);
761
762 assert_eq!(iter.next(), None);
764 assert_eq!(iter.size_hint(), (0, Some(0)));
765 assert_eq!(iter.len(), 0);
766 });
767 }
768
769 #[test]
770 fn clone_behavior() {
771 let pool1 = OpaquePool::with_layout_of::<u32>();
772
773 let pool2 = pool1.clone();
775
776 assert_eq!(pool1.object_layout(), pool2.object_layout());
778
779 let _handle1 = pool1.insert(100_u32);
781
782 assert_eq!(pool2.len(), 1);
784 assert!(!pool2.is_empty());
785
786 let _handle2 = pool2.insert(200_u32);
788
789 assert_eq!(pool1.len(), 2);
791
792 pool1.with_iter(|iter| {
794 let values: Vec<u32> = iter
795 .map(|ptr| unsafe { *ptr.cast::<u32>().as_ref() })
797 .collect();
798 assert_eq!(values, vec![100, 200]);
799 });
800
801 pool2.with_iter(|iter| {
802 let values: Vec<u32> = iter
803 .map(|ptr| unsafe { *ptr.cast::<u32>().as_ref() })
805 .collect();
806 assert_eq!(values, vec![100, 200]);
807 });
808 }
809
810 #[test]
811 fn lifecycle_management_pool_keeps_inner_alive() {
812 let pool = OpaquePool::with_layout_of::<String>();
813
814 let handle = pool.insert("test data".to_string());
816
817 let pool_clone = pool.clone();
819
820 drop(pool);
822
823 assert_eq!(&*handle, "test data");
825
826 assert_eq!(pool_clone.len(), 1);
828 assert!(!pool_clone.is_empty());
829
830 drop(handle);
832
833 assert_eq!(pool_clone.len(), 0);
835 assert!(pool_clone.is_empty());
836 }
837
838 #[test]
839 fn lifecycle_management_handles_keep_pool_alive() {
840 let handle = {
841 let pool = OpaquePool::with_layout_of::<String>();
842 pool.insert("persistent data".to_string())
844 };
845
846 assert_eq!(&*handle, "persistent data");
848
849 drop(handle);
852 }
854
855 #[test]
856 #[cfg(not(miri))] fn concurrent_access_basic() {
858 use std::sync::{Arc, Barrier};
859 use std::thread;
860
861 let pool = Arc::new(Mutex::new(OpaquePool::with_layout_of::<u32>()));
862 let barrier = Arc::new(Barrier::new(3));
863
864 let mut handles = vec![];
865
866 for i in 0..3 {
868 let pool_clone = Arc::clone(&pool);
869 let barrier_clone = Arc::clone(&barrier);
870
871 let handle = thread::spawn(move || {
872 barrier_clone.wait();
873
874 let value = (i + 1) * 100;
875 let handle = {
876 let pool_guard = pool_clone.lock();
877 pool_guard.insert(value)
878 };
879
880 (handle, value)
882 });
883
884 handles.push(handle);
885 }
886
887 let mut pooled_handles = vec![];
889 for handle in handles {
890 let (pooled_handle, value) = handle.join().unwrap();
891 assert_eq!(*pooled_handle, value);
892 pooled_handles.push(pooled_handle);
893 }
894
895 {
897 let pool_guard = pool.lock();
898 assert_eq!(pool_guard.len(), 3);
899
900 let mut values: Vec<u32> = pool_guard.with_iter(|iter| {
901 iter
902 .map(|ptr| unsafe { *ptr.cast::<u32>().as_ref() })
904 .collect()
905 });
906
907 values.sort_unstable();
908 assert_eq!(values, vec![100, 200, 300]);
909 }
910
911 drop(pooled_handles);
913 }
914
915 #[test]
916 fn pooled_mut_integration() {
917 let pool = OpaquePool::with_layout_of::<String>();
918
919 let mut handle = pool.insert("initial".to_string());
921
922 assert_eq!(&*handle, "initial");
924
925 handle.push_str(" value");
927 assert_eq!(&*handle, "initial value");
928
929 assert_eq!(pool.len(), 1);
931
932 pool.with_iter(|iter| {
934 let values: Vec<String> = iter
935 .map(|ptr| unsafe { ptr.cast::<String>().as_ref().clone() })
937 .collect();
938 assert_eq!(values, vec!["initial value"]);
939 });
940
941 drop(handle);
943 assert_eq!(pool.len(), 0);
944 assert!(pool.is_empty());
945 }
946
947 #[test]
948 fn multiple_handles_to_different_objects() {
949 let pool = OpaquePool::with_layout_of::<u32>();
950
951 let handle1 = pool.insert(100_u32);
953 let handle2 = pool.insert(200_u32);
954 let handle3 = pool.insert(300_u32);
955
956 assert_eq!(pool.len(), 3);
957
958 assert_eq!(*handle1, 100);
960 assert_eq!(*handle2, 200);
961 assert_eq!(*handle3, 300);
962
963 drop(handle2);
965 assert_eq!(pool.len(), 2);
966
967 assert_eq!(*handle1, 100);
969 assert_eq!(*handle3, 300);
970
971 pool.with_iter(|iter| {
973 let mut values: Vec<u32> = iter
974 .map(|ptr| unsafe { *ptr.cast::<u32>().as_ref() })
976 .collect();
977 values.sort_unstable();
978 assert_eq!(values, vec![100, 300]);
979 });
980
981 drop(handle1);
982 drop(handle3);
983 assert_eq!(pool.len(), 0);
984 }
985
986 #[test]
987 fn insert_methods_with_lifecycle() {
988 let pool = OpaquePool::with_layout_of::<String>();
989
990 let handle1 = pool.insert("regular".to_string());
992 assert_eq!(pool.len(), 1);
993
994 let handle2 = unsafe { pool.insert_unchecked("unchecked".to_string()) };
997 assert_eq!(pool.len(), 2);
998
999 let handle3 = unsafe {
1002 pool.insert_with(|uninit| {
1003 uninit.write("with_closure".to_string());
1004 })
1005 };
1006 assert_eq!(pool.len(), 3);
1007
1008 let handle4 = unsafe {
1011 pool.insert_with_unchecked(|uninit| {
1012 uninit.write("with_closure_unchecked".to_string());
1013 })
1014 };
1015 assert_eq!(pool.len(), 4);
1016
1017 assert_eq!(&*handle1, "regular");
1019 assert_eq!(&*handle2, "unchecked");
1020 assert_eq!(&*handle3, "with_closure");
1021 assert_eq!(&*handle4, "with_closure_unchecked");
1022
1023 drop(handle1);
1025 assert_eq!(pool.len(), 3);
1026
1027 drop(handle2);
1028 drop(handle3);
1029 drop(handle4);
1030 assert_eq!(pool.len(), 0);
1031 }
1032
1033 #[test]
1034 fn pool_operations_with_arc_semantics() {
1035 let pool1 = OpaquePool::with_layout_of::<u32>();
1036
1037 let _handle1 = pool1.insert(100_u32);
1039 let _handle2 = pool1.insert(200_u32);
1040
1041 let pool2 = pool1.clone();
1043
1044 assert_eq!(pool1.capacity(), pool2.capacity());
1046
1047 let initial_capacity = pool1.capacity();
1048 pool1.reserve(10);
1049
1050 assert!(pool1.capacity() >= initial_capacity);
1052 assert_eq!(pool1.capacity(), pool2.capacity());
1053
1054 pool2.shrink_to_fit();
1056 assert_eq!(pool1.capacity(), pool2.capacity());
1057
1058 assert_eq!(pool1.len(), pool2.len());
1060 assert_eq!(pool1.is_empty(), pool2.is_empty());
1061 assert_eq!(pool1.object_layout(), pool2.object_layout());
1062 }
1063
1064 #[test]
1065 fn into_inner_removes_and_returns_value() {
1066 let pool = OpaquePool::with_layout_of::<String>();
1067
1068 let mut handle = pool.insert("initial value".to_string());
1070 assert_eq!(pool.len(), 1);
1071 assert_eq!(&*handle, "initial value");
1072
1073 handle.push_str(" - modified");
1075 assert_eq!(&*handle, "initial value - modified");
1076 assert_eq!(pool.len(), 1);
1077
1078 let extracted_value = handle.into_inner();
1080
1081 assert_eq!(extracted_value, "initial value - modified");
1083
1084 assert_eq!(pool.len(), 0);
1086 assert!(pool.is_empty());
1087
1088 let final_value = extracted_value + " - after extraction";
1090 assert_eq!(final_value, "initial value - modified - after extraction");
1091 }
1092
1093 #[test]
1094 fn pool_operations_work_with_shared_references() {
1095 let pool = OpaquePool::with_layout_of::<String>();
1097
1098 let handle1 = pool.insert("hello".to_string());
1100 assert_eq!(pool.len(), 1);
1101 assert_eq!(&*handle1, "hello");
1102
1103 let handle2 = unsafe {
1106 pool.insert_with(|uninit| {
1107 uninit.write("world".to_string());
1108 })
1109 };
1110 assert_eq!(pool.len(), 2);
1111 assert_eq!(&*handle2, "world");
1112
1113 let handle3 = unsafe { pool.insert_unchecked("test".to_string()) };
1116 assert_eq!(pool.len(), 3);
1117 assert_eq!(&*handle3, "test");
1118
1119 let handle4 = unsafe {
1122 pool.insert_with_unchecked(|uninit| {
1123 uninit.write("unchecked".to_string());
1124 })
1125 };
1126 assert_eq!(pool.len(), 4);
1127 assert_eq!(&*handle4, "unchecked");
1128
1129 pool.reserve(10);
1131 pool.shrink_to_fit();
1132
1133 drop(handle1);
1135 drop(handle2);
1136 drop(handle3);
1137 drop(handle4);
1138 assert_eq!(pool.len(), 0);
1139 }
1140}