1use std::{fmt::Debug, ops::Deref, sync::atomic::AtomicU32};
2
3use crate::TinyPtr;
4
5#[derive(Debug)]
6struct RefCounted<T> {
7 count: AtomicU32,
8 value: T,
9}
10
11#[derive(Debug)]
12pub struct TinyWeak<T>(TinyPtr<RefCounted<T>>);
25
26unsafe impl<T: Send + Sync> Send for TinyWeak<T> {}
27unsafe impl<T: Send + Sync> Sync for TinyWeak<T> {}
28
29impl<T> Clone for TinyWeak<T> {
30 fn clone(&self) -> Self {
31 Self(self.0)
32 }
33}
34
35crate::boxed::impl_traits!(TinyArc);
36
37impl<T> TinyWeak<T> {
38 pub fn upgrade(&self) -> TinyArc<T> {
55 let arc = TinyArc(self.0);
56 TinyArc::increase_count(&arc);
57 arc
58 }
59}
60
61pub struct TinyArc<T>(TinyPtr<RefCounted<T>>);
74
75unsafe impl<T: Send + Sync> Send for TinyArc<T> {}
76unsafe impl<T: Send + Sync> Sync for TinyArc<T> {}
77
78impl<T> TinyArc<T> {
79 pub fn new(value: T) -> Self {
87 Self(TinyPtr::new(RefCounted {
88 count: AtomicU32::new(1),
89 value,
90 }))
91 }
92 pub fn new_cyclic<F>(data_fn: F) -> Self where F: FnOnce(TinyWeak<T>) -> T {
104 let mut ptr = TinyPtr::new(RefCounted {
105 count: AtomicU32::new(0),
106 value: unsafe { std::mem::MaybeUninit::<T>::uninit().assume_init() },
107 });
108 let data = data_fn(TinyWeak(ptr));
109 unsafe {
110 let ptr = ptr.get_mut();
111 std::ptr::addr_of_mut!(ptr.value).write(data);
112 }
113 let this = Self(ptr);
114 Self::increase_count(&this);
115 this
116 }
117 pub fn as_ptr(this: &Self) -> *const T {
121 &this.get().value
122 }
123 pub fn ptr_eq(this: &Self, other: &Self) -> bool {
125 this.0.id() == other.0.id()
126 }
127 pub fn downgrade(this: &Self) -> TinyWeak<T> {
131 TinyWeak(this.0)
132 }
133
134 fn get(&self) -> &RefCounted<T> {
137 unsafe { &*self.0.get() }
138 }
139 fn increase_count(this: &Self) -> u32 {
140 this.get()
141 .count
142 .fetch_add(1, std::sync::atomic::Ordering::Relaxed)
143 }
144 fn decrease_count(this: &Self) -> u32 {
145 this.get()
146 .count
147 .fetch_sub(1, std::sync::atomic::Ordering::Relaxed)
148 }
149}
150
151impl<T: Debug> Debug for TinyArc<T> {
152 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 f.debug_struct("TinyArc")
154 .field("refcount", self.get())
155 .finish()
156 }
157}
158
159impl<T> Deref for TinyArc<T> {
160 type Target = T;
161 fn deref(&self) -> &Self::Target {
162 let refcounted = self.get();
163 if refcounted.count.load(std::sync::atomic::Ordering::Relaxed) == 0 {
164 panic!("Attempted to dereference a TinyArc before it was built")
165 }
166 &refcounted.value
167 }
168}
169
170impl<T> Clone for TinyArc<T> {
171 fn clone(&self) -> Self {
172 Self::increase_count(self);
173 Self(self.0)
174 }
175}
176
177impl<T> std::ops::Drop for TinyArc<T> {
178 fn drop(&mut self) {
179 let owners = Self::decrease_count(self);
180 if owners == 1 {
181 self.0.take();
183 }
184 }
185}
186
187#[cfg(test)]
188mod tests {
189
190 use std::sync::atomic::AtomicBool;
191
192 use super::*;
193
194 use crate::tests::{*, make_drop_indicator};
195
196 #[test]
197 fn multiple_thread_access() {
198 make_drop_indicator!(__ind, p2, 42);
199 let p2 = TinyArc::new(p2);
200 let p1 = p2.clone();
201 let t1 = std::thread::spawn(move || {
202 assert_eq!(*p1, 42);
203 });
204 let t2 = std::thread::spawn(move || {
205 assert_eq!(*p2, 42);
206 });
207 t1.join().unwrap();
208 t2.join().unwrap();
209 assert_dropped!(__ind);
210 }
211 #[test]
212 fn assert_optimization_test() {
213 assert_eq!(
214 std::mem::size_of::<Option<TinyArc<u8>>>(),
215 std::mem::size_of::<TinyArc<u8>>()
216 );
217 }
218
219 #[test]
220 fn single_arc_test() {
221 make_drop_indicator!(__ind, b, 42);
222 let b = TinyArc::new(b);
223 assert_eq!(*b, 42);
224 std::mem::drop(b);
225 assert_dropped!(__ind)
226 }
227
228 #[test]
229 #[cfg_attr(feature = "1byteid", ignore = "uses too much memory")]
230 fn multiple_arc_test() {
231 for i in 0..100 {
232 make_drop_indicator!(__ind, val, i);
233 {
234 let b = TinyArc::new(val);
235 assert_eq!(*b, i);
236 }
237 assert_dropped!(__ind)
238 }
239 }
240
241 #[test]
242 fn multiple_refs_test() {
243 make_drop_indicator!(__ind, v, 30);
244 let i = TinyArc::new(v);
245 for _x in 0..200 {
246 let j = i.clone();
247 assert_eq!(*j, 30);
248 }
249 std::mem::drop(i);
250 assert_dropped!(__ind)
251 }
252
253 #[test]
254 fn make_cyclic_test() {
255 #[derive(Debug)]
256 struct Narcissus {
257 _drop_indicator: DropIndicator<()>,
258 self_: TinyWeak<Narcissus>,
259 }
260
261 make_drop_indicator!(__ind, ind, ());
262 let narc = TinyArc::new_cyclic(|weak| {
263 Narcissus{self_: weak, _drop_indicator: ind}
264 });
265
266 assert!(TinyArc::ptr_eq(&narc, &narc.self_.upgrade()));
267 std::mem::drop(narc);
268 assert_dropped!(__ind);
269 }
270
271 #[test]
272 #[should_panic]
273 fn make_cyclic_panic_test() {
274 TinyArc::<()>::new_cyclic(|weak| {
275 weak.upgrade();
276 });
277 }
278}