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 unsafe { (*header).count.load(AtomicOrdering::Acquire) };
218 unsafe {
222 T::drop_and_dealloc(header as *mut u8);
223 }
224 }
225 }
226}
227
228impl<T: ?Sized + CompactArcDrop> Clone for CompactArc<T> {
233 #[inline]
234 fn clone(&self) -> Self {
235 let header = self.ptr.as_ptr();
236 let old_count = unsafe { (*header).count.fetch_add(1, AtomicOrdering::Relaxed) };
240
241 if old_count > isize::MAX as usize {
242 std::process::abort();
243 }
244
245 CompactArc {
246 ptr: self.ptr,
247 _marker: PhantomData,
248 }
249 }
250}
251
252impl<T: ?Sized + CompactArcDrop> CompactArc<T> {
257 #[inline]
259 pub fn ptr_eq(this: &Self, other: &Self) -> bool {
260 ptr::addr_eq(this.ptr.as_ptr(), other.ptr.as_ptr())
261 }
262
263 #[inline]
268 pub fn strong_count(this: &Self) -> usize {
269 unsafe { (*this.ptr.as_ptr()).count.load(AtomicOrdering::Relaxed) }
272 }
273
274 #[inline]
280 fn is_unique(this: &Self) -> bool {
281 unsafe { (*this.ptr.as_ptr()).count.load(AtomicOrdering::Acquire) == 1 }
284 }
285
286 #[inline]
288 pub fn meta(this: &Self) -> usize {
289 unsafe { (*this.ptr.as_ptr()).len }
293 }
294}
295
296impl<T: CompactArcDrop> CompactArc<T> {
301 #[inline]
303 #[must_use]
304 pub fn new(data: T) -> Self {
305 Self::new_with_meta(data, 0)
306 }
307
308 #[inline]
311 #[must_use]
312 pub fn new_with_meta(data: T, meta: usize) -> Self {
313 let data_offset = data_offset_for::<T>();
314 let align = mem::align_of::<T>().max(mem::align_of::<Header>());
315 let total_size = data_offset + mem::size_of::<T>();
316 let layout = Layout::from_size_align(total_size, align).expect("layout overflow");
317
318 unsafe {
323 let ptr = alloc(layout);
324 if ptr.is_null() {
325 handle_alloc_error(layout);
326 }
327
328 let header = ptr as *mut Header;
330 ptr::write(
331 header,
332 Header {
333 count: AtomicUsize::new(1),
334 len: meta,
335 },
336 );
337
338 let data_ptr = ptr.add(data_offset) as *mut T;
340 ptr::write(data_ptr, data);
341
342 CompactArc {
343 ptr: NonNull::new_unchecked(header),
344 _marker: PhantomData,
345 }
346 }
347 }
348
349 #[inline]
352 pub fn try_unwrap(this: Self) -> Result<T, Self> {
353 let header = this.ptr.as_ptr();
354
355 if unsafe {
359 (*header)
360 .count
361 .compare_exchange(1, 0, AtomicOrdering::Acquire, AtomicOrdering::Relaxed)
362 .is_ok()
363 } {
364 let _ = ManuallyDrop::new(this);
365
366 unsafe {
370 let data_offset = data_offset_for::<T>();
372 let data_ptr = (header as *const u8).add(data_offset) as *const T;
373 let data = ptr::read(data_ptr);
374
375 let align = mem::align_of::<T>().max(mem::align_of::<Header>());
377 let layout =
378 Layout::from_size_align_unchecked(data_offset + mem::size_of::<T>(), align);
379 dealloc(header as *mut u8, layout);
380
381 Ok(data)
382 }
383 } else {
384 Err(this)
385 }
386 }
387
388 #[inline]
393 pub fn get_mut(this: &mut Self) -> Option<&mut T> {
394 if Self::is_unique(this) {
395 unsafe {
399 let data_ptr = (this.ptr.as_ptr() as *mut u8).add(data_offset_for::<T>()) as *mut T;
400 Some(&mut *data_ptr)
401 }
402 } else {
403 None
404 }
405 }
406
407 #[inline]
411 pub fn make_mut(this: &mut Self) -> &mut T
412 where
413 T: Clone,
414 {
415 if !Self::is_unique(this) {
417 let meta = Self::meta(this);
418 *this = CompactArc::new_with_meta((**this).clone(), meta);
420 }
421 Self::get_mut(this).unwrap()
423 }
424
425 #[inline]
427 pub fn as_ptr(this: &Self) -> *const T {
428 let header = this.ptr.as_ptr();
433 unsafe { (header as *const u8).add(data_offset_for::<T>()) as *const T }
434 }
435
436 #[inline]
438 pub fn into_raw(this: Self) -> *const T {
439 let header = this.ptr.as_ptr();
443 let ptr = unsafe { (header as *const u8).add(data_offset_for::<T>()) as *const T };
444 mem::forget(this);
445 ptr
446 }
447
448 #[inline]
454 pub unsafe fn from_raw(ptr: *const T) -> Self {
455 let header = (ptr as *const u8).sub(data_offset_for::<T>()) as *mut Header;
456 CompactArc {
457 ptr: NonNull::new_unchecked(header),
458 _marker: PhantomData,
459 }
460 }
461}
462
463impl<T: CompactArcDrop> Deref for CompactArc<T> {
464 type Target = T;
465
466 #[inline]
467 fn deref(&self) -> &T {
468 unsafe {
472 let data_ptr = (self.ptr.as_ptr() as *const u8).add(data_offset_for::<T>()) as *const T;
473 &*data_ptr
474 }
475 }
476}
477
478impl<T: CompactArcDrop + Default> Default for CompactArc<T> {
479 #[inline]
480 fn default() -> Self {
481 CompactArc::new(T::default())
482 }
483}
484
485impl<T: CompactArcDrop + fmt::Debug> fmt::Debug for CompactArc<T> {
486 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
487 fmt::Debug::fmt(&**self, f)
488 }
489}
490
491impl<T: CompactArcDrop + fmt::Display> fmt::Display for CompactArc<T> {
492 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493 fmt::Display::fmt(&**self, f)
494 }
495}
496
497impl<T: CompactArcDrop + PartialEq> PartialEq for CompactArc<T> {
498 #[inline]
499 fn eq(&self, other: &Self) -> bool {
500 if CompactArc::ptr_eq(self, other) {
501 return true;
502 }
503 **self == **other
504 }
505}
506
507impl<T: CompactArcDrop + Eq> Eq for CompactArc<T> {}
508
509impl<T: CompactArcDrop + PartialOrd> PartialOrd for CompactArc<T> {
510 #[inline]
511 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
512 (**self).partial_cmp(&**other)
513 }
514}
515
516impl<T: CompactArcDrop + Ord> Ord for CompactArc<T> {
517 #[inline]
518 fn cmp(&self, other: &Self) -> Ordering {
519 (**self).cmp(&**other)
520 }
521}
522
523impl<T: CompactArcDrop + Hash> Hash for CompactArc<T> {
524 fn hash<H: Hasher>(&self, state: &mut H) {
525 (**self).hash(state)
526 }
527}
528
529impl<T: CompactArcDrop> Borrow<T> for CompactArc<T> {
530 fn borrow(&self) -> &T {
531 self
532 }
533}
534
535impl<T: CompactArcDrop> AsRef<T> for CompactArc<T> {
536 fn as_ref(&self) -> &T {
537 self
538 }
539}
540
541impl<T: CompactArcDrop> From<T> for CompactArc<T> {
542 #[inline]
543 fn from(value: T) -> Self {
544 CompactArc::new(value)
545 }
546}
547
548impl CompactArc<str> {
553 #[must_use]
557 pub fn from_str_slice(s: &str) -> Self {
558 let len = s.len();
559 let data_offset = data_offset_for::<u8>(); let total_size = data_offset + len;
561 let layout = Layout::from_size_align(total_size, mem::align_of::<Header>())
562 .expect("layout overflow");
563
564 unsafe {
568 let ptr = alloc(layout);
569 if ptr.is_null() {
570 handle_alloc_error(layout);
571 }
572
573 let header = ptr as *mut Header;
575 ptr::write(
576 header,
577 Header {
578 count: AtomicUsize::new(1),
579 len,
580 },
581 );
582
583 let data_ptr = ptr.add(data_offset);
585 ptr::copy_nonoverlapping(s.as_ptr(), data_ptr, len);
586
587 CompactArc {
588 ptr: NonNull::new_unchecked(header),
589 _marker: PhantomData,
590 }
591 }
592 }
593
594 #[inline]
596 pub fn len(&self) -> usize {
597 unsafe { (*self.ptr.as_ptr()).len }
600 }
601
602 #[inline]
604 pub fn is_empty(&self) -> bool {
605 self.len() == 0
606 }
607}
608
609impl Deref for CompactArc<str> {
610 type Target = str;
611
612 #[inline]
613 fn deref(&self) -> &str {
614 unsafe {
618 let header = self.ptr.as_ptr();
619 let len = (*header).len;
620 let data_offset = data_offset_for::<u8>(); let data_ptr = (header as *const u8).add(data_offset);
622 std::str::from_utf8_unchecked(std::slice::from_raw_parts(data_ptr, len))
623 }
624 }
625}
626
627impl From<&str> for CompactArc<str> {
628 #[inline]
629 fn from(s: &str) -> Self {
630 CompactArc::from_str_slice(s)
631 }
632}
633
634impl From<String> for CompactArc<str> {
635 #[inline]
636 fn from(s: String) -> Self {
637 CompactArc::from_str_slice(&s)
638 }
639}
640
641impl fmt::Debug for CompactArc<str> {
642 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
643 fmt::Debug::fmt(&**self, f)
644 }
645}
646
647impl fmt::Display for CompactArc<str> {
648 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
649 fmt::Display::fmt(&**self, f)
650 }
651}
652
653impl PartialEq for CompactArc<str> {
654 #[inline]
655 fn eq(&self, other: &Self) -> bool {
656 if CompactArc::ptr_eq(self, other) {
657 return true;
658 }
659 **self == **other
660 }
661}
662
663impl Eq for CompactArc<str> {}
664
665impl PartialOrd for CompactArc<str> {
666 #[inline]
667 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
668 Some(self.cmp(other))
669 }
670}
671
672impl Ord for CompactArc<str> {
673 #[inline]
674 fn cmp(&self, other: &Self) -> Ordering {
675 (**self).cmp(&**other)
676 }
677}
678
679impl Hash for CompactArc<str> {
680 fn hash<H: Hasher>(&self, state: &mut H) {
681 (**self).hash(state)
682 }
683}
684
685impl Borrow<str> for CompactArc<str> {
686 fn borrow(&self) -> &str {
687 self
688 }
689}
690
691impl AsRef<str> for CompactArc<str> {
692 fn as_ref(&self) -> &str {
693 self
694 }
695}
696
697impl<T> CompactArc<[T]> {
702 #[must_use]
706 pub fn from_vec(mut vec: Vec<T>) -> Self {
707 let len = vec.len();
708 let data_offset = data_offset_for::<T>();
709 let align = mem::align_of::<T>().max(mem::align_of::<Header>());
710 let data_size = mem::size_of::<T>() * len;
711 let layout =
712 Layout::from_size_align(data_offset + data_size, align).expect("layout overflow");
713
714 unsafe {
719 let ptr = alloc(layout);
720 if ptr.is_null() {
721 handle_alloc_error(layout);
722 }
723
724 let header = ptr as *mut Header;
726 ptr::write(
727 header,
728 Header {
729 count: AtomicUsize::new(1),
730 len,
731 },
732 );
733
734 let data_ptr = ptr.add(data_offset) as *mut T;
736 ptr::copy_nonoverlapping(vec.as_ptr(), data_ptr, len);
737
738 vec.set_len(0);
740
741 CompactArc {
742 ptr: NonNull::new_unchecked(header),
743 _marker: PhantomData,
744 }
745 }
746 }
747
748 #[must_use]
753 pub fn from_compact_vec(mut vec: CompactVec<T>) -> Self {
754 let len = vec.len();
755 let data_offset = data_offset_for::<T>();
756 let align = mem::align_of::<T>().max(mem::align_of::<Header>());
757 let data_size = mem::size_of::<T>() * len;
758 let layout =
759 Layout::from_size_align(data_offset + data_size, align).expect("layout overflow");
760
761 unsafe {
766 let ptr = alloc(layout);
767 if ptr.is_null() {
768 handle_alloc_error(layout);
769 }
770
771 let header = ptr as *mut Header;
773 ptr::write(
774 header,
775 Header {
776 count: AtomicUsize::new(1),
777 len,
778 },
779 );
780
781 let data_ptr = ptr.add(data_offset) as *mut T;
783 ptr::copy_nonoverlapping(vec.as_ptr(), data_ptr, len);
784
785 vec.set_len(0);
787
788 CompactArc {
789 ptr: NonNull::new_unchecked(header),
790 _marker: PhantomData,
791 }
792 }
793 }
794}
795
796impl<T: Clone> CompactArc<[T]> {
797 #[must_use]
806 pub fn from_slice(slice: &[T]) -> Self {
807 let len = slice.len();
808 let data_offset = data_offset_for::<T>();
809 let align = mem::align_of::<T>().max(mem::align_of::<Header>());
810 let layout = Layout::from_size_align(data_offset + mem::size_of_val(slice), align)
811 .expect("layout overflow");
812
813 unsafe {
818 let ptr = alloc(layout);
819 if ptr.is_null() {
820 handle_alloc_error(layout);
821 }
822
823 let header = ptr as *mut Header;
825 ptr::write(
826 header,
827 Header {
828 count: AtomicUsize::new(1),
829 len,
830 },
831 );
832
833 let data_ptr = ptr.add(data_offset) as *mut T;
834
835 struct CloneGuard<T> {
837 data_ptr: *mut T,
838 alloc_ptr: *mut u8,
839 layout: Layout,
840 written: usize,
841 }
842
843 impl<T> Drop for CloneGuard<T> {
844 fn drop(&mut self) {
845 unsafe {
849 let slice = ptr::slice_from_raw_parts_mut(self.data_ptr, self.written);
851 ptr::drop_in_place(slice);
852 dealloc(self.alloc_ptr, self.layout);
854 }
855 }
856 }
857
858 let mut guard = CloneGuard {
859 data_ptr,
860 alloc_ptr: ptr,
861 layout,
862 written: 0,
863 };
864
865 for (i, item) in slice.iter().enumerate() {
867 ptr::write(data_ptr.add(i), item.clone());
868 guard.written += 1;
869 }
870
871 mem::forget(guard);
873
874 CompactArc {
875 ptr: NonNull::new_unchecked(header),
876 _marker: PhantomData,
877 }
878 }
879 }
880}
881
882impl<T> CompactArc<[T]> {
883 #[inline]
885 pub fn len(&self) -> usize {
886 unsafe { (*self.ptr.as_ptr()).len }
889 }
890
891 #[inline]
893 pub fn is_empty(&self) -> bool {
894 self.len() == 0
895 }
896
897 #[inline]
903 #[doc(hidden)]
904 pub fn data_ptr_mut(&self) -> *mut T {
905 unsafe { (self.ptr.as_ptr() as *mut u8).add(data_offset_for::<T>()) as *mut T }
906 }
907}
908
909impl<T> Deref for CompactArc<[T]> {
910 type Target = [T];
911
912 #[inline]
913 fn deref(&self) -> &[T] {
914 unsafe {
919 let header = self.ptr.as_ptr();
920 let len = (*header).len;
921 let data_ptr = (header as *const u8).add(data_offset_for::<T>()) as *const T;
922 std::slice::from_raw_parts(data_ptr, len)
923 }
924 }
925}
926
927impl<T: Clone> From<&[T]> for CompactArc<[T]> {
928 #[inline]
929 fn from(slice: &[T]) -> Self {
930 CompactArc::from_slice(slice)
931 }
932}
933
934impl<T> From<Vec<T>> for CompactArc<[T]> {
935 #[inline]
936 fn from(vec: Vec<T>) -> Self {
937 CompactArc::from_vec(vec)
938 }
939}
940
941impl<T: fmt::Debug> fmt::Debug for CompactArc<[T]> {
942 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
943 fmt::Debug::fmt(&**self, f)
944 }
945}
946
947impl<T: PartialEq> PartialEq for CompactArc<[T]> {
948 #[inline]
949 fn eq(&self, other: &Self) -> bool {
950 if CompactArc::ptr_eq(self, other) {
951 return true;
952 }
953 **self == **other
954 }
955}
956
957impl<T: Eq> Eq for CompactArc<[T]> {}
958
959impl<T: PartialOrd> PartialOrd for CompactArc<[T]> {
960 #[inline]
961 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
962 (**self).partial_cmp(&**other)
963 }
964}
965
966impl<T: Ord> Ord for CompactArc<[T]> {
967 #[inline]
968 fn cmp(&self, other: &Self) -> Ordering {
969 (**self).cmp(&**other)
970 }
971}
972
973impl<T: Hash> Hash for CompactArc<[T]> {
974 fn hash<H: Hasher>(&self, state: &mut H) {
975 (**self).hash(state)
976 }
977}
978
979impl<T> Borrow<[T]> for CompactArc<[T]> {
980 fn borrow(&self) -> &[T] {
981 self
982 }
983}
984
985impl<T> AsRef<[T]> for CompactArc<[T]> {
986 fn as_ref(&self) -> &[T] {
987 self
988 }
989}
990
991#[cfg(test)]
992mod tests {
993 use super::*;
994
995 #[test]
996 fn test_new_and_deref() {
997 let arc = CompactArc::new(42);
998 assert_eq!(*arc, 42);
999 }
1000
1001 #[test]
1002 fn test_clone_and_count() {
1003 let arc = CompactArc::new(42);
1004 assert_eq!(CompactArc::strong_count(&arc), 1);
1005
1006 let arc2 = arc.clone();
1007 assert_eq!(CompactArc::strong_count(&arc), 2);
1008 assert_eq!(CompactArc::strong_count(&arc2), 2);
1009
1010 drop(arc2);
1011 assert_eq!(CompactArc::strong_count(&arc), 1);
1012 }
1013
1014 #[test]
1015 fn test_ptr_eq() {
1016 let arc1 = CompactArc::new(42);
1017 let arc2 = arc1.clone();
1018 let arc3 = CompactArc::new(42);
1019
1020 assert!(CompactArc::ptr_eq(&arc1, &arc2));
1021 assert!(!CompactArc::ptr_eq(&arc1, &arc3));
1022 }
1023
1024 #[test]
1025 fn test_try_unwrap_success() {
1026 let arc = CompactArc::new(42);
1027 let value = CompactArc::try_unwrap(arc).unwrap();
1028 assert_eq!(value, 42);
1029 }
1030
1031 #[test]
1032 fn test_try_unwrap_failure() {
1033 let arc = CompactArc::new(42);
1034 let _arc2 = arc.clone();
1035 let result = CompactArc::try_unwrap(arc);
1036 assert!(result.is_err());
1037 }
1038
1039 #[test]
1040 fn test_get_mut() {
1041 let mut arc = CompactArc::new(42);
1042 *CompactArc::get_mut(&mut arc).unwrap() = 100;
1043 assert_eq!(*arc, 100);
1044
1045 let _arc2 = arc.clone();
1046 assert!(CompactArc::get_mut(&mut arc).is_none());
1047 }
1048
1049 #[test]
1050 fn test_make_mut() {
1051 let mut arc = CompactArc::new(42);
1052 *CompactArc::make_mut(&mut arc) = 100;
1053 assert_eq!(*arc, 100);
1054
1055 let arc2 = arc.clone();
1056 *CompactArc::make_mut(&mut arc) = 200;
1057 assert_eq!(*arc, 200);
1058 assert_eq!(*arc2, 100);
1059 }
1060
1061 #[test]
1062 fn test_into_raw_from_raw() {
1063 let arc = CompactArc::new(42);
1064 let ptr = CompactArc::into_raw(arc);
1065
1066 let arc2 = unsafe { CompactArc::from_raw(ptr) };
1068 assert_eq!(*arc2, 42);
1069 }
1070
1071 #[test]
1072 fn test_debug_display() {
1073 let arc = CompactArc::new(42);
1074 assert_eq!(format!("{:?}", arc), "42");
1075 assert_eq!(format!("{}", arc), "42");
1076 }
1077
1078 #[test]
1079 fn test_equality() {
1080 let arc1 = CompactArc::new(42);
1081 let arc2 = CompactArc::new(42);
1082 let arc3 = CompactArc::new(100);
1083
1084 assert_eq!(arc1, arc2);
1085 assert_ne!(arc1, arc3);
1086 }
1087
1088 #[test]
1089 fn test_ordering() {
1090 let arc1 = CompactArc::new(1);
1091 let arc2 = CompactArc::new(2);
1092
1093 assert!(arc1 < arc2);
1094 assert!(arc2 > arc1);
1095 }
1096
1097 #[test]
1098 fn test_hash() {
1099 use std::collections::HashMap;
1100
1101 let arc = CompactArc::new(42);
1102 let mut map = HashMap::new();
1103 map.insert(arc.clone(), "value");
1104
1105 assert_eq!(map.get(&arc), Some(&"value"));
1106 }
1107
1108 #[test]
1109 fn test_send_sync() {
1110 fn assert_send<T: Send>() {}
1111 fn assert_sync<T: Sync>() {}
1112
1113 assert_send::<CompactArc<i32>>();
1114 assert_sync::<CompactArc<i32>>();
1115 }
1116
1117 #[test]
1118 fn test_sized_pointer_size() {
1119 assert_eq!(std::mem::size_of::<CompactArc<i32>>(), 8);
1121 assert_eq!(std::mem::size_of::<CompactArc<i64>>(), 8);
1122 assert_eq!(std::mem::size_of::<CompactArc<String>>(), 8);
1123 }
1124
1125 #[test]
1126 fn test_header_size() {
1127 assert_eq!(std::mem::size_of::<Header>(), 16);
1129 }
1130
1131 #[test]
1132 fn test_high_alignment_type() {
1133 #[repr(align(64))]
1134 #[derive(Debug, Clone, PartialEq)]
1135 struct Aligned64 {
1136 value: u64,
1137 }
1138
1139 let arc = CompactArc::new(Aligned64 { value: 42 });
1140 assert_eq!(arc.value, 42);
1141
1142 let data_ptr = CompactArc::as_ptr(&arc);
1144 assert_eq!(data_ptr as usize % 64, 0, "Data should be 64-byte aligned");
1145
1146 let arc2 = arc.clone();
1148 assert_eq!(arc2.value, 42);
1149 assert_eq!(CompactArc::strong_count(&arc), 2);
1150
1151 drop(arc);
1152 assert_eq!(arc2.value, 42);
1153
1154 let value = CompactArc::try_unwrap(arc2).unwrap();
1156 assert_eq!(value.value, 42);
1157 }
1158
1159 #[test]
1160 fn test_high_alignment_slice() {
1161 #[repr(align(32))]
1162 #[derive(Debug, Clone, PartialEq)]
1163 struct Aligned32(u32);
1164
1165 let arr: CompactArc<[Aligned32]> =
1166 CompactArc::from_slice(&[Aligned32(1), Aligned32(2), Aligned32(3)]);
1167
1168 assert_eq!(arr.len(), 3);
1169 assert_eq!(arr[0], Aligned32(1));
1170 assert_eq!(arr[1], Aligned32(2));
1171 assert_eq!(arr[2], Aligned32(3));
1172
1173 let first_ptr = &arr[0] as *const Aligned32;
1175 assert_eq!(
1176 first_ptr as usize % 32,
1177 0,
1178 "Elements should be 32-byte aligned"
1179 );
1180 }
1181
1182 #[test]
1183 fn test_drop_complex_type() {
1184 use std::sync::atomic::{AtomicUsize, Ordering};
1185
1186 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
1187
1188 struct DropCounter;
1189 impl Drop for DropCounter {
1190 fn drop(&mut self) {
1191 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
1192 }
1193 }
1194
1195 DROP_COUNT.store(0, Ordering::SeqCst);
1196
1197 {
1198 let arc = CompactArc::new(DropCounter);
1199 let _arc2 = arc.clone();
1200 let _arc3 = arc.clone();
1201 }
1202
1203 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 1);
1204 }
1205
1206 #[test]
1207 fn test_last_reference_drops_before_workers_are_joined() {
1208 use std::sync::{Arc, Barrier};
1209
1210 let barrier = Arc::new(Barrier::new(8));
1211 let value = CompactArc::new(vec![42_u64; 128]);
1212 let mut workers = Vec::new();
1213 for _ in 0..8 {
1214 let shared = value.clone();
1215 let barrier = barrier.clone();
1216 workers.push(std::thread::spawn(move || {
1217 barrier.wait();
1218 assert_eq!(shared.iter().sum::<u64>(), 42 * 128);
1219 drop(shared);
1220 }));
1221 }
1222 drop(value);
1225 for worker in workers {
1226 worker.join().expect("reader thread");
1227 }
1228 }
1229
1230 #[test]
1231 fn test_thread_safety() {
1232 use std::thread;
1233
1234 let arc = CompactArc::new(0);
1235 let mut handles = vec![];
1236
1237 for _ in 0..10 {
1238 let arc_clone = arc.clone();
1239 handles.push(thread::spawn(move || {
1240 for _ in 0..1000 {
1241 let _ = *arc_clone;
1242 let _another = arc_clone.clone();
1243 }
1244 }));
1245 }
1246
1247 for handle in handles {
1248 handle.join().unwrap();
1249 }
1250
1251 drop(arc);
1252 }
1253
1254 #[test]
1259 fn test_str_basic() {
1260 let s: CompactArc<str> = CompactArc::from_str_slice("hello world");
1261 assert_eq!(&*s, "hello world");
1262 assert_eq!(s.len(), 11);
1263 assert!(!s.is_empty());
1264 }
1265
1266 #[test]
1267 fn test_str_empty() {
1268 let s: CompactArc<str> = CompactArc::from_str_slice("");
1269 assert_eq!(&*s, "");
1270 assert_eq!(s.len(), 0);
1271 assert!(s.is_empty());
1272 }
1273
1274 #[test]
1275 fn test_str_clone() {
1276 let s1: CompactArc<str> = CompactArc::from_str_slice("hello");
1277 let s2 = s1.clone();
1278
1279 assert_eq!(&*s1, "hello");
1280 assert_eq!(&*s2, "hello");
1281 assert!(CompactArc::ptr_eq(&s1, &s2));
1282 assert_eq!(CompactArc::strong_count(&s1), 2);
1283 }
1284
1285 #[test]
1286 fn test_str_drop() {
1287 let s1: CompactArc<str> = CompactArc::from_str_slice("test string");
1288 let s2 = s1.clone();
1289 assert_eq!(CompactArc::strong_count(&s1), 2);
1290
1291 drop(s1);
1292 assert_eq!(CompactArc::strong_count(&s2), 1);
1293 assert_eq!(&*s2, "test string");
1294 }
1295
1296 #[test]
1297 fn test_str_unicode() {
1298 let s: CompactArc<str> = CompactArc::from_str_slice("こんにちは世界");
1299 assert_eq!(&*s, "こんにちは世界");
1300 assert_eq!(s.len(), 21);
1301 }
1302
1303 #[test]
1304 fn test_str_from_impls() {
1305 let s1: CompactArc<str> = CompactArc::from("hello");
1306 let s2: CompactArc<str> = CompactArc::from(String::from("world"));
1307
1308 assert_eq!(&*s1, "hello");
1309 assert_eq!(&*s2, "world");
1310 }
1311
1312 #[test]
1313 fn test_str_thin_pointer() {
1314 assert_eq!(std::mem::size_of::<CompactArc<str>>(), 8);
1316 }
1317
1318 #[test]
1319 fn test_str_equality() {
1320 let s1: CompactArc<str> = CompactArc::from_str_slice("hello");
1321 let s2: CompactArc<str> = CompactArc::from_str_slice("hello");
1322 let s3: CompactArc<str> = CompactArc::from_str_slice("world");
1323
1324 assert_eq!(s1, s2);
1325 assert_ne!(s1, s3);
1326 }
1327
1328 #[test]
1329 fn test_str_hash() {
1330 use std::collections::HashMap;
1331
1332 let s: CompactArc<str> = CompactArc::from_str_slice("key");
1333 let mut map = HashMap::new();
1334 map.insert(s.clone(), "value");
1335
1336 assert_eq!(map.get(&s), Some(&"value"));
1337 }
1338
1339 #[test]
1344 fn test_slice_basic() {
1345 let arr: CompactArc<[i32]> = CompactArc::from_slice(&[1, 2, 3, 4, 5]);
1346 assert_eq!(&*arr, &[1, 2, 3, 4, 5]);
1347 assert_eq!(arr.len(), 5);
1348 assert!(!arr.is_empty());
1349 }
1350
1351 #[test]
1352 fn test_slice_empty() {
1353 let empty: &[i32] = &[];
1354 let arr: CompactArc<[i32]> = CompactArc::from_slice(empty);
1355 assert_eq!(&*arr, empty);
1356 assert_eq!(arr.len(), 0);
1357 assert!(arr.is_empty());
1358 }
1359
1360 #[test]
1361 fn test_slice_clone() {
1362 let arr1: CompactArc<[i32]> = CompactArc::from_slice(&[1, 2, 3]);
1363 let arr2 = arr1.clone();
1364
1365 assert_eq!(&*arr1, &[1, 2, 3]);
1366 assert_eq!(&*arr2, &[1, 2, 3]);
1367 assert!(CompactArc::ptr_eq(&arr1, &arr2));
1368 assert_eq!(CompactArc::strong_count(&arr1), 2);
1369 }
1370
1371 #[test]
1372 fn test_slice_thin_pointer() {
1373 assert_eq!(std::mem::size_of::<CompactArc<[i32]>>(), 8);
1375 assert_eq!(std::mem::size_of::<CompactArc<[String]>>(), 8);
1376 }
1377
1378 #[test]
1379 fn test_slice_from_vec() {
1380 let arr: CompactArc<[String]> = CompactArc::from(vec![
1381 String::from("a"),
1382 String::from("b"),
1383 String::from("c"),
1384 ]);
1385 assert_eq!(arr.len(), 3);
1386 assert_eq!(&arr[0], "a");
1387 assert_eq!(&arr[1], "b");
1388 assert_eq!(&arr[2], "c");
1389 }
1390
1391 #[test]
1392 fn test_slice_from_compact_vec() {
1393 let mut compact_vec = CompactVec::new();
1394 compact_vec.push(String::from("x"));
1395 compact_vec.push(String::from("y"));
1396 compact_vec.push(String::from("z"));
1397
1398 let arr: CompactArc<[String]> = CompactArc::from_compact_vec(compact_vec);
1399 assert_eq!(arr.len(), 3);
1400 assert_eq!(&arr[0], "x");
1401 assert_eq!(&arr[1], "y");
1402 assert_eq!(&arr[2], "z");
1403 }
1404
1405 #[test]
1406 fn test_from_compact_vec_moves_elements() {
1407 use std::sync::atomic::{AtomicUsize, Ordering};
1408
1409 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
1410 static CLONE_COUNT: AtomicUsize = AtomicUsize::new(0);
1411
1412 #[derive(Debug, PartialEq)]
1413 struct MoveTracker(u32);
1414
1415 impl Clone for MoveTracker {
1416 fn clone(&self) -> Self {
1417 CLONE_COUNT.fetch_add(1, Ordering::SeqCst);
1418 MoveTracker(self.0)
1419 }
1420 }
1421
1422 impl Drop for MoveTracker {
1423 fn drop(&mut self) {
1424 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
1425 }
1426 }
1427
1428 DROP_COUNT.store(0, Ordering::SeqCst);
1429 CLONE_COUNT.store(0, Ordering::SeqCst);
1430
1431 {
1432 let mut compact_vec = CompactVec::new();
1433 compact_vec.push(MoveTracker(1));
1434 compact_vec.push(MoveTracker(2));
1435 compact_vec.push(MoveTracker(3));
1436
1437 let arr: CompactArc<[MoveTracker]> = CompactArc::from_compact_vec(compact_vec);
1438
1439 assert_eq!(arr[0].0, 1);
1441 assert_eq!(arr[1].0, 2);
1442 assert_eq!(arr[2].0, 3);
1443
1444 assert_eq!(
1446 CLONE_COUNT.load(Ordering::SeqCst),
1447 0,
1448 "from_compact_vec should move, not clone"
1449 );
1450 }
1451
1452 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 3);
1454 }
1455
1456 #[test]
1457 fn test_slice_drop_elements() {
1458 use std::sync::atomic::{AtomicUsize, Ordering};
1459
1460 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
1461
1462 #[derive(Clone)]
1463 struct DropCounter;
1464 impl Drop for DropCounter {
1465 fn drop(&mut self) {
1466 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
1467 }
1468 }
1469
1470 DROP_COUNT.store(0, Ordering::SeqCst);
1471
1472 {
1473 let arr: CompactArc<[DropCounter]> =
1474 CompactArc::from_slice(&[DropCounter, DropCounter, DropCounter]);
1475 let _arr2 = arr.clone();
1476 }
1477
1478 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 6);
1480 }
1481
1482 #[test]
1483 fn test_from_slice_panic_safety() {
1484 use std::sync::atomic::{AtomicUsize, Ordering};
1485
1486 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
1487 static CLONE_COUNT: AtomicUsize = AtomicUsize::new(0);
1488
1489 #[derive(Debug)]
1490 struct PanicOnThird(u32);
1491
1492 impl Clone for PanicOnThird {
1493 fn clone(&self) -> Self {
1494 let count = CLONE_COUNT.fetch_add(1, Ordering::SeqCst);
1495 if count == 2 {
1496 panic!("Panic on third clone!");
1497 }
1498 PanicOnThird(self.0)
1499 }
1500 }
1501
1502 impl Drop for PanicOnThird {
1503 fn drop(&mut self) {
1504 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
1505 }
1506 }
1507
1508 DROP_COUNT.store(0, Ordering::SeqCst);
1509 CLONE_COUNT.store(0, Ordering::SeqCst);
1510
1511 let slice = &[
1512 PanicOnThird(1),
1513 PanicOnThird(2),
1514 PanicOnThird(3),
1515 PanicOnThird(4),
1516 ];
1517
1518 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1519 let _: CompactArc<[PanicOnThird]> = CompactArc::from_slice(slice);
1520 }));
1521
1522 assert!(result.is_err(), "Should have panicked");
1523
1524 let drops_from_cleanup = DROP_COUNT.load(Ordering::SeqCst);
1527 assert_eq!(
1528 drops_from_cleanup, 2,
1529 "Should have dropped 2 successfully cloned elements"
1530 );
1531 }
1532
1533 #[test]
1534 fn test_from_vec_moves_elements() {
1535 use std::sync::atomic::{AtomicUsize, Ordering};
1536
1537 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
1538 static CLONE_COUNT: AtomicUsize = AtomicUsize::new(0);
1539
1540 #[derive(Debug, PartialEq)]
1541 struct MoveTracker(u32);
1542
1543 impl Clone for MoveTracker {
1544 fn clone(&self) -> Self {
1545 CLONE_COUNT.fetch_add(1, Ordering::SeqCst);
1546 MoveTracker(self.0)
1547 }
1548 }
1549
1550 impl Drop for MoveTracker {
1551 fn drop(&mut self) {
1552 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
1553 }
1554 }
1555
1556 DROP_COUNT.store(0, Ordering::SeqCst);
1557 CLONE_COUNT.store(0, Ordering::SeqCst);
1558
1559 {
1560 let vec = vec![MoveTracker(1), MoveTracker(2), MoveTracker(3)];
1561 let arr: CompactArc<[MoveTracker]> = CompactArc::from_vec(vec);
1562
1563 assert_eq!(arr[0].0, 1);
1565 assert_eq!(arr[1].0, 2);
1566 assert_eq!(arr[2].0, 3);
1567
1568 assert_eq!(
1570 CLONE_COUNT.load(Ordering::SeqCst),
1571 0,
1572 "from_vec should move, not clone"
1573 );
1574 }
1575
1576 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 3);
1578 }
1579
1580 #[test]
1581 fn test_dst_send_sync() {
1582 fn assert_send<T: Send>() {}
1583 fn assert_sync<T: Sync>() {}
1584
1585 assert_send::<CompactArc<str>>();
1586 assert_sync::<CompactArc<str>>();
1587 assert_send::<CompactArc<[i32]>>();
1588 assert_sync::<CompactArc<[i32]>>();
1589 }
1590
1591 #[test]
1592 fn test_str_thread_safety() {
1593 use std::thread;
1594
1595 let s: CompactArc<str> = CompactArc::from_str_slice("shared string");
1596 let mut handles = vec![];
1597
1598 for _ in 0..10 {
1599 let s_clone = s.clone();
1600 handles.push(thread::spawn(move || {
1601 for _ in 0..1000 {
1602 let _ = s_clone.len();
1603 let _another = s_clone.clone();
1604 }
1605 }));
1606 }
1607
1608 for handle in handles {
1609 handle.join().unwrap();
1610 }
1611
1612 drop(s);
1613 }
1614}