1use std::alloc::{alloc, dealloc, handle_alloc_error, Layout};
52use std::borrow::Borrow;
53use std::cmp::Ordering;
54use std::fmt;
55use std::hash::{Hash, Hasher};
56use std::marker::PhantomData;
57use std::mem::{self, ManuallyDrop};
58use std::ops::Deref;
59use std::ptr::{self, NonNull};
60use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
61
62use super::CompactVec;
63
64#[repr(C)]
72struct Header {
73 count: AtomicUsize,
74 len: usize,
76 }
78
79#[inline]
82const fn data_offset_for<T>() -> usize {
83 let header_size = mem::size_of::<Header>();
84 let align = mem::align_of::<T>();
85 (header_size + align - 1) & !(align - 1)
86}
87
88pub unsafe trait CompactArcDrop {
106 unsafe fn drop_and_dealloc(ptr: *mut u8);
113}
114
115unsafe impl<T> CompactArcDrop for T {
118 #[inline]
119 unsafe fn drop_and_dealloc(ptr: *mut u8) {
120 let data_offset = data_offset_for::<T>();
121 let align = mem::align_of::<T>().max(mem::align_of::<Header>());
122
123 let data_ptr = ptr.add(data_offset) as *mut T;
125 ptr::drop_in_place(data_ptr);
126
127 let layout = Layout::from_size_align_unchecked(data_offset + mem::size_of::<T>(), align);
129 dealloc(ptr, layout);
130 }
131}
132
133unsafe impl CompactArcDrop for str {
136 #[inline]
137 unsafe fn drop_and_dealloc(ptr: *mut u8) {
138 let header = ptr as *mut Header;
139 let len = (*header).len;
140 let data_offset = data_offset_for::<u8>(); let total_size = data_offset + len;
142 let layout = Layout::from_size_align_unchecked(total_size, mem::align_of::<Header>());
143 dealloc(ptr, layout);
144 }
145}
146
147#[allow(clippy::manual_slice_size_calculation)]
148unsafe impl<T> CompactArcDrop for [T] {
151 #[inline]
152 unsafe fn drop_and_dealloc(ptr: *mut u8) {
153 let header = ptr as *mut Header;
154 let len = (*header).len;
155 let data_offset = data_offset_for::<T>();
156 let align = mem::align_of::<T>().max(mem::align_of::<Header>());
157
158 let data_ptr = ptr.add(data_offset) as *mut T;
160 ptr::drop_in_place(std::ptr::slice_from_raw_parts_mut(data_ptr, len));
161
162 let layout =
164 Layout::from_size_align_unchecked(data_offset + mem::size_of::<T>() * len, align);
165 dealloc(ptr, layout);
166 }
167}
168
169pub struct CompactArc<T: ?Sized + CompactArcDrop> {
188 ptr: NonNull<Header>,
190 _marker: PhantomData<T>,
191}
192
193unsafe impl<T: ?Sized + CompactArcDrop + Send + Sync> Send for CompactArc<T> {}
197unsafe impl<T: ?Sized + CompactArcDrop + Send + Sync> Sync for CompactArc<T> {}
199
200impl<T: ?Sized + CompactArcDrop> Drop for CompactArc<T> {
205 #[inline]
206 fn drop(&mut self) {
207 let header = self.ptr.as_ptr();
208 let old_count = unsafe { (*header).count.fetch_sub(1, AtomicOrdering::Release) };
212
213 if old_count == 1 {
214 std::sync::atomic::fence(AtomicOrdering::Acquire);
215 unsafe {
219 T::drop_and_dealloc(header as *mut u8);
220 }
221 }
222 }
223}
224
225impl<T: ?Sized + CompactArcDrop> Clone for CompactArc<T> {
230 #[inline]
231 fn clone(&self) -> Self {
232 let header = self.ptr.as_ptr();
233 let old_count = unsafe { (*header).count.fetch_add(1, AtomicOrdering::Relaxed) };
237
238 if old_count > isize::MAX as usize {
239 std::process::abort();
240 }
241
242 CompactArc {
243 ptr: self.ptr,
244 _marker: PhantomData,
245 }
246 }
247}
248
249impl<T: ?Sized + CompactArcDrop> CompactArc<T> {
254 #[inline]
256 pub fn ptr_eq(this: &Self, other: &Self) -> bool {
257 ptr::addr_eq(this.ptr.as_ptr(), other.ptr.as_ptr())
258 }
259
260 #[inline]
265 pub fn strong_count(this: &Self) -> usize {
266 unsafe { (*this.ptr.as_ptr()).count.load(AtomicOrdering::Relaxed) }
269 }
270
271 #[inline]
277 fn is_unique(this: &Self) -> bool {
278 unsafe { (*this.ptr.as_ptr()).count.load(AtomicOrdering::Acquire) == 1 }
281 }
282
283 #[inline]
285 pub fn meta(this: &Self) -> usize {
286 unsafe { (*this.ptr.as_ptr()).len }
290 }
291}
292
293impl<T: CompactArcDrop> CompactArc<T> {
298 #[inline]
300 #[must_use]
301 pub fn new(data: T) -> Self {
302 Self::new_with_meta(data, 0)
303 }
304
305 #[inline]
308 #[must_use]
309 pub fn new_with_meta(data: T, meta: usize) -> Self {
310 let data_offset = data_offset_for::<T>();
311 let align = mem::align_of::<T>().max(mem::align_of::<Header>());
312 let total_size = data_offset + mem::size_of::<T>();
313 let layout = Layout::from_size_align(total_size, align).expect("layout overflow");
314
315 unsafe {
320 let ptr = alloc(layout);
321 if ptr.is_null() {
322 handle_alloc_error(layout);
323 }
324
325 let header = ptr as *mut Header;
327 ptr::write(
328 header,
329 Header {
330 count: AtomicUsize::new(1),
331 len: meta,
332 },
333 );
334
335 let data_ptr = ptr.add(data_offset) as *mut T;
337 ptr::write(data_ptr, data);
338
339 CompactArc {
340 ptr: NonNull::new_unchecked(header),
341 _marker: PhantomData,
342 }
343 }
344 }
345
346 #[inline]
349 pub fn try_unwrap(this: Self) -> Result<T, Self> {
350 let header = this.ptr.as_ptr();
351
352 if unsafe {
356 (*header)
357 .count
358 .compare_exchange(1, 0, AtomicOrdering::Acquire, AtomicOrdering::Relaxed)
359 .is_ok()
360 } {
361 let _ = ManuallyDrop::new(this);
362
363 unsafe {
367 let data_offset = data_offset_for::<T>();
369 let data_ptr = (header as *const u8).add(data_offset) as *const T;
370 let data = ptr::read(data_ptr);
371
372 let align = mem::align_of::<T>().max(mem::align_of::<Header>());
374 let layout =
375 Layout::from_size_align_unchecked(data_offset + mem::size_of::<T>(), align);
376 dealloc(header as *mut u8, layout);
377
378 Ok(data)
379 }
380 } else {
381 Err(this)
382 }
383 }
384
385 #[inline]
390 pub fn get_mut(this: &mut Self) -> Option<&mut T> {
391 if Self::is_unique(this) {
392 unsafe {
396 let data_ptr = (this.ptr.as_ptr() as *mut u8).add(data_offset_for::<T>()) as *mut T;
397 Some(&mut *data_ptr)
398 }
399 } else {
400 None
401 }
402 }
403
404 #[inline]
408 pub fn make_mut(this: &mut Self) -> &mut T
409 where
410 T: Clone,
411 {
412 if !Self::is_unique(this) {
414 let meta = Self::meta(this);
415 *this = CompactArc::new_with_meta((**this).clone(), meta);
417 }
418 Self::get_mut(this).unwrap()
420 }
421
422 #[inline]
424 pub fn as_ptr(this: &Self) -> *const T {
425 let header = this.ptr.as_ptr();
430 unsafe { (header as *const u8).add(data_offset_for::<T>()) as *const T }
431 }
432
433 #[inline]
435 pub fn into_raw(this: Self) -> *const T {
436 let header = this.ptr.as_ptr();
440 let ptr = unsafe { (header as *const u8).add(data_offset_for::<T>()) as *const T };
441 mem::forget(this);
442 ptr
443 }
444
445 #[inline]
451 pub unsafe fn from_raw(ptr: *const T) -> Self {
452 let header = (ptr as *const u8).sub(data_offset_for::<T>()) as *mut Header;
453 CompactArc {
454 ptr: NonNull::new_unchecked(header),
455 _marker: PhantomData,
456 }
457 }
458}
459
460impl<T: CompactArcDrop> Deref for CompactArc<T> {
461 type Target = T;
462
463 #[inline]
464 fn deref(&self) -> &T {
465 unsafe {
469 let data_ptr = (self.ptr.as_ptr() as *const u8).add(data_offset_for::<T>()) as *const T;
470 &*data_ptr
471 }
472 }
473}
474
475impl<T: CompactArcDrop + Default> Default for CompactArc<T> {
476 #[inline]
477 fn default() -> Self {
478 CompactArc::new(T::default())
479 }
480}
481
482impl<T: CompactArcDrop + fmt::Debug> fmt::Debug for CompactArc<T> {
483 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
484 fmt::Debug::fmt(&**self, f)
485 }
486}
487
488impl<T: CompactArcDrop + fmt::Display> fmt::Display for CompactArc<T> {
489 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
490 fmt::Display::fmt(&**self, f)
491 }
492}
493
494impl<T: CompactArcDrop + PartialEq> PartialEq for CompactArc<T> {
495 #[inline]
496 fn eq(&self, other: &Self) -> bool {
497 if CompactArc::ptr_eq(self, other) {
498 return true;
499 }
500 **self == **other
501 }
502}
503
504impl<T: CompactArcDrop + Eq> Eq for CompactArc<T> {}
505
506impl<T: CompactArcDrop + PartialOrd> PartialOrd for CompactArc<T> {
507 #[inline]
508 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
509 (**self).partial_cmp(&**other)
510 }
511}
512
513impl<T: CompactArcDrop + Ord> Ord for CompactArc<T> {
514 #[inline]
515 fn cmp(&self, other: &Self) -> Ordering {
516 (**self).cmp(&**other)
517 }
518}
519
520impl<T: CompactArcDrop + Hash> Hash for CompactArc<T> {
521 fn hash<H: Hasher>(&self, state: &mut H) {
522 (**self).hash(state)
523 }
524}
525
526impl<T: CompactArcDrop> Borrow<T> for CompactArc<T> {
527 fn borrow(&self) -> &T {
528 self
529 }
530}
531
532impl<T: CompactArcDrop> AsRef<T> for CompactArc<T> {
533 fn as_ref(&self) -> &T {
534 self
535 }
536}
537
538impl<T: CompactArcDrop> From<T> for CompactArc<T> {
539 #[inline]
540 fn from(value: T) -> Self {
541 CompactArc::new(value)
542 }
543}
544
545impl CompactArc<str> {
550 #[must_use]
554 pub fn from_str_slice(s: &str) -> Self {
555 let len = s.len();
556 let data_offset = data_offset_for::<u8>(); let total_size = data_offset + len;
558 let layout = Layout::from_size_align(total_size, mem::align_of::<Header>())
559 .expect("layout overflow");
560
561 unsafe {
565 let ptr = alloc(layout);
566 if ptr.is_null() {
567 handle_alloc_error(layout);
568 }
569
570 let header = ptr as *mut Header;
572 ptr::write(
573 header,
574 Header {
575 count: AtomicUsize::new(1),
576 len,
577 },
578 );
579
580 let data_ptr = ptr.add(data_offset);
582 ptr::copy_nonoverlapping(s.as_ptr(), data_ptr, len);
583
584 CompactArc {
585 ptr: NonNull::new_unchecked(header),
586 _marker: PhantomData,
587 }
588 }
589 }
590
591 #[inline]
593 pub fn len(&self) -> usize {
594 unsafe { (*self.ptr.as_ptr()).len }
597 }
598
599 #[inline]
601 pub fn is_empty(&self) -> bool {
602 self.len() == 0
603 }
604}
605
606impl Deref for CompactArc<str> {
607 type Target = str;
608
609 #[inline]
610 fn deref(&self) -> &str {
611 unsafe {
615 let header = self.ptr.as_ptr();
616 let len = (*header).len;
617 let data_offset = data_offset_for::<u8>(); let data_ptr = (header as *const u8).add(data_offset);
619 std::str::from_utf8_unchecked(std::slice::from_raw_parts(data_ptr, len))
620 }
621 }
622}
623
624impl From<&str> for CompactArc<str> {
625 #[inline]
626 fn from(s: &str) -> Self {
627 CompactArc::from_str_slice(s)
628 }
629}
630
631impl From<String> for CompactArc<str> {
632 #[inline]
633 fn from(s: String) -> Self {
634 CompactArc::from_str_slice(&s)
635 }
636}
637
638impl fmt::Debug for CompactArc<str> {
639 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
640 fmt::Debug::fmt(&**self, f)
641 }
642}
643
644impl fmt::Display for CompactArc<str> {
645 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
646 fmt::Display::fmt(&**self, f)
647 }
648}
649
650impl PartialEq for CompactArc<str> {
651 #[inline]
652 fn eq(&self, other: &Self) -> bool {
653 if CompactArc::ptr_eq(self, other) {
654 return true;
655 }
656 **self == **other
657 }
658}
659
660impl Eq for CompactArc<str> {}
661
662impl PartialOrd for CompactArc<str> {
663 #[inline]
664 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
665 Some(self.cmp(other))
666 }
667}
668
669impl Ord for CompactArc<str> {
670 #[inline]
671 fn cmp(&self, other: &Self) -> Ordering {
672 (**self).cmp(&**other)
673 }
674}
675
676impl Hash for CompactArc<str> {
677 fn hash<H: Hasher>(&self, state: &mut H) {
678 (**self).hash(state)
679 }
680}
681
682impl Borrow<str> for CompactArc<str> {
683 fn borrow(&self) -> &str {
684 self
685 }
686}
687
688impl AsRef<str> for CompactArc<str> {
689 fn as_ref(&self) -> &str {
690 self
691 }
692}
693
694impl<T> CompactArc<[T]> {
699 #[must_use]
703 pub fn from_vec(mut vec: Vec<T>) -> Self {
704 let len = vec.len();
705 let data_offset = data_offset_for::<T>();
706 let align = mem::align_of::<T>().max(mem::align_of::<Header>());
707 let data_size = mem::size_of::<T>() * len;
708 let layout =
709 Layout::from_size_align(data_offset + data_size, align).expect("layout overflow");
710
711 unsafe {
716 let ptr = alloc(layout);
717 if ptr.is_null() {
718 handle_alloc_error(layout);
719 }
720
721 let header = ptr as *mut Header;
723 ptr::write(
724 header,
725 Header {
726 count: AtomicUsize::new(1),
727 len,
728 },
729 );
730
731 let data_ptr = ptr.add(data_offset) as *mut T;
733 ptr::copy_nonoverlapping(vec.as_ptr(), data_ptr, len);
734
735 vec.set_len(0);
737
738 CompactArc {
739 ptr: NonNull::new_unchecked(header),
740 _marker: PhantomData,
741 }
742 }
743 }
744
745 #[must_use]
750 pub fn from_compact_vec(mut vec: CompactVec<T>) -> Self {
751 let len = vec.len();
752 let data_offset = data_offset_for::<T>();
753 let align = mem::align_of::<T>().max(mem::align_of::<Header>());
754 let data_size = mem::size_of::<T>() * len;
755 let layout =
756 Layout::from_size_align(data_offset + data_size, align).expect("layout overflow");
757
758 unsafe {
763 let ptr = alloc(layout);
764 if ptr.is_null() {
765 handle_alloc_error(layout);
766 }
767
768 let header = ptr as *mut Header;
770 ptr::write(
771 header,
772 Header {
773 count: AtomicUsize::new(1),
774 len,
775 },
776 );
777
778 let data_ptr = ptr.add(data_offset) as *mut T;
780 ptr::copy_nonoverlapping(vec.as_ptr(), data_ptr, len);
781
782 vec.set_len(0);
784
785 CompactArc {
786 ptr: NonNull::new_unchecked(header),
787 _marker: PhantomData,
788 }
789 }
790 }
791}
792
793impl<T: Clone> CompactArc<[T]> {
794 #[must_use]
803 pub fn from_slice(slice: &[T]) -> Self {
804 let len = slice.len();
805 let data_offset = data_offset_for::<T>();
806 let align = mem::align_of::<T>().max(mem::align_of::<Header>());
807 let layout = Layout::from_size_align(data_offset + mem::size_of_val(slice), align)
808 .expect("layout overflow");
809
810 unsafe {
815 let ptr = alloc(layout);
816 if ptr.is_null() {
817 handle_alloc_error(layout);
818 }
819
820 let header = ptr as *mut Header;
822 ptr::write(
823 header,
824 Header {
825 count: AtomicUsize::new(1),
826 len,
827 },
828 );
829
830 let data_ptr = ptr.add(data_offset) as *mut T;
831
832 struct CloneGuard<T> {
834 data_ptr: *mut T,
835 alloc_ptr: *mut u8,
836 layout: Layout,
837 written: usize,
838 }
839
840 impl<T> Drop for CloneGuard<T> {
841 fn drop(&mut self) {
842 unsafe {
846 let slice = ptr::slice_from_raw_parts_mut(self.data_ptr, self.written);
848 ptr::drop_in_place(slice);
849 dealloc(self.alloc_ptr, self.layout);
851 }
852 }
853 }
854
855 let mut guard = CloneGuard {
856 data_ptr,
857 alloc_ptr: ptr,
858 layout,
859 written: 0,
860 };
861
862 for (i, item) in slice.iter().enumerate() {
864 ptr::write(data_ptr.add(i), item.clone());
865 guard.written += 1;
866 }
867
868 mem::forget(guard);
870
871 CompactArc {
872 ptr: NonNull::new_unchecked(header),
873 _marker: PhantomData,
874 }
875 }
876 }
877}
878
879impl<T> CompactArc<[T]> {
880 #[inline]
882 pub fn len(&self) -> usize {
883 unsafe { (*self.ptr.as_ptr()).len }
886 }
887
888 #[inline]
890 pub fn is_empty(&self) -> bool {
891 self.len() == 0
892 }
893
894 #[inline]
900 #[doc(hidden)]
901 pub fn data_ptr_mut(&self) -> *mut T {
902 unsafe { (self.ptr.as_ptr() as *mut u8).add(data_offset_for::<T>()) as *mut T }
903 }
904}
905
906impl<T> Deref for CompactArc<[T]> {
907 type Target = [T];
908
909 #[inline]
910 fn deref(&self) -> &[T] {
911 unsafe {
916 let header = self.ptr.as_ptr();
917 let len = (*header).len;
918 let data_ptr = (header as *const u8).add(data_offset_for::<T>()) as *const T;
919 std::slice::from_raw_parts(data_ptr, len)
920 }
921 }
922}
923
924impl<T: Clone> From<&[T]> for CompactArc<[T]> {
925 #[inline]
926 fn from(slice: &[T]) -> Self {
927 CompactArc::from_slice(slice)
928 }
929}
930
931impl<T> From<Vec<T>> for CompactArc<[T]> {
932 #[inline]
933 fn from(vec: Vec<T>) -> Self {
934 CompactArc::from_vec(vec)
935 }
936}
937
938impl<T: fmt::Debug> fmt::Debug for CompactArc<[T]> {
939 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
940 fmt::Debug::fmt(&**self, f)
941 }
942}
943
944impl<T: PartialEq> PartialEq for CompactArc<[T]> {
945 #[inline]
946 fn eq(&self, other: &Self) -> bool {
947 if CompactArc::ptr_eq(self, other) {
948 return true;
949 }
950 **self == **other
951 }
952}
953
954impl<T: Eq> Eq for CompactArc<[T]> {}
955
956impl<T: PartialOrd> PartialOrd for CompactArc<[T]> {
957 #[inline]
958 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
959 (**self).partial_cmp(&**other)
960 }
961}
962
963impl<T: Ord> Ord for CompactArc<[T]> {
964 #[inline]
965 fn cmp(&self, other: &Self) -> Ordering {
966 (**self).cmp(&**other)
967 }
968}
969
970impl<T: Hash> Hash for CompactArc<[T]> {
971 fn hash<H: Hasher>(&self, state: &mut H) {
972 (**self).hash(state)
973 }
974}
975
976impl<T> Borrow<[T]> for CompactArc<[T]> {
977 fn borrow(&self) -> &[T] {
978 self
979 }
980}
981
982impl<T> AsRef<[T]> for CompactArc<[T]> {
983 fn as_ref(&self) -> &[T] {
984 self
985 }
986}
987
988#[cfg(test)]
989mod tests {
990 use super::*;
991
992 #[test]
993 fn test_new_and_deref() {
994 let arc = CompactArc::new(42);
995 assert_eq!(*arc, 42);
996 }
997
998 #[test]
999 fn test_clone_and_count() {
1000 let arc = CompactArc::new(42);
1001 assert_eq!(CompactArc::strong_count(&arc), 1);
1002
1003 let arc2 = arc.clone();
1004 assert_eq!(CompactArc::strong_count(&arc), 2);
1005 assert_eq!(CompactArc::strong_count(&arc2), 2);
1006
1007 drop(arc2);
1008 assert_eq!(CompactArc::strong_count(&arc), 1);
1009 }
1010
1011 #[test]
1012 fn test_ptr_eq() {
1013 let arc1 = CompactArc::new(42);
1014 let arc2 = arc1.clone();
1015 let arc3 = CompactArc::new(42);
1016
1017 assert!(CompactArc::ptr_eq(&arc1, &arc2));
1018 assert!(!CompactArc::ptr_eq(&arc1, &arc3));
1019 }
1020
1021 #[test]
1022 fn test_try_unwrap_success() {
1023 let arc = CompactArc::new(42);
1024 let value = CompactArc::try_unwrap(arc).unwrap();
1025 assert_eq!(value, 42);
1026 }
1027
1028 #[test]
1029 fn test_try_unwrap_failure() {
1030 let arc = CompactArc::new(42);
1031 let _arc2 = arc.clone();
1032 let result = CompactArc::try_unwrap(arc);
1033 assert!(result.is_err());
1034 }
1035
1036 #[test]
1037 fn test_get_mut() {
1038 let mut arc = CompactArc::new(42);
1039 *CompactArc::get_mut(&mut arc).unwrap() = 100;
1040 assert_eq!(*arc, 100);
1041
1042 let _arc2 = arc.clone();
1043 assert!(CompactArc::get_mut(&mut arc).is_none());
1044 }
1045
1046 #[test]
1047 fn test_make_mut() {
1048 let mut arc = CompactArc::new(42);
1049 *CompactArc::make_mut(&mut arc) = 100;
1050 assert_eq!(*arc, 100);
1051
1052 let arc2 = arc.clone();
1053 *CompactArc::make_mut(&mut arc) = 200;
1054 assert_eq!(*arc, 200);
1055 assert_eq!(*arc2, 100);
1056 }
1057
1058 #[test]
1059 fn test_into_raw_from_raw() {
1060 let arc = CompactArc::new(42);
1061 let ptr = CompactArc::into_raw(arc);
1062
1063 let arc2 = unsafe { CompactArc::from_raw(ptr) };
1065 assert_eq!(*arc2, 42);
1066 }
1067
1068 #[test]
1069 fn test_debug_display() {
1070 let arc = CompactArc::new(42);
1071 assert_eq!(format!("{:?}", arc), "42");
1072 assert_eq!(format!("{}", arc), "42");
1073 }
1074
1075 #[test]
1076 fn test_equality() {
1077 let arc1 = CompactArc::new(42);
1078 let arc2 = CompactArc::new(42);
1079 let arc3 = CompactArc::new(100);
1080
1081 assert_eq!(arc1, arc2);
1082 assert_ne!(arc1, arc3);
1083 }
1084
1085 #[test]
1086 fn test_ordering() {
1087 let arc1 = CompactArc::new(1);
1088 let arc2 = CompactArc::new(2);
1089
1090 assert!(arc1 < arc2);
1091 assert!(arc2 > arc1);
1092 }
1093
1094 #[test]
1095 fn test_hash() {
1096 use std::collections::HashMap;
1097
1098 let arc = CompactArc::new(42);
1099 let mut map = HashMap::new();
1100 map.insert(arc.clone(), "value");
1101
1102 assert_eq!(map.get(&arc), Some(&"value"));
1103 }
1104
1105 #[test]
1106 fn test_send_sync() {
1107 fn assert_send<T: Send>() {}
1108 fn assert_sync<T: Sync>() {}
1109
1110 assert_send::<CompactArc<i32>>();
1111 assert_sync::<CompactArc<i32>>();
1112 }
1113
1114 #[test]
1115 fn test_sized_pointer_size() {
1116 assert_eq!(std::mem::size_of::<CompactArc<i32>>(), 8);
1118 assert_eq!(std::mem::size_of::<CompactArc<i64>>(), 8);
1119 assert_eq!(std::mem::size_of::<CompactArc<String>>(), 8);
1120 }
1121
1122 #[test]
1123 fn test_header_size() {
1124 assert_eq!(std::mem::size_of::<Header>(), 16);
1126 }
1127
1128 #[test]
1129 fn test_high_alignment_type() {
1130 #[repr(align(64))]
1131 #[derive(Debug, Clone, PartialEq)]
1132 struct Aligned64 {
1133 value: u64,
1134 }
1135
1136 let arc = CompactArc::new(Aligned64 { value: 42 });
1137 assert_eq!(arc.value, 42);
1138
1139 let data_ptr = CompactArc::as_ptr(&arc);
1141 assert_eq!(data_ptr as usize % 64, 0, "Data should be 64-byte aligned");
1142
1143 let arc2 = arc.clone();
1145 assert_eq!(arc2.value, 42);
1146 assert_eq!(CompactArc::strong_count(&arc), 2);
1147
1148 drop(arc);
1149 assert_eq!(arc2.value, 42);
1150
1151 let value = CompactArc::try_unwrap(arc2).unwrap();
1153 assert_eq!(value.value, 42);
1154 }
1155
1156 #[test]
1157 fn test_high_alignment_slice() {
1158 #[repr(align(32))]
1159 #[derive(Debug, Clone, PartialEq)]
1160 struct Aligned32(u32);
1161
1162 let arr: CompactArc<[Aligned32]> =
1163 CompactArc::from_slice(&[Aligned32(1), Aligned32(2), Aligned32(3)]);
1164
1165 assert_eq!(arr.len(), 3);
1166 assert_eq!(arr[0], Aligned32(1));
1167 assert_eq!(arr[1], Aligned32(2));
1168 assert_eq!(arr[2], Aligned32(3));
1169
1170 let first_ptr = &arr[0] as *const Aligned32;
1172 assert_eq!(
1173 first_ptr as usize % 32,
1174 0,
1175 "Elements should be 32-byte aligned"
1176 );
1177 }
1178
1179 #[test]
1180 fn test_drop_complex_type() {
1181 use std::sync::atomic::{AtomicUsize, Ordering};
1182
1183 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
1184
1185 struct DropCounter;
1186 impl Drop for DropCounter {
1187 fn drop(&mut self) {
1188 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
1189 }
1190 }
1191
1192 DROP_COUNT.store(0, Ordering::SeqCst);
1193
1194 {
1195 let arc = CompactArc::new(DropCounter);
1196 let _arc2 = arc.clone();
1197 let _arc3 = arc.clone();
1198 }
1199
1200 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 1);
1201 }
1202
1203 #[test]
1204 fn test_thread_safety() {
1205 use std::thread;
1206
1207 let arc = CompactArc::new(0);
1208 let mut handles = vec![];
1209
1210 for _ in 0..10 {
1211 let arc_clone = arc.clone();
1212 handles.push(thread::spawn(move || {
1213 for _ in 0..1000 {
1214 let _ = *arc_clone;
1215 let _another = arc_clone.clone();
1216 }
1217 }));
1218 }
1219
1220 for handle in handles {
1221 handle.join().unwrap();
1222 }
1223
1224 drop(arc);
1225 }
1226
1227 #[test]
1232 fn test_str_basic() {
1233 let s: CompactArc<str> = CompactArc::from_str_slice("hello world");
1234 assert_eq!(&*s, "hello world");
1235 assert_eq!(s.len(), 11);
1236 assert!(!s.is_empty());
1237 }
1238
1239 #[test]
1240 fn test_str_empty() {
1241 let s: CompactArc<str> = CompactArc::from_str_slice("");
1242 assert_eq!(&*s, "");
1243 assert_eq!(s.len(), 0);
1244 assert!(s.is_empty());
1245 }
1246
1247 #[test]
1248 fn test_str_clone() {
1249 let s1: CompactArc<str> = CompactArc::from_str_slice("hello");
1250 let s2 = s1.clone();
1251
1252 assert_eq!(&*s1, "hello");
1253 assert_eq!(&*s2, "hello");
1254 assert!(CompactArc::ptr_eq(&s1, &s2));
1255 assert_eq!(CompactArc::strong_count(&s1), 2);
1256 }
1257
1258 #[test]
1259 fn test_str_drop() {
1260 let s1: CompactArc<str> = CompactArc::from_str_slice("test string");
1261 let s2 = s1.clone();
1262 assert_eq!(CompactArc::strong_count(&s1), 2);
1263
1264 drop(s1);
1265 assert_eq!(CompactArc::strong_count(&s2), 1);
1266 assert_eq!(&*s2, "test string");
1267 }
1268
1269 #[test]
1270 fn test_str_unicode() {
1271 let s: CompactArc<str> = CompactArc::from_str_slice("こんにちは世界");
1272 assert_eq!(&*s, "こんにちは世界");
1273 assert_eq!(s.len(), 21);
1274 }
1275
1276 #[test]
1277 fn test_str_from_impls() {
1278 let s1: CompactArc<str> = CompactArc::from("hello");
1279 let s2: CompactArc<str> = CompactArc::from(String::from("world"));
1280
1281 assert_eq!(&*s1, "hello");
1282 assert_eq!(&*s2, "world");
1283 }
1284
1285 #[test]
1286 fn test_str_thin_pointer() {
1287 assert_eq!(std::mem::size_of::<CompactArc<str>>(), 8);
1289 }
1290
1291 #[test]
1292 fn test_str_equality() {
1293 let s1: CompactArc<str> = CompactArc::from_str_slice("hello");
1294 let s2: CompactArc<str> = CompactArc::from_str_slice("hello");
1295 let s3: CompactArc<str> = CompactArc::from_str_slice("world");
1296
1297 assert_eq!(s1, s2);
1298 assert_ne!(s1, s3);
1299 }
1300
1301 #[test]
1302 fn test_str_hash() {
1303 use std::collections::HashMap;
1304
1305 let s: CompactArc<str> = CompactArc::from_str_slice("key");
1306 let mut map = HashMap::new();
1307 map.insert(s.clone(), "value");
1308
1309 assert_eq!(map.get(&s), Some(&"value"));
1310 }
1311
1312 #[test]
1317 fn test_slice_basic() {
1318 let arr: CompactArc<[i32]> = CompactArc::from_slice(&[1, 2, 3, 4, 5]);
1319 assert_eq!(&*arr, &[1, 2, 3, 4, 5]);
1320 assert_eq!(arr.len(), 5);
1321 assert!(!arr.is_empty());
1322 }
1323
1324 #[test]
1325 fn test_slice_empty() {
1326 let empty: &[i32] = &[];
1327 let arr: CompactArc<[i32]> = CompactArc::from_slice(empty);
1328 assert_eq!(&*arr, empty);
1329 assert_eq!(arr.len(), 0);
1330 assert!(arr.is_empty());
1331 }
1332
1333 #[test]
1334 fn test_slice_clone() {
1335 let arr1: CompactArc<[i32]> = CompactArc::from_slice(&[1, 2, 3]);
1336 let arr2 = arr1.clone();
1337
1338 assert_eq!(&*arr1, &[1, 2, 3]);
1339 assert_eq!(&*arr2, &[1, 2, 3]);
1340 assert!(CompactArc::ptr_eq(&arr1, &arr2));
1341 assert_eq!(CompactArc::strong_count(&arr1), 2);
1342 }
1343
1344 #[test]
1345 fn test_slice_thin_pointer() {
1346 assert_eq!(std::mem::size_of::<CompactArc<[i32]>>(), 8);
1348 assert_eq!(std::mem::size_of::<CompactArc<[String]>>(), 8);
1349 }
1350
1351 #[test]
1352 fn test_slice_from_vec() {
1353 let arr: CompactArc<[String]> = CompactArc::from(vec![
1354 String::from("a"),
1355 String::from("b"),
1356 String::from("c"),
1357 ]);
1358 assert_eq!(arr.len(), 3);
1359 assert_eq!(&arr[0], "a");
1360 assert_eq!(&arr[1], "b");
1361 assert_eq!(&arr[2], "c");
1362 }
1363
1364 #[test]
1365 fn test_slice_from_compact_vec() {
1366 let mut compact_vec = CompactVec::new();
1367 compact_vec.push(String::from("x"));
1368 compact_vec.push(String::from("y"));
1369 compact_vec.push(String::from("z"));
1370
1371 let arr: CompactArc<[String]> = CompactArc::from_compact_vec(compact_vec);
1372 assert_eq!(arr.len(), 3);
1373 assert_eq!(&arr[0], "x");
1374 assert_eq!(&arr[1], "y");
1375 assert_eq!(&arr[2], "z");
1376 }
1377
1378 #[test]
1379 fn test_from_compact_vec_moves_elements() {
1380 use std::sync::atomic::{AtomicUsize, Ordering};
1381
1382 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
1383 static CLONE_COUNT: AtomicUsize = AtomicUsize::new(0);
1384
1385 #[derive(Debug, PartialEq)]
1386 struct MoveTracker(u32);
1387
1388 impl Clone for MoveTracker {
1389 fn clone(&self) -> Self {
1390 CLONE_COUNT.fetch_add(1, Ordering::SeqCst);
1391 MoveTracker(self.0)
1392 }
1393 }
1394
1395 impl Drop for MoveTracker {
1396 fn drop(&mut self) {
1397 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
1398 }
1399 }
1400
1401 DROP_COUNT.store(0, Ordering::SeqCst);
1402 CLONE_COUNT.store(0, Ordering::SeqCst);
1403
1404 {
1405 let mut compact_vec = CompactVec::new();
1406 compact_vec.push(MoveTracker(1));
1407 compact_vec.push(MoveTracker(2));
1408 compact_vec.push(MoveTracker(3));
1409
1410 let arr: CompactArc<[MoveTracker]> = CompactArc::from_compact_vec(compact_vec);
1411
1412 assert_eq!(arr[0].0, 1);
1414 assert_eq!(arr[1].0, 2);
1415 assert_eq!(arr[2].0, 3);
1416
1417 assert_eq!(
1419 CLONE_COUNT.load(Ordering::SeqCst),
1420 0,
1421 "from_compact_vec should move, not clone"
1422 );
1423 }
1424
1425 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 3);
1427 }
1428
1429 #[test]
1430 fn test_slice_drop_elements() {
1431 use std::sync::atomic::{AtomicUsize, Ordering};
1432
1433 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
1434
1435 #[derive(Clone)]
1436 struct DropCounter;
1437 impl Drop for DropCounter {
1438 fn drop(&mut self) {
1439 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
1440 }
1441 }
1442
1443 DROP_COUNT.store(0, Ordering::SeqCst);
1444
1445 {
1446 let arr: CompactArc<[DropCounter]> =
1447 CompactArc::from_slice(&[DropCounter, DropCounter, DropCounter]);
1448 let _arr2 = arr.clone();
1449 }
1450
1451 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 6);
1453 }
1454
1455 #[test]
1456 fn test_from_slice_panic_safety() {
1457 use std::sync::atomic::{AtomicUsize, Ordering};
1458
1459 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
1460 static CLONE_COUNT: AtomicUsize = AtomicUsize::new(0);
1461
1462 #[derive(Debug)]
1463 struct PanicOnThird(u32);
1464
1465 impl Clone for PanicOnThird {
1466 fn clone(&self) -> Self {
1467 let count = CLONE_COUNT.fetch_add(1, Ordering::SeqCst);
1468 if count == 2 {
1469 panic!("Panic on third clone!");
1470 }
1471 PanicOnThird(self.0)
1472 }
1473 }
1474
1475 impl Drop for PanicOnThird {
1476 fn drop(&mut self) {
1477 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
1478 }
1479 }
1480
1481 DROP_COUNT.store(0, Ordering::SeqCst);
1482 CLONE_COUNT.store(0, Ordering::SeqCst);
1483
1484 let slice = &[
1485 PanicOnThird(1),
1486 PanicOnThird(2),
1487 PanicOnThird(3),
1488 PanicOnThird(4),
1489 ];
1490
1491 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1492 let _: CompactArc<[PanicOnThird]> = CompactArc::from_slice(slice);
1493 }));
1494
1495 assert!(result.is_err(), "Should have panicked");
1496
1497 let drops_from_cleanup = DROP_COUNT.load(Ordering::SeqCst);
1500 assert_eq!(
1501 drops_from_cleanup, 2,
1502 "Should have dropped 2 successfully cloned elements"
1503 );
1504 }
1505
1506 #[test]
1507 fn test_from_vec_moves_elements() {
1508 use std::sync::atomic::{AtomicUsize, Ordering};
1509
1510 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
1511 static CLONE_COUNT: AtomicUsize = AtomicUsize::new(0);
1512
1513 #[derive(Debug, PartialEq)]
1514 struct MoveTracker(u32);
1515
1516 impl Clone for MoveTracker {
1517 fn clone(&self) -> Self {
1518 CLONE_COUNT.fetch_add(1, Ordering::SeqCst);
1519 MoveTracker(self.0)
1520 }
1521 }
1522
1523 impl Drop for MoveTracker {
1524 fn drop(&mut self) {
1525 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
1526 }
1527 }
1528
1529 DROP_COUNT.store(0, Ordering::SeqCst);
1530 CLONE_COUNT.store(0, Ordering::SeqCst);
1531
1532 {
1533 let vec = vec![MoveTracker(1), MoveTracker(2), MoveTracker(3)];
1534 let arr: CompactArc<[MoveTracker]> = CompactArc::from_vec(vec);
1535
1536 assert_eq!(arr[0].0, 1);
1538 assert_eq!(arr[1].0, 2);
1539 assert_eq!(arr[2].0, 3);
1540
1541 assert_eq!(
1543 CLONE_COUNT.load(Ordering::SeqCst),
1544 0,
1545 "from_vec should move, not clone"
1546 );
1547 }
1548
1549 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 3);
1551 }
1552
1553 #[test]
1554 fn test_dst_send_sync() {
1555 fn assert_send<T: Send>() {}
1556 fn assert_sync<T: Sync>() {}
1557
1558 assert_send::<CompactArc<str>>();
1559 assert_sync::<CompactArc<str>>();
1560 assert_send::<CompactArc<[i32]>>();
1561 assert_sync::<CompactArc<[i32]>>();
1562 }
1563
1564 #[test]
1565 fn test_str_thread_safety() {
1566 use std::thread;
1567
1568 let s: CompactArc<str> = CompactArc::from_str_slice("shared string");
1569 let mut handles = vec![];
1570
1571 for _ in 0..10 {
1572 let s_clone = s.clone();
1573 handles.push(thread::spawn(move || {
1574 for _ in 0..1000 {
1575 let _ = s_clone.len();
1576 let _another = s_clone.clone();
1577 }
1578 }));
1579 }
1580
1581 for handle in handles {
1582 handle.join().unwrap();
1583 }
1584
1585 drop(s);
1586 }
1587}