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::{mdref, 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]
58const fn thin_to_thick<H, T>(
59 arc: &ThinArc<H, T>,
60) -> *mut ArcInner<HeaderSliceWithLengthProtected<H, T>> {
61 let thin = arc.ptr.as_ptr();
62 let len = unsafe { (*thin).data.header.length };
63 let fake_slice = ptr::slice_from_raw_parts_mut(thin as *mut T, len);
64
65 fake_slice as *mut ArcInner<HeaderSliceWithLengthProtected<H, T>>
66}
67
68impl<H, T> ThinArc<H, T> {
69 #[inline]
72 pub fn with_arc<F, U>(&self, f: F) -> U
73 where
74 F: FnOnce(&Arc<HeaderSliceWithLengthUnchecked<H, T>>) -> U,
75 {
76 let transient = ManuallyDrop::new(Arc::from_protected(unsafe {
78 Arc::from_raw_inner(thin_to_thick(self))
79 }));
80
81 f(&transient)
84 }
85
86 #[inline]
89 fn with_protected_arc<F, U>(&self, f: F) -> U
90 where
91 F: FnOnce(&Arc<HeaderSliceWithLengthProtected<H, T>>) -> U,
92 {
93 let transient = ManuallyDrop::new(unsafe { Arc::from_raw_inner(thin_to_thick(self)) });
95
96 f(&transient)
99 }
100
101 #[inline]
104 pub fn with_arc_mut<F, U>(&mut self, f: F) -> U
105 where
106 F: FnOnce(&mut Arc<HeaderSliceWithLengthProtected<H, T>>) -> U,
107 {
108 struct DropGuard<'a, H, T> {
111 transient: ManuallyDrop<Arc<HeaderSliceWithLengthProtected<H, T>>>,
112 this: &'a mut ThinArc<H, T>,
113 }
114
115 impl<'a, H, T> Drop for DropGuard<'a, H, T> {
116 fn drop(&mut self) {
117 debug_assert_eq!(
123 self.transient.length(),
124 self.transient.slice().len(),
125 "Length needs to be correct for ThinArc to work"
126 );
127 self.this.ptr = self.transient.p.cast();
129 }
130 }
131
132 let transient = ManuallyDrop::new(unsafe { Arc::from_raw_inner(thin_to_thick(self)) });
134
135 let mut guard = DropGuard {
136 transient,
137 this: self,
138 };
139
140 let ret = f(&mut guard.transient);
143
144 debug_assert_eq!(
146 guard.transient.length(),
147 guard.transient.slice().len(),
148 "Length needs to be correct for ThinArc to work"
149 );
150
151 ret
152 }
153
154 pub fn from_header_and_iter<I>(header: H, items: I) -> Self
157 where
158 I: Iterator<Item = T> + ExactSizeIterator,
159 {
160 let header = HeaderWithLength::new(header, items.len());
161 Arc::into_thin(Arc::from_header_and_iter(header, items))
162 }
163
164 pub fn try_from_header_and_iter<I>(header: H, items: I) -> Result<Self, AllocError>
168 where
169 I: Iterator<Item = T> + ExactSizeIterator,
170 {
171 let header = HeaderWithLength::new(header, items.len());
172 Ok(Arc::into_thin(Arc::try_from_header_and_iter(
173 header, items,
174 )?))
175 }
176
177 pub fn from_header_and_slice(header: H, items: &[T]) -> Self
180 where
181 T: Copy,
182 {
183 let header = HeaderWithLength::new(header, items.len());
184 Arc::into_thin(Arc::from_header_and_slice(header, items))
185 }
186
187 pub fn try_from_header_and_slice(header: H, items: &[T]) -> Result<Self, AllocError>
191 where
192 T: Copy,
193 {
194 let header = HeaderWithLength::new(header, items.len());
195 Ok(Arc::into_thin(Arc::try_from_header_and_slice(
196 header, items,
197 )?))
198 }
199
200 #[inline]
203 pub const fn ptr(&self) -> *const c_void {
204 self.ptr.cast().as_ptr()
205 }
206
207 #[inline]
210 pub const fn heap_ptr(&self) -> *const c_void {
211 self.ptr()
212 }
213
214 #[inline]
226 pub const unsafe fn from_raw(ptr: *const c_void) -> Self {
227 Self {
228 ptr: ptr::NonNull::new_unchecked(ptr as *mut c_void).cast(),
229 phantom: PhantomData,
230 }
231 }
232
233 #[inline]
235 pub const fn into_raw(self) -> *const c_void {
236 let this = ManuallyDrop::new(self);
237 mdref(&this).ptr()
238 }
239
240 #[inline]
244 pub const fn as_ptr(&self) -> *const c_void {
245 self.ptr()
246 }
247
248 #[inline]
257 pub fn strong_count(this: &Self) -> usize {
258 Self::with_arc(this, Arc::strong_count)
259 }
260}
261
262impl<H, T> Deref for ThinArc<H, T> {
263 type Target = HeaderSliceWithLengthUnchecked<H, T>;
264
265 #[inline]
266 fn deref(&self) -> &Self::Target {
267 unsafe { (*thin_to_thick(self)).data.inner() }
268 }
269}
270
271impl<H, T> Clone for ThinArc<H, T> {
272 #[inline]
273 fn clone(&self) -> Self {
274 ThinArc::with_protected_arc(self, |a| Arc::protected_into_thin(a.clone()))
275 }
276}
277
278impl<H, T> Drop for ThinArc<H, T> {
279 #[inline]
280 fn drop(&mut self) {
281 let _ = Arc::protected_from_thin(ThinArc {
282 ptr: self.ptr,
283 phantom: PhantomData,
284 });
285 }
286}
287
288impl<H, T> Arc<HeaderSliceWithLengthUnchecked<H, T>> {
289 #[inline]
295 unsafe fn into_thin_unchecked(a: Self) -> ThinArc<H, T> {
296 let this_protected: Arc<HeaderSliceWithLengthProtected<H, T>> =
298 unsafe { Arc::from_unprotected_unchecked(a) };
299
300 Arc::protected_into_thin(this_protected)
301 }
302
303 #[inline]
306 pub fn into_thin(a: Self) -> ThinArc<H, T> {
307 assert_eq!(
308 a.header.length,
309 a.slice.len(),
310 "Length needs to be correct for ThinArc to work"
311 );
312 unsafe { Self::into_thin_unchecked(a) }
314 }
315
316 #[inline]
319 pub const fn from_thin(a: ThinArc<H, T>) -> Self {
320 Self::from_protected(Arc::<HeaderSliceWithLengthProtected<H, T>>::protected_from_thin(a))
321 }
322
323 #[inline]
326 const fn from_protected(a: Arc<HeaderSliceWithLengthProtected<H, T>>) -> Self {
327 unsafe { Arc::from_raw_inner(Arc::into_raw_inner(a) as _) }
331 }
332}
333
334impl<H, T> Arc<HeaderSliceWithLengthProtected<H, T>> {
335 #[inline]
338 pub const fn protected_into_thin(a: Self) -> ThinArc<H, T> {
339 debug_assert!(
340 a.inner().data.length() == a.inner().data.slice().len(),
341 "Length needs to be correct for ThinArc to work"
342 );
343
344 let fat_ptr: *mut ArcInner<HeaderSliceWithLengthProtected<H, T>> = Arc::into_raw_inner(a);
345 let thin_ptr: *mut ArcInner<HeaderSlice<HeaderWithLength<H>, [T; 0]>> = fat_ptr.cast();
347 ThinArc {
348 ptr: unsafe { ptr::NonNull::new_unchecked(thin_ptr) },
349 phantom: PhantomData,
350 }
351 }
352
353 #[inline]
356 pub const fn protected_from_thin(a: ThinArc<H, T>) -> Self {
357 let a = ManuallyDrop::new(a);
358 let ptr = thin_to_thick(mdref(&a));
359 unsafe { Arc::from_raw_inner(ptr) }
360 }
361
362 #[inline]
367 const unsafe fn from_unprotected_unchecked(
368 a: Arc<HeaderSliceWithLengthUnchecked<H, T>>,
369 ) -> Self {
370 unsafe { Arc::from_raw_inner(Arc::into_raw_inner(a) as _) }
375 }
376}
377
378impl<H: PartialEq, T: PartialEq> PartialEq for ThinArc<H, T> {
379 #[inline]
380 fn eq(&self, other: &ThinArc<H, T>) -> bool {
381 ThinArc::with_arc(self, |a| ThinArc::with_arc(other, |b| *a == *b))
382 }
383}
384
385impl<H: Eq, T: Eq> Eq for ThinArc<H, T> {}
386
387impl<H: PartialOrd, T: PartialOrd> PartialOrd for ThinArc<H, T> {
388 #[inline]
389 fn partial_cmp(&self, other: &ThinArc<H, T>) -> Option<Ordering> {
390 ThinArc::with_arc(self, |a| ThinArc::with_arc(other, |b| a.partial_cmp(b)))
391 }
392}
393
394impl<H: Ord, T: Ord> Ord for ThinArc<H, T> {
395 #[inline]
396 fn cmp(&self, other: &ThinArc<H, T>) -> Ordering {
397 ThinArc::with_arc(self, |a| ThinArc::with_arc(other, |b| a.cmp(b)))
398 }
399}
400
401impl<H: Hash, T: Hash> Hash for ThinArc<H, T> {
402 fn hash<HSR: Hasher>(&self, state: &mut HSR) {
403 ThinArc::with_arc(self, |a| a.hash(state))
404 }
405}
406
407impl<H: fmt::Debug, T: fmt::Debug> fmt::Debug for ThinArc<H, T> {
408 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
409 fmt::Debug::fmt(&**self, f)
410 }
411}
412
413impl<H, T> fmt::Pointer for ThinArc<H, T> {
414 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
415 fmt::Pointer::fmt(&self.ptr(), f)
416 }
417}
418
419#[cfg(test)]
420mod tests {
421 use crate::{Arc, HeaderWithLength, ThinArc};
422 use alloc::vec;
423 use core::clone::Clone;
424 use core::ops::Drop;
425 use core::sync::atomic;
426 use core::sync::atomic::Ordering::{Acquire, SeqCst};
427
428 #[derive(PartialEq)]
429 struct Canary(*mut atomic::AtomicUsize);
430
431 impl Drop for Canary {
432 fn drop(&mut self) {
433 unsafe {
434 (*self.0).fetch_add(1, SeqCst);
435 }
436 }
437 }
438
439 #[test]
440 fn empty_thin() {
441 let header = HeaderWithLength::new(100u32, 0);
442 let x = Arc::from_header_and_iter(header, core::iter::empty::<i32>());
443 let y = Arc::into_thin(x.clone());
444 assert_eq!(y.header.header, 100);
445 assert!(y.slice.is_empty());
446 assert_eq!(x.header.header, 100);
447 assert!(x.slice.is_empty());
448 }
449
450 #[test]
451 fn try_from_header_and_iter_thin() {
452 let a = ThinArc::try_from_header_and_iter(42u32, vec![1u16, 2, 3].into_iter()).unwrap();
453 assert_eq!(a.header.header, 42);
454 assert_eq!(&a.slice, [1, 2, 3]);
455 }
456
457 #[test]
458 fn try_from_header_and_slice_thin() {
459 let a = ThinArc::try_from_header_and_slice(42u32, &[1u16, 2, 3]).unwrap();
460 assert_eq!(a.header.header, 42);
461 assert_eq!(&a.slice, [1, 2, 3]);
462 }
463
464 #[test]
465 fn thin_assert_padding() {
466 #[derive(Clone, Default)]
467 #[repr(C)]
468 struct Padded {
469 i: u16,
470 }
471
472 let header = HeaderWithLength::new(0i32, 2);
474 let items = vec![Padded { i: 0xdead }, Padded { i: 0xbeef }];
475 let a = ThinArc::from_header_and_iter(header, items.into_iter());
476 assert_eq!(a.slice.len(), 2);
477 assert_eq!(a.slice[0].i, 0xdead);
478 assert_eq!(a.slice[1].i, 0xbeef);
479 }
480
481 #[test]
482 #[allow(clippy::redundant_clone, clippy::eq_op)]
483 fn slices_and_thin() {
484 let mut canary = atomic::AtomicUsize::new(0);
485 let c = Canary(&mut canary as *mut atomic::AtomicUsize);
486 let v = vec![5, 6];
487 let header = HeaderWithLength::new(c, v.len());
488 {
489 let x = Arc::into_thin(Arc::from_header_and_slice(header, &v));
490 let y = ThinArc::with_arc(&x, |q| q.clone());
491 let _ = y.clone();
492 let _ = x == x;
493 Arc::from_thin(x.clone());
494 }
495 assert_eq!(canary.load(Acquire), 1);
496 }
497
498 #[test]
499 #[allow(clippy::redundant_clone, clippy::eq_op)]
500 fn iter_and_thin() {
501 let mut canary = atomic::AtomicUsize::new(0);
502 let c = Canary(&mut canary as *mut atomic::AtomicUsize);
503 let v = vec![5, 6];
504 let header = HeaderWithLength::new(c, v.len());
505 {
506 let x = Arc::into_thin(Arc::from_header_and_iter(header, v.into_iter()));
507 let y = ThinArc::with_arc(&x, |q| q.clone());
508 let _ = y.clone();
509 let _ = x == x;
510 Arc::from_thin(x.clone());
511 }
512 assert_eq!(canary.load(Acquire), 1);
513 }
514
515 #[test]
516 fn into_raw_and_from_raw() {
517 let mut canary = atomic::AtomicUsize::new(0);
518 let c = Canary(&mut canary as *mut atomic::AtomicUsize);
519 let v = vec![5, 6];
520 let header = HeaderWithLength::new(c, v.len());
521 {
522 type ThinArcCanary = ThinArc<Canary, u32>;
523 let x: ThinArcCanary = Arc::into_thin(Arc::from_header_and_iter(header, v.into_iter()));
524 let ptr = x.as_ptr();
525
526 assert_eq!(x.into_raw(), ptr);
527
528 let _x = unsafe { ThinArcCanary::from_raw(ptr) };
529 }
530 assert_eq!(canary.load(Acquire), 1);
531 }
532
533 #[test]
534 fn thin_eq_and_cmp() {
535 [
536 [("*", &b"AB"[..]), ("*", &b"ab"[..])],
537 [("*", &b"AB"[..]), ("*", &b"a"[..])],
538 [("*", &b"A"[..]), ("*", &b"ab"[..])],
539 [("A", &b"*"[..]), ("a", &b"*"[..])],
540 [("a", &b"*"[..]), ("A", &b"*"[..])],
541 [("AB", &b"*"[..]), ("a", &b"*"[..])],
542 [("A", &b"*"[..]), ("ab", &b"*"[..])],
543 ]
544 .iter()
545 .for_each(|[lt @ (lh, ls), rt @ (rh, rs)]| {
546 let l = ThinArc::from_header_and_slice(lh, ls);
547 let r = ThinArc::from_header_and_slice(rh, rs);
548
549 assert_eq!(l, l);
550 assert_eq!(r, r);
551
552 assert_ne!(l, r);
553 assert_ne!(r, l);
554
555 assert_eq!(l <= l, lt <= lt, "{lt:?} <= {lt:?}");
556 assert_eq!(l >= l, lt >= lt, "{lt:?} >= {lt:?}");
557
558 assert_eq!(l < l, lt < lt, "{lt:?} < {lt:?}");
559 assert_eq!(l > l, lt > lt, "{lt:?} > {lt:?}");
560
561 assert_eq!(r <= r, rt <= rt, "{rt:?} <= {rt:?}");
562 assert_eq!(r >= r, rt >= rt, "{rt:?} >= {rt:?}");
563
564 assert_eq!(r < r, rt < rt, "{rt:?} < {rt:?}");
565 assert_eq!(r > r, rt > rt, "{rt:?} > {rt:?}");
566
567 assert_eq!(l < r, lt < rt, "{lt:?} < {rt:?}");
568 assert_eq!(r > l, rt > lt, "{rt:?} > {lt:?}");
569 })
570 }
571
572 #[test]
573 fn thin_eq_and_partial_cmp() {
574 [
575 [(0.0, &[0.0, 0.0][..]), (1.0, &[0.0, 0.0][..])],
576 [(1.0, &[0.0, 0.0][..]), (0.0, &[0.0, 0.0][..])],
577 [(0.0, &[0.0][..]), (0.0, &[0.0, 0.0][..])],
578 [(0.0, &[0.0, 0.0][..]), (0.0, &[0.0][..])],
579 [(0.0, &[1.0, 2.0][..]), (0.0, &[10.0, 20.0][..])],
580 ]
581 .iter()
582 .for_each(|[lt @ (lh, ls), rt @ (rh, rs)]| {
583 let l = ThinArc::from_header_and_slice(lh, ls);
584 let r = ThinArc::from_header_and_slice(rh, rs);
585
586 assert_eq!(l, l);
587 assert_eq!(r, r);
588
589 assert_ne!(l, r);
590 assert_ne!(r, l);
591
592 assert_eq!(l <= l, lt <= lt, "{lt:?} <= {lt:?}");
593 assert_eq!(l >= l, lt >= lt, "{lt:?} >= {lt:?}");
594
595 assert_eq!(l < l, lt < lt, "{lt:?} < {lt:?}");
596 assert_eq!(l > l, lt > lt, "{lt:?} > {lt:?}");
597
598 assert_eq!(r <= r, rt <= rt, "{rt:?} <= {rt:?}");
599 assert_eq!(r >= r, rt >= rt, "{rt:?} >= {rt:?}");
600
601 assert_eq!(r < r, rt < rt, "{rt:?} < {rt:?}");
602 assert_eq!(r > r, rt > rt, "{rt:?} > {rt:?}");
603
604 assert_eq!(l < r, lt < rt, "{lt:?} < {rt:?}");
605 assert_eq!(r > l, rt > lt, "{rt:?} > {lt:?}");
606 })
607 }
608
609 #[test]
610 fn with_arc_mut() {
611 let mut arc: ThinArc<u8, u16> = ThinArc::from_header_and_slice(1u8, &[1, 2, 3]);
612 arc.with_arc_mut(|arc| Arc::get_mut(arc).unwrap().slice_mut().fill(2));
613 arc.with_arc_mut(|arc| assert!(Arc::get_unique(arc).is_some()));
614 arc.with_arc(|arc| assert!(Arc::is_unique(arc)));
615 let arcs = [
618 arc.clone(),
619 arc.clone(),
620 arc.clone(),
621 arc.clone(),
622 arc.clone(),
623 ];
624 arc.with_arc(|arc| assert_eq!(6, Arc::count(arc)));
625
626 assert_eq!(arc.header.header, 1);
628 assert_eq!(&arc.slice, [2, 2, 2]);
629
630 drop(arcs);
633 arc.with_arc_mut(|arc| assert!(Arc::get_unique(arc).is_some()));
634 arc.with_arc(|arc| assert!(Arc::is_unique(arc)));
635 assert_eq!(arc.header.header, 1);
636 assert_eq!(&arc.slice, [2, 2, 2]);
637 }
638
639 #[allow(dead_code)]
640 const fn is_partial_ord<T: ?Sized + PartialOrd>() {}
641
642 #[allow(dead_code)]
643 const fn is_ord<T: ?Sized + Ord>() {}
644
645 const _: () = is_partial_ord::<ThinArc<f64, f64>>();
647 const _: () = is_partial_ord::<ThinArc<f64, u64>>();
648 const _: () = is_partial_ord::<ThinArc<u64, f64>>();
649 const _: () = is_ord::<ThinArc<u64, u64>>();
650}