1#![cfg(feature = "tbox")]
2use std::borrow::Borrow;
3use std::borrow::BorrowMut;
4use std::cmp::Ordering;
5use std::fmt;
6use std::hash::Hash;
7use std::hash::Hasher;
8use std::marker::PhantomData;
9use std::ops::Deref;
10use std::ops::DerefMut;
11
12use crate::*;
13
14#[cfg(feature = "st_tbox")]
16#[doc(hidden)]
17pub type TRcPool<T> = STPool<RcInner<T>>;
18
19#[cfg(not(feature = "st_tbox"))]
20#[doc(hidden)]
21pub type TRcPool<T> = TPool<RcInner<T>>;
22
23#[macro_export]
39macro_rules! define_trc_pool {
40 ($TAG:ty:$T:ty) => {
41 $crate::assoc_static!($TAG: $T, $crate::TRcPool<$T> = $crate::TRcPool::new());
42 };
43}
44
45pub struct TRc<T, TAG>
48where
49 T: AssocStatic<TRcPool<T>, TAG> + 'static,
50 TAG: 'static,
51{
52 slot: Slot<RcInner<T>, Mutable>,
53 tag: PhantomData<TAG>,
54}
55
56impl<T, TAG> TRc<T, TAG>
57where
58 T: AssocStatic<TRcPool<T>, TAG> + 'static,
59 TAG: 'static,
60{
61 #[must_use]
63 pub fn strong_count(this: &Self) -> usize {
64 this.slot.get().get_strong()
65 }
66
67 #[must_use]
69 pub fn weak_count(this: &Self) -> usize {
70 this.slot.get().get_weak()
71 }
72}
73
74impl<T, TAG> TRc<T, TAG>
75where
76 T: AssocStatic<TRcPool<T>, TAG> + 'static,
77 TAG: 'static,
78{
79 #[inline]
81 pub fn new(t: T, _tag: TAG) -> Self {
82 Self {
83 slot: T::get_static().alloc(RcInner::new(t)).for_mutation(),
84 tag: PhantomData,
85 }
86 }
87
88 #[inline]
90 pub fn new_notag(t: T) -> Self {
91 Self {
92 slot: T::get_static().alloc(RcInner::new(t)).for_mutation(),
93 tag: PhantomData,
94 }
95 }
96
97 #[must_use]
99 pub fn downgrade(this: &Self) -> TWeak<T, TAG> {
100 this.slot.get().inc_weak();
101 unsafe {
102 TWeak::<T, TAG> {
103 slot: this.slot.copy(),
104 tag: PhantomData,
105 }
106 }
107 }
108}
109
110impl<T, TAG> Default for TRc<T, TAG>
111where
112 T: AssocStatic<TRcPool<T>, TAG> + 'static + Default,
113 TAG: 'static,
114{
115 #[inline]
117 fn default() -> Self {
118 TRc::new_notag(T::default())
119 }
120}
121
122impl<T, TAG> Clone for TRc<T, TAG>
123where
124 T: AssocStatic<TRcPool<T>, TAG> + 'static,
125 TAG: 'static,
126{
127 #[must_use]
128 fn clone(&self) -> Self {
129 self.slot.get().inc_strong();
130 unsafe {
131 Self {
132 slot: self.slot.copy(),
133 tag: PhantomData,
134 }
135 }
136 }
137}
138
139impl<T, TAG> Drop for TRc<T, TAG>
140where
141 T: AssocStatic<TRcPool<T>, TAG> + 'static,
142 TAG: 'static,
143{
144 #[inline]
145 fn drop(&mut self) {
146 let mslot = self.slot.get_mut();
147
148 mslot.dec_strong();
149
150 if mslot.get_strong() == 0 {
151 if mslot.get_weak() == 0 {
152 unsafe {
154 T::get_static().free_by_ref(&mut self.slot);
155 }
156 } else {
157 unsafe {
159 mslot.data.assume_init_drop();
160 }
161 }
162 }
163 }
164}
165
166impl<T, TAG> Deref for TRc<T, TAG>
167where
168 T: AssocStatic<TRcPool<T>, TAG> + 'static,
169 TAG: 'static,
170{
171 type Target = T;
172
173 #[inline]
174 fn deref(&self) -> &<Self as Deref>::Target {
175 unsafe { self.slot.get().data.assume_init_ref() }
176 }
177}
178
179impl<T, TAG> DerefMut for TRc<T, TAG>
180where
181 T: AssocStatic<TRcPool<T>, TAG> + 'static,
182 TAG: 'static,
183{
184 #[inline]
185 fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
186 unsafe { self.slot.get_mut().data.assume_init_mut() }
187 }
188}
189
190impl<T, TAG> Borrow<T> for TRc<T, TAG>
191where
192 T: AssocStatic<TRcPool<T>, TAG> + 'static,
193 TAG: 'static,
194{
195 #[inline]
196 fn borrow(&self) -> &T {
197 unsafe { self.slot.get().data.assume_init_ref() }
198 }
199}
200
201impl<T, TAG> BorrowMut<T> for TRc<T, TAG>
202where
203 T: AssocStatic<TRcPool<T>, TAG> + 'static,
204 TAG: 'static,
205{
206 #[inline]
207 fn borrow_mut(&mut self) -> &mut T {
208 unsafe { self.slot.get_mut().data.assume_init_mut() }
209 }
210}
211
212impl<T, TAG> AsRef<T> for TRc<T, TAG>
213where
214 T: AssocStatic<TRcPool<T>, TAG> + 'static,
215 TAG: 'static,
216{
217 #[inline]
218 fn as_ref(&self) -> &T {
219 unsafe { self.slot.get().data.assume_init_ref() }
220 }
221}
222
223impl<T, TAG> AsMut<T> for TRc<T, TAG>
224where
225 T: AssocStatic<TRcPool<T>, TAG> + 'static,
226 TAG: 'static,
227{
228 #[inline]
229 fn as_mut(&mut self) -> &mut T {
230 unsafe { self.slot.get_mut().data.assume_init_mut() }
231 }
232}
233
234impl<T: PartialEq, TAG> PartialEq for TRc<T, TAG>
235where
236 T: AssocStatic<TRcPool<T>, TAG> + 'static,
237 TAG: 'static,
238{
239 #[inline]
240 fn eq(&self, other: &Self) -> bool {
241 PartialEq::eq(&**self, &**other)
242 }
243}
244
245impl<T: PartialOrd, TAG> PartialOrd for TRc<T, TAG>
246where
247 T: AssocStatic<TRcPool<T>, TAG> + 'static,
248 TAG: 'static,
249{
250 #[inline]
251 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
252 PartialOrd::partial_cmp(&**self, &**other)
253 }
254 #[inline]
255 fn lt(&self, other: &Self) -> bool {
256 PartialOrd::lt(&**self, &**other)
257 }
258 #[inline]
259 fn le(&self, other: &Self) -> bool {
260 PartialOrd::le(&**self, &**other)
261 }
262 #[inline]
263 fn ge(&self, other: &Self) -> bool {
264 PartialOrd::ge(&**self, &**other)
265 }
266 #[inline]
267 fn gt(&self, other: &Self) -> bool {
268 PartialOrd::gt(&**self, &**other)
269 }
270}
271
272impl<T: Ord, TAG> Ord for TRc<T, TAG>
273where
274 T: AssocStatic<TRcPool<T>, TAG> + 'static,
275 TAG: 'static,
276{
277 #[inline]
278 fn cmp(&self, other: &Self) -> Ordering {
279 Ord::cmp(&**self, &**other)
280 }
281}
282
283impl<T: Eq, TAG> Eq for TRc<T, TAG>
284where
285 T: AssocStatic<TRcPool<T>, TAG> + 'static,
286 TAG: 'static,
287{
288}
289
290impl<T: Hash, TAG> Hash for TRc<T, TAG>
291where
292 T: AssocStatic<TRcPool<T>, TAG> + 'static,
293 TAG: 'static,
294{
295 fn hash<H: Hasher>(&self, state: &mut H) {
296 (**self).hash(state);
297 }
298}
299
300impl<T: Hasher, TAG> Hasher for TRc<T, TAG>
301where
302 T: AssocStatic<TRcPool<T>, TAG> + 'static,
303 TAG: 'static,
304{
305 fn finish(&self) -> u64 {
306 (**self).finish()
307 }
308 fn write(&mut self, bytes: &[u8]) {
309 (**self).write(bytes);
310 }
311 fn write_u8(&mut self, i: u8) {
312 (**self).write_u8(i);
313 }
314 fn write_u16(&mut self, i: u16) {
315 (**self).write_u16(i);
316 }
317 fn write_u32(&mut self, i: u32) {
318 (**self).write_u32(i);
319 }
320 fn write_u64(&mut self, i: u64) {
321 (**self).write_u64(i);
322 }
323 fn write_u128(&mut self, i: u128) {
324 (**self).write_u128(i);
325 }
326 fn write_usize(&mut self, i: usize) {
327 (**self).write_usize(i);
328 }
329 fn write_i8(&mut self, i: i8) {
330 (**self).write_i8(i);
331 }
332 fn write_i16(&mut self, i: i16) {
333 (**self).write_i16(i);
334 }
335 fn write_i32(&mut self, i: i32) {
336 (**self).write_i32(i);
337 }
338 fn write_i64(&mut self, i: i64) {
339 (**self).write_i64(i);
340 }
341 fn write_i128(&mut self, i: i128) {
342 (**self).write_i128(i);
343 }
344 fn write_isize(&mut self, i: isize) {
345 (**self).write_isize(i);
346 }
347 }
354
355impl<T: fmt::Display, TAG> fmt::Display for TRc<T, TAG>
356where
357 T: AssocStatic<TRcPool<T>, TAG> + 'static,
358 TAG: 'static,
359{
360 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361 fmt::Display::fmt(&**self, f)
362 }
363}
364
365impl<T: fmt::Debug, TAG> fmt::Debug for TRc<T, TAG>
366where
367 T: AssocStatic<TRcPool<T>, TAG> + 'static,
368 TAG: 'static,
369{
370 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
371 fmt::Debug::fmt(&**self, f)
372 }
373}
374
375impl<T, TAG> fmt::Pointer for TRc<T, TAG>
376where
377 T: AssocStatic<TRcPool<T>, TAG> + 'static,
378 TAG: 'static,
379{
380 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
381 let ptr: *const T = &**self;
382 fmt::Pointer::fmt(&ptr, f)
383 }
384}
385
386pub struct TWeak<T, TAG>
388where
389 T: AssocStatic<TRcPool<T>, TAG> + 'static,
390 TAG: 'static,
391{
392 slot: Slot<RcInner<T>, Mutable>,
393 tag: PhantomData<TAG>,
394}
395
396impl<T, TAG> TWeak<T, TAG>
397where
398 T: AssocStatic<TRcPool<T>, TAG> + 'static,
399 TAG: 'static,
400{
401 #[must_use]
403 pub fn strong_count(&self) -> usize {
404 self.slot.get().get_strong()
405 }
406
407 #[must_use]
409 pub fn weak_count(&self) -> usize {
410 self.slot.get().get_weak()
411 }
412}
413
414impl<T, TAG> TWeak<T, TAG>
415where
416 T: AssocStatic<TRcPool<T>, TAG> + 'static,
417 TAG: 'static,
418{
419 #[must_use]
421 pub fn upgrade(&self) -> Option<TRc<T, TAG>> {
422 if self.strong_count() > 0 {
423 self.slot.get().inc_strong();
424 unsafe {
425 Some(TRc::<T, TAG> {
426 slot: self.slot.copy(),
427 tag: PhantomData,
428 })
429 }
430 } else {
431 None
432 }
433 }
434}
435
436impl<T, TAG> Clone for TWeak<T, TAG>
437where
438 T: AssocStatic<TRcPool<T>, TAG> + 'static,
439 TAG: 'static,
440{
441 fn clone(&self) -> Self {
442 self.slot.get().inc_weak();
443 unsafe {
444 Self {
445 slot: self.slot.copy(),
446 tag: PhantomData,
447 }
448 }
449 }
450}
451
452impl<T, TAG> Drop for TWeak<T, TAG>
453where
454 T: AssocStatic<TRcPool<T>, TAG> + 'static,
455 TAG: 'static,
456{
457 #[inline]
458 fn drop(&mut self) {
459 let mslot = self.slot.get_mut();
460 mslot.dec_weak();
461
462 if mslot.get_strong() == 0 {
463 if mslot.get_weak() == 0 {
464 unsafe {
466 T::get_static().free_by_ref(&mut self.slot);
467 }
468 } else {
469 unsafe {
471 mslot.data.assume_init_drop();
472 }
473 }
474 }
475 }
476}
477
478#[cfg(test)]
479mod tests {
480 use crate::*;
481 use serial_test::serial;
482
483 define_trc_pool!((): &'static str);
484 define_trc_pool!((): u64);
485
486 #[test]
487 #[ignore]
488 #[serial]
489 fn smoke() {
490 TBox::<&'static str, ()>::pool()
491 .acquire()
492 .expect("some other thread owns the pool");
493
494 let _mybox = TRc::new("TBoxed", ());
495
496 TBox::<&'static str, ()>::pool()
497 .release()
498 .expect("thread does not own the pool");
499 }
500}