1use core::cmp::Ordering;
2use core::ffi::c_void;
3use core::fmt;
4use core::hash::{Hash, Hasher};
5use core::iter::{ExactSizeIterator, Iterator};
6use core::marker::PhantomData;
7use core::mem::ManuallyDrop;
8use core::ops::Deref;
9use core::panic::{RefUnwindSafe, UnwindSafe};
10use core::ptr;
11
12use super::{Arc, ArcInner, HeaderSlice, HeaderSliceWithLengthProtected, HeaderWithLength};
13use crate::header::HeaderSliceWithLengthUnchecked;
14use crate::AllocError;
15
16#[repr(transparent)]
32pub struct ThinArc<H, T> {
33 ptr: ptr::NonNull<ArcInner<HeaderSlice<HeaderWithLength<H>, [T; 0]>>>,
46 phantom: PhantomData<(H, T)>,
47}
48
49unsafe impl<H: Sync + Send, T: Sync + Send> Send for ThinArc<H, T> {}
50unsafe impl<H: Sync + Send, T: Sync + Send> Sync for ThinArc<H, T> {}
51
52impl<H: RefUnwindSafe, T: RefUnwindSafe> UnwindSafe for ThinArc<H, T> {}
53
54#[inline]
58fn thin_to_thick<H, T>(arc: &ThinArc<H, T>) -> *mut ArcInner<HeaderSliceWithLengthProtected<H, T>> {
59 let thin = arc.ptr.as_ptr();
60 let len = unsafe { (*thin).data.header.length };
61 let fake_slice = ptr::slice_from_raw_parts_mut(thin as *mut T, len);
62
63 fake_slice as *mut ArcInner<HeaderSliceWithLengthProtected<H, T>>
64}
65
66impl<H, T> ThinArc<H, T> {
67 #[inline]
70 pub fn with_arc<F, U>(&self, f: F) -> U
71 where
72 F: FnOnce(&Arc<HeaderSliceWithLengthUnchecked<H, T>>) -> U,
73 {
74 let transient = ManuallyDrop::new(Arc::from_protected(unsafe {
76 Arc::from_raw_inner(thin_to_thick(self))
77 }));
78
79 f(&transient)
82 }
83
84 #[inline]
87 fn with_protected_arc<F, U>(&self, f: F) -> U
88 where
89 F: FnOnce(&Arc<HeaderSliceWithLengthProtected<H, T>>) -> U,
90 {
91 let transient = ManuallyDrop::new(unsafe { Arc::from_raw_inner(thin_to_thick(self)) });
93
94 f(&transient)
97 }
98
99 #[inline]
102 pub fn with_arc_mut<F, U>(&mut self, f: F) -> U
103 where
104 F: FnOnce(&mut Arc<HeaderSliceWithLengthProtected<H, T>>) -> U,
105 {
106 struct DropGuard<'a, H, T> {
109 transient: ManuallyDrop<Arc<HeaderSliceWithLengthProtected<H, T>>>,
110 this: &'a mut ThinArc<H, T>,
111 }
112
113 impl<'a, H, T> Drop for DropGuard<'a, H, T> {
114 fn drop(&mut self) {
115 debug_assert_eq!(
121 self.transient.length(),
122 self.transient.slice().len(),
123 "Length needs to be correct for ThinArc to work"
124 );
125 self.this.ptr = self.transient.p.cast();
127 }
128 }
129
130 let transient = ManuallyDrop::new(unsafe { Arc::from_raw_inner(thin_to_thick(self)) });
132
133 let mut guard = DropGuard {
134 transient,
135 this: self,
136 };
137
138 let ret = f(&mut guard.transient);
141
142 debug_assert_eq!(
144 guard.transient.length(),
145 guard.transient.slice().len(),
146 "Length needs to be correct for ThinArc to work"
147 );
148
149 ret
150 }
151
152 pub fn from_header_and_iter<I>(header: H, items: I) -> Self
155 where
156 I: Iterator<Item = T> + ExactSizeIterator,
157 {
158 let header = HeaderWithLength::new(header, items.len());
159 Arc::into_thin(Arc::from_header_and_iter(header, items))
160 }
161
162 pub fn try_from_header_and_iter<I>(header: H, items: I) -> Result<Self, AllocError>
166 where
167 I: Iterator<Item = T> + ExactSizeIterator,
168 {
169 let header = HeaderWithLength::new(header, items.len());
170 Ok(Arc::into_thin(Arc::try_from_header_and_iter(
171 header, items,
172 )?))
173 }
174
175 pub fn from_header_and_slice(header: H, items: &[T]) -> Self
178 where
179 T: Copy,
180 {
181 let header = HeaderWithLength::new(header, items.len());
182 Arc::into_thin(Arc::from_header_and_slice(header, items))
183 }
184
185 pub fn try_from_header_and_slice(header: H, items: &[T]) -> Result<Self, AllocError>
189 where
190 T: Copy,
191 {
192 let header = HeaderWithLength::new(header, items.len());
193 Ok(Arc::into_thin(Arc::try_from_header_and_slice(
194 header, items,
195 )?))
196 }
197
198 #[inline]
201 pub fn ptr(&self) -> *const c_void {
202 self.ptr.cast().as_ptr()
203 }
204
205 #[inline]
208 pub fn heap_ptr(&self) -> *const c_void {
209 self.ptr()
210 }
211
212 #[inline]
224 pub unsafe fn from_raw(ptr: *const c_void) -> Self {
225 Self {
226 ptr: ptr::NonNull::new_unchecked(ptr as *mut c_void).cast(),
227 phantom: PhantomData,
228 }
229 }
230
231 #[inline]
233 pub fn into_raw(self) -> *const c_void {
234 let this = ManuallyDrop::new(self);
235 this.ptr()
236 }
237
238 #[inline]
242 pub fn as_ptr(&self) -> *const c_void {
243 self.ptr()
244 }
245
246 #[inline]
255 pub fn strong_count(this: &Self) -> usize {
256 Self::with_arc(this, Arc::strong_count)
257 }
258}
259
260impl<H, T> Deref for ThinArc<H, T> {
261 type Target = HeaderSliceWithLengthUnchecked<H, T>;
262
263 #[inline]
264 fn deref(&self) -> &Self::Target {
265 unsafe { (*thin_to_thick(self)).data.inner() }
266 }
267}
268
269impl<H, T> Clone for ThinArc<H, T> {
270 #[inline]
271 fn clone(&self) -> Self {
272 ThinArc::with_protected_arc(self, |a| Arc::protected_into_thin(a.clone()))
273 }
274}
275
276impl<H, T> Drop for ThinArc<H, T> {
277 #[inline]
278 fn drop(&mut self) {
279 let _ = Arc::protected_from_thin(ThinArc {
280 ptr: self.ptr,
281 phantom: PhantomData,
282 });
283 }
284}
285
286impl<H, T> Arc<HeaderSliceWithLengthUnchecked<H, T>> {
287 #[inline]
293 unsafe fn into_thin_unchecked(a: Self) -> ThinArc<H, T> {
294 let this_protected: Arc<HeaderSliceWithLengthProtected<H, T>> =
296 unsafe { Arc::from_unprotected_unchecked(a) };
297
298 Arc::protected_into_thin(this_protected)
299 }
300
301 #[inline]
304 pub fn into_thin(a: Self) -> ThinArc<H, T> {
305 assert_eq!(
306 a.header.length,
307 a.slice.len(),
308 "Length needs to be correct for ThinArc to work"
309 );
310 unsafe { Self::into_thin_unchecked(a) }
312 }
313
314 #[inline]
317 pub fn from_thin(a: ThinArc<H, T>) -> Self {
318 Self::from_protected(Arc::<HeaderSliceWithLengthProtected<H, T>>::protected_from_thin(a))
319 }
320
321 #[inline]
324 fn from_protected(a: Arc<HeaderSliceWithLengthProtected<H, T>>) -> Self {
325 unsafe { Arc::from_raw_inner(Arc::into_raw_inner(a) as _) }
329 }
330}
331
332impl<H, T> Arc<HeaderSliceWithLengthProtected<H, T>> {
333 #[inline]
336 pub fn protected_into_thin(a: Self) -> ThinArc<H, T> {
337 debug_assert_eq!(
338 a.length(),
339 a.slice().len(),
340 "Length needs to be correct for ThinArc to work"
341 );
342
343 let fat_ptr: *mut ArcInner<HeaderSliceWithLengthProtected<H, T>> = Arc::into_raw_inner(a);
344 let thin_ptr: *mut ArcInner<HeaderSlice<HeaderWithLength<H>, [T; 0]>> = fat_ptr.cast();
346 ThinArc {
347 ptr: unsafe { ptr::NonNull::new_unchecked(thin_ptr) },
348 phantom: PhantomData,
349 }
350 }
351
352 #[inline]
355 pub fn protected_from_thin(a: ThinArc<H, T>) -> Self {
356 let a = ManuallyDrop::new(a);
357 let ptr = thin_to_thick(&a);
358 unsafe { Arc::from_raw_inner(ptr) }
359 }
360
361 #[inline]
366 unsafe fn from_unprotected_unchecked(a: Arc<HeaderSliceWithLengthUnchecked<H, T>>) -> Self {
367 unsafe { Arc::from_raw_inner(Arc::into_raw_inner(a) as _) }
372 }
373}
374
375impl<H: PartialEq, T: PartialEq> PartialEq for ThinArc<H, T> {
376 #[inline]
377 fn eq(&self, other: &ThinArc<H, T>) -> bool {
378 ThinArc::with_arc(self, |a| ThinArc::with_arc(other, |b| *a == *b))
379 }
380}
381
382impl<H: Eq, T: Eq> Eq for ThinArc<H, T> {}
383
384impl<H: PartialOrd, T: PartialOrd> PartialOrd for ThinArc<H, T> {
385 #[inline]
386 fn partial_cmp(&self, other: &ThinArc<H, T>) -> Option<Ordering> {
387 ThinArc::with_arc(self, |a| ThinArc::with_arc(other, |b| a.partial_cmp(b)))
388 }
389}
390
391impl<H: Ord, T: Ord> Ord for ThinArc<H, T> {
392 #[inline]
393 fn cmp(&self, other: &ThinArc<H, T>) -> Ordering {
394 ThinArc::with_arc(self, |a| ThinArc::with_arc(other, |b| a.cmp(b)))
395 }
396}
397
398impl<H: Hash, T: Hash> Hash for ThinArc<H, T> {
399 fn hash<HSR: Hasher>(&self, state: &mut HSR) {
400 ThinArc::with_arc(self, |a| a.hash(state))
401 }
402}
403
404impl<H: fmt::Debug, T: fmt::Debug> fmt::Debug for ThinArc<H, T> {
405 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
406 fmt::Debug::fmt(&**self, f)
407 }
408}
409
410impl<H, T> fmt::Pointer for ThinArc<H, T> {
411 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
412 fmt::Pointer::fmt(&self.ptr(), f)
413 }
414}
415
416#[cfg(test)]
417mod tests {
418 use crate::{Arc, HeaderWithLength, ThinArc};
419 use alloc::vec;
420 use core::clone::Clone;
421 use core::ops::Drop;
422 use core::sync::atomic;
423 use core::sync::atomic::Ordering::{Acquire, SeqCst};
424
425 #[derive(PartialEq)]
426 struct Canary(*mut atomic::AtomicUsize);
427
428 impl Drop for Canary {
429 fn drop(&mut self) {
430 unsafe {
431 (*self.0).fetch_add(1, SeqCst);
432 }
433 }
434 }
435
436 #[test]
437 fn empty_thin() {
438 let header = HeaderWithLength::new(100u32, 0);
439 let x = Arc::from_header_and_iter(header, core::iter::empty::<i32>());
440 let y = Arc::into_thin(x.clone());
441 assert_eq!(y.header.header, 100);
442 assert!(y.slice.is_empty());
443 assert_eq!(x.header.header, 100);
444 assert!(x.slice.is_empty());
445 }
446
447 #[test]
448 fn try_from_header_and_iter_thin() {
449 let a = ThinArc::try_from_header_and_iter(42u32, vec![1u16, 2, 3].into_iter()).unwrap();
450 assert_eq!(a.header.header, 42);
451 assert_eq!(&a.slice, [1, 2, 3]);
452 }
453
454 #[test]
455 fn try_from_header_and_slice_thin() {
456 let a = ThinArc::try_from_header_and_slice(42u32, &[1u16, 2, 3]).unwrap();
457 assert_eq!(a.header.header, 42);
458 assert_eq!(&a.slice, [1, 2, 3]);
459 }
460
461 #[test]
462 fn thin_assert_padding() {
463 #[derive(Clone, Default)]
464 #[repr(C)]
465 struct Padded {
466 i: u16,
467 }
468
469 let header = HeaderWithLength::new(0i32, 2);
471 let items = vec![Padded { i: 0xdead }, Padded { i: 0xbeef }];
472 let a = ThinArc::from_header_and_iter(header, items.into_iter());
473 assert_eq!(a.slice.len(), 2);
474 assert_eq!(a.slice[0].i, 0xdead);
475 assert_eq!(a.slice[1].i, 0xbeef);
476 }
477
478 #[test]
479 #[allow(clippy::redundant_clone, clippy::eq_op)]
480 fn slices_and_thin() {
481 let mut canary = atomic::AtomicUsize::new(0);
482 let c = Canary(&mut canary as *mut atomic::AtomicUsize);
483 let v = vec![5, 6];
484 let header = HeaderWithLength::new(c, v.len());
485 {
486 let x = Arc::into_thin(Arc::from_header_and_slice(header, &v));
487 let y = ThinArc::with_arc(&x, |q| q.clone());
488 let _ = y.clone();
489 let _ = x == x;
490 Arc::from_thin(x.clone());
491 }
492 assert_eq!(canary.load(Acquire), 1);
493 }
494
495 #[test]
496 #[allow(clippy::redundant_clone, clippy::eq_op)]
497 fn iter_and_thin() {
498 let mut canary = atomic::AtomicUsize::new(0);
499 let c = Canary(&mut canary as *mut atomic::AtomicUsize);
500 let v = vec![5, 6];
501 let header = HeaderWithLength::new(c, v.len());
502 {
503 let x = Arc::into_thin(Arc::from_header_and_iter(header, v.into_iter()));
504 let y = ThinArc::with_arc(&x, |q| q.clone());
505 let _ = y.clone();
506 let _ = x == x;
507 Arc::from_thin(x.clone());
508 }
509 assert_eq!(canary.load(Acquire), 1);
510 }
511
512 #[test]
513 fn into_raw_and_from_raw() {
514 let mut canary = atomic::AtomicUsize::new(0);
515 let c = Canary(&mut canary as *mut atomic::AtomicUsize);
516 let v = vec![5, 6];
517 let header = HeaderWithLength::new(c, v.len());
518 {
519 type ThinArcCanary = ThinArc<Canary, u32>;
520 let x: ThinArcCanary = Arc::into_thin(Arc::from_header_and_iter(header, v.into_iter()));
521 let ptr = x.as_ptr();
522
523 assert_eq!(x.into_raw(), ptr);
524
525 let _x = unsafe { ThinArcCanary::from_raw(ptr) };
526 }
527 assert_eq!(canary.load(Acquire), 1);
528 }
529
530 #[test]
531 fn thin_eq_and_cmp() {
532 [
533 [("*", &b"AB"[..]), ("*", &b"ab"[..])],
534 [("*", &b"AB"[..]), ("*", &b"a"[..])],
535 [("*", &b"A"[..]), ("*", &b"ab"[..])],
536 [("A", &b"*"[..]), ("a", &b"*"[..])],
537 [("a", &b"*"[..]), ("A", &b"*"[..])],
538 [("AB", &b"*"[..]), ("a", &b"*"[..])],
539 [("A", &b"*"[..]), ("ab", &b"*"[..])],
540 ]
541 .iter()
542 .for_each(|[lt @ (lh, ls), rt @ (rh, rs)]| {
543 let l = ThinArc::from_header_and_slice(lh, ls);
544 let r = ThinArc::from_header_and_slice(rh, rs);
545
546 assert_eq!(l, l);
547 assert_eq!(r, r);
548
549 assert_ne!(l, r);
550 assert_ne!(r, l);
551
552 assert_eq!(l <= l, lt <= lt, "{lt:?} <= {lt:?}");
553 assert_eq!(l >= l, lt >= lt, "{lt:?} >= {lt:?}");
554
555 assert_eq!(l < l, lt < lt, "{lt:?} < {lt:?}");
556 assert_eq!(l > l, lt > lt, "{lt:?} > {lt:?}");
557
558 assert_eq!(r <= r, rt <= rt, "{rt:?} <= {rt:?}");
559 assert_eq!(r >= r, rt >= rt, "{rt:?} >= {rt:?}");
560
561 assert_eq!(r < r, rt < rt, "{rt:?} < {rt:?}");
562 assert_eq!(r > r, rt > rt, "{rt:?} > {rt:?}");
563
564 assert_eq!(l < r, lt < rt, "{lt:?} < {rt:?}");
565 assert_eq!(r > l, rt > lt, "{rt:?} > {lt:?}");
566 })
567 }
568
569 #[test]
570 fn thin_eq_and_partial_cmp() {
571 [
572 [(0.0, &[0.0, 0.0][..]), (1.0, &[0.0, 0.0][..])],
573 [(1.0, &[0.0, 0.0][..]), (0.0, &[0.0, 0.0][..])],
574 [(0.0, &[0.0][..]), (0.0, &[0.0, 0.0][..])],
575 [(0.0, &[0.0, 0.0][..]), (0.0, &[0.0][..])],
576 [(0.0, &[1.0, 2.0][..]), (0.0, &[10.0, 20.0][..])],
577 ]
578 .iter()
579 .for_each(|[lt @ (lh, ls), rt @ (rh, rs)]| {
580 let l = ThinArc::from_header_and_slice(lh, ls);
581 let r = ThinArc::from_header_and_slice(rh, rs);
582
583 assert_eq!(l, l);
584 assert_eq!(r, r);
585
586 assert_ne!(l, r);
587 assert_ne!(r, l);
588
589 assert_eq!(l <= l, lt <= lt, "{lt:?} <= {lt:?}");
590 assert_eq!(l >= l, lt >= lt, "{lt:?} >= {lt:?}");
591
592 assert_eq!(l < l, lt < lt, "{lt:?} < {lt:?}");
593 assert_eq!(l > l, lt > lt, "{lt:?} > {lt:?}");
594
595 assert_eq!(r <= r, rt <= rt, "{rt:?} <= {rt:?}");
596 assert_eq!(r >= r, rt >= rt, "{rt:?} >= {rt:?}");
597
598 assert_eq!(r < r, rt < rt, "{rt:?} < {rt:?}");
599 assert_eq!(r > r, rt > rt, "{rt:?} > {rt:?}");
600
601 assert_eq!(l < r, lt < rt, "{lt:?} < {rt:?}");
602 assert_eq!(r > l, rt > lt, "{rt:?} > {lt:?}");
603 })
604 }
605
606 #[test]
607 fn with_arc_mut() {
608 let mut arc: ThinArc<u8, u16> = ThinArc::from_header_and_slice(1u8, &[1, 2, 3]);
609 arc.with_arc_mut(|arc| Arc::get_mut(arc).unwrap().slice_mut().fill(2));
610 arc.with_arc_mut(|arc| assert!(Arc::get_unique(arc).is_some()));
611 arc.with_arc(|arc| assert!(Arc::is_unique(arc)));
612 let arcs = [
615 arc.clone(),
616 arc.clone(),
617 arc.clone(),
618 arc.clone(),
619 arc.clone(),
620 ];
621 arc.with_arc(|arc| assert_eq!(6, Arc::count(arc)));
622
623 assert_eq!(arc.header.header, 1);
625 assert_eq!(&arc.slice, [2, 2, 2]);
626
627 drop(arcs);
630 arc.with_arc_mut(|arc| assert!(Arc::get_unique(arc).is_some()));
631 arc.with_arc(|arc| assert!(Arc::is_unique(arc)));
632 assert_eq!(arc.header.header, 1);
633 assert_eq!(&arc.slice, [2, 2, 2]);
634 }
635
636 #[allow(dead_code)]
637 const fn is_partial_ord<T: ?Sized + PartialOrd>() {}
638
639 #[allow(dead_code)]
640 const fn is_ord<T: ?Sized + Ord>() {}
641
642 const _: () = is_partial_ord::<ThinArc<f64, f64>>();
644 const _: () = is_partial_ord::<ThinArc<f64, u64>>();
645 const _: () = is_partial_ord::<ThinArc<u64, f64>>();
646 const _: () = is_ord::<ThinArc<u64, u64>>();
647}