onsen/
trefcounted.rs

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/// The pool type backing the `TRc`.
15#[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/// For each type that shall be allocated with `TRcs` there must be an associated global
24/// memory pool. This is defined with this macro.
25///
26/// ```rust,ignore
27/// use onsen::*;
28///
29/// // ZST tag
30/// struct MyTag;
31///
32/// // define a pool holding u8 values
33/// define_trc_pool!(MyTag: u8);
34///
35/// /// allocated a trc from the u8 pool tagged by 'MyTag'
36/// let trc = TRc::new(123u8, MyTag);
37/// ```
38#[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
45/// A reference counted smart pointer for Pool allocated objects. This wraps Slots in a safe
46/// way. A `TRc` need a Pool holding `RcInner<T>`, not `T`.
47pub 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    /// Associated function that returns the number of strong counters of this `TRc`.
62    #[must_use]
63    pub fn strong_count(this: &Self) -> usize {
64        this.slot.get().get_strong()
65    }
66
67    /// Associated function that returns the number of weak counters of this `TRc`.
68    #[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    /// Allocate a `TRc` from a Pool.
80    #[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    /// Allocate a `TRc` from a Pool with inferred or turbofish tag.
89    #[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    /// Creates a `TWeak` reference from a `TRc`.
98    #[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    /// Allocate a default initialized `TRc`
116    #[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                // no references exist, can be freed completely
153                unsafe {
154                    T::get_static().free_by_ref(&mut self.slot);
155                }
156            } else {
157                // only weak references exist, drop in place
158                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    // fn write_length_prefix(&mut self, len: usize) {
348    //     (**self).write_length_prefix(len)
349    // }
350    // fn write_str(&mut self, s: &str) {
351    //     (**self).write_str(s)
352    // }
353}
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
386/// `TWeak` references do not keep the object alive.
387pub 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    /// Associated function that returns the number of strong counters of this `TWeak`.
402    #[must_use]
403    pub fn strong_count(&self) -> usize {
404        self.slot.get().get_strong()
405    }
406
407    /// Associated function that returns the number of weak counters of this `TWeak`.
408    #[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    /// Tries to create a `TRc` from a `TWeak` reference. Fails when the strong count was zero.
420    #[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                // no references exist, can be freed completely
465                unsafe {
466                    T::get_static().free_by_ref(&mut self.slot);
467                }
468            } else {
469                // only weak references exist, drop in place
470                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}