1use std::{
2 fmt, mem, ops,
3 ptr::NonNull,
4 sync::atomic::{AtomicUsize, Ordering},
5};
6
7#[derive(Debug)]
9pub(super) struct LinearcInner<T: ?Sized> {
10 pub(super) ref_count: AtomicUsize,
11 pub(super) data: T,
12}
13
14pub struct Linearc<T: ?Sized> {
22 ptr: NonNull<LinearcInner<T>>,
23}
24
25unsafe impl<T: ?Sized> Send for Linearc<T> {}
26unsafe impl<T: ?Sized> Sync for Linearc<T> {}
27
28impl<T: ?Sized> Linearc<T> {
29 #[inline]
30 pub(super) fn from_inner(inner: Box<LinearcInner<T>>) -> Self {
31 Self {
32 ptr: unsafe { NonNull::new_unchecked(Box::into_raw(inner)) },
33 }
34 }
35
36 #[inline]
38 pub fn clone(arc: &Self) -> Self {
39 arc.clone()
40 }
41
42 fn into_box(arc: Self) -> Option<Box<LinearcInner<T>>> {
43 let count = unsafe { arc.ptr.as_ref() }
44 .ref_count
45 .fetch_sub(1, Ordering::AcqRel);
46 if count == 1 {
47 let inner = unsafe { Box::from_raw(arc.ptr.as_ptr()) };
48 mem::forget(arc);
49 Some(inner)
50 } else {
51 mem::forget(arc);
52 None
53 }
54 }
55
56 #[inline]
58 pub fn drop_last(arc: Self) -> bool {
59 Linearc::into_box(arc).is_some()
60 }
61}
62
63impl<T> Linearc<T> {
64 #[inline]
66 pub fn new(data: T) -> Self {
67 Self::from_inner(Box::new(LinearcInner {
68 ref_count: AtomicUsize::new(1),
69 data,
70 }))
71 }
72
73 pub fn into_inner(arc: Self) -> Option<T> {
75 Linearc::into_box(arc).map(|inner| inner.data)
76 }
77}
78
79impl<T: ?Sized> Clone for Linearc<T> {
80 fn clone(&self) -> Self {
81 unsafe { self.ptr.as_ref() }
82 .ref_count
83 .fetch_add(1, Ordering::Release);
84 Self { ptr: self.ptr }
85 }
86}
87
88impl<T: ?Sized> Drop for Linearc<T> {
89 fn drop(&mut self) {
90 let count = unsafe { self.ptr.as_ref() }
91 .ref_count
92 .fetch_sub(1, Ordering::AcqRel);
93 if count == 1 {
94 let _ = unsafe { Box::from_raw(self.ptr.as_ptr()) };
95 }
96 }
97}
98
99impl<T: ?Sized> ops::Deref for Linearc<T> {
100 type Target = T;
101
102 #[inline]
103 fn deref(&self) -> &T {
104 &unsafe { self.ptr.as_ref() }.data
105 }
106}
107
108impl<T: fmt::Debug> fmt::Debug for Linearc<T> {
109 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
110 unsafe { self.ptr.as_ref() }.fmt(formatter)
111 }
112}