onsen/
tstrongcounted.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 `TSc`.
15#[cfg(feature = "st_tbox")]
16#[doc(hidden)]
17pub type TScPool<T> = STPool<ScInner<T>>;
18
19#[cfg(not(feature = "st_tbox"))]
20#[doc(hidden)]
21pub type TScPool<T> = TPool<ScInner<T>>;
22
23/// For each type that shall be allocated with `TScs` 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 = TSc::new(123u8, MyTag);
37/// ```
38#[macro_export]
39macro_rules! define_tsc_pool {
40    ($TAG:ty:$T:ty) => {
41        $crate::assoc_static!($TAG: $T, $crate::TScPool<$T> = $crate::TScPool::new());
42    };
43}
44
45/// A reference counted smart pointer for Pool allocated objects. This wraps Slots in a safe
46/// way. A `TSc` need a Pool holding `ScInner<T>`, not `T`.
47pub struct TSc<T, TAG>
48where
49    T: AssocStatic<TScPool<T>, TAG> + 'static,
50    TAG: 'static,
51{
52    slot: Slot<ScInner<T>, Mutable>,
53    tag: PhantomData<TAG>,
54}
55
56impl<T, TAG> TSc<T, TAG>
57where
58    T: AssocStatic<TScPool<T>, TAG> + 'static,
59    TAG: 'static,
60{
61    /// Associated function that returns the number of strong counters of this `TSc`.
62    #[must_use]
63    pub fn strong_count(this: &Self) -> usize {
64        this.slot.get().get_strong()
65    }
66}
67
68impl<T, TAG> TSc<T, TAG>
69where
70    T: AssocStatic<TScPool<T>, TAG> + 'static,
71    TAG: 'static,
72{
73    /// Allocate a `TSc` from a Pool.
74    #[inline]
75    pub fn new(t: T, _tag: TAG) -> Self {
76        Self {
77            slot: T::get_static().alloc(ScInner::new(t)).for_mutation(),
78            tag: PhantomData,
79        }
80    }
81
82    /// Allocate a `TSc` from a Pool with inferred or turbofish tag.
83    #[inline]
84    pub fn new_notag(t: T) -> Self {
85        Self {
86            slot: T::get_static().alloc(ScInner::new(t)).for_mutation(),
87            tag: PhantomData,
88        }
89    }
90}
91
92impl<T, TAG> Default for TSc<T, TAG>
93where
94    T: AssocStatic<TScPool<T>, TAG> + 'static + Default,
95    TAG: 'static,
96{
97    /// Allocate a default initialized `TSc`
98    #[inline]
99    fn default() -> Self {
100        TSc::new_notag(T::default())
101    }
102}
103
104impl<T, TAG> Clone for TSc<T, TAG>
105where
106    T: AssocStatic<TScPool<T>, TAG> + 'static,
107    TAG: 'static,
108{
109    #[must_use]
110    fn clone(&self) -> Self {
111        self.slot.get().inc_strong();
112        unsafe {
113            Self {
114                slot: self.slot.copy(),
115                tag: PhantomData,
116            }
117        }
118    }
119}
120
121impl<T, TAG> Drop for TSc<T, TAG>
122where
123    T: AssocStatic<TScPool<T>, TAG> + 'static,
124    TAG: 'static,
125{
126    #[inline]
127    fn drop(&mut self) {
128        let mslot = self.slot.get_mut();
129
130        mslot.dec_strong();
131
132        if mslot.get_strong() == 0 {
133            unsafe {
134                T::get_static().free_by_ref(&mut self.slot);
135            }
136        }
137    }
138}
139
140impl<T, TAG> Deref for TSc<T, TAG>
141where
142    T: AssocStatic<TScPool<T>, TAG> + 'static,
143    TAG: 'static,
144{
145    type Target = T;
146
147    #[inline]
148    fn deref(&self) -> &<Self as Deref>::Target {
149        unsafe { self.slot.get().data.assume_init_ref() }
150    }
151}
152
153impl<T, TAG> DerefMut for TSc<T, TAG>
154where
155    T: AssocStatic<TScPool<T>, TAG> + 'static,
156    TAG: 'static,
157{
158    #[inline]
159    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
160        unsafe { self.slot.get_mut().data.assume_init_mut() }
161    }
162}
163
164impl<T, TAG> Borrow<T> for TSc<T, TAG>
165where
166    T: AssocStatic<TScPool<T>, TAG> + 'static,
167    TAG: 'static,
168{
169    #[inline]
170    fn borrow(&self) -> &T {
171        unsafe { self.slot.get().data.assume_init_ref() }
172    }
173}
174
175impl<T, TAG> BorrowMut<T> for TSc<T, TAG>
176where
177    T: AssocStatic<TScPool<T>, TAG> + 'static,
178    TAG: 'static,
179{
180    #[inline]
181    fn borrow_mut(&mut self) -> &mut T {
182        unsafe { self.slot.get_mut().data.assume_init_mut() }
183    }
184}
185
186impl<T, TAG> AsRef<T> for TSc<T, TAG>
187where
188    T: AssocStatic<TScPool<T>, TAG> + 'static,
189    TAG: 'static,
190{
191    #[inline]
192    fn as_ref(&self) -> &T {
193        unsafe { self.slot.get().data.assume_init_ref() }
194    }
195}
196
197impl<T, TAG> AsMut<T> for TSc<T, TAG>
198where
199    T: AssocStatic<TScPool<T>, TAG> + 'static,
200    TAG: 'static,
201{
202    #[inline]
203    fn as_mut(&mut self) -> &mut T {
204        unsafe { self.slot.get_mut().data.assume_init_mut() }
205    }
206}
207
208impl<T: PartialEq, TAG> PartialEq for TSc<T, TAG>
209where
210    T: AssocStatic<TScPool<T>, TAG> + 'static,
211    TAG: 'static,
212{
213    #[inline]
214    fn eq(&self, other: &Self) -> bool {
215        PartialEq::eq(&**self, &**other)
216    }
217}
218
219impl<T: PartialOrd, TAG> PartialOrd for TSc<T, TAG>
220where
221    T: AssocStatic<TScPool<T>, TAG> + 'static,
222    TAG: 'static,
223{
224    #[inline]
225    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
226        PartialOrd::partial_cmp(&**self, &**other)
227    }
228    #[inline]
229    fn lt(&self, other: &Self) -> bool {
230        PartialOrd::lt(&**self, &**other)
231    }
232    #[inline]
233    fn le(&self, other: &Self) -> bool {
234        PartialOrd::le(&**self, &**other)
235    }
236    #[inline]
237    fn ge(&self, other: &Self) -> bool {
238        PartialOrd::ge(&**self, &**other)
239    }
240    #[inline]
241    fn gt(&self, other: &Self) -> bool {
242        PartialOrd::gt(&**self, &**other)
243    }
244}
245
246impl<T: Ord, TAG> Ord for TSc<T, TAG>
247where
248    T: AssocStatic<TScPool<T>, TAG> + 'static,
249    TAG: 'static,
250{
251    #[inline]
252    fn cmp(&self, other: &Self) -> Ordering {
253        Ord::cmp(&**self, &**other)
254    }
255}
256
257impl<T: Eq, TAG> Eq for TSc<T, TAG>
258where
259    T: AssocStatic<TScPool<T>, TAG> + 'static,
260    TAG: 'static,
261{
262}
263
264impl<T: Hash, TAG> Hash for TSc<T, TAG>
265where
266    T: AssocStatic<TScPool<T>, TAG> + 'static,
267    TAG: 'static,
268{
269    fn hash<H: Hasher>(&self, state: &mut H) {
270        (**self).hash(state);
271    }
272}
273
274impl<T: Hasher, TAG> Hasher for TSc<T, TAG>
275where
276    T: AssocStatic<TScPool<T>, TAG> + 'static,
277    TAG: 'static,
278{
279    fn finish(&self) -> u64 {
280        (**self).finish()
281    }
282    fn write(&mut self, bytes: &[u8]) {
283        (**self).write(bytes);
284    }
285    fn write_u8(&mut self, i: u8) {
286        (**self).write_u8(i);
287    }
288    fn write_u16(&mut self, i: u16) {
289        (**self).write_u16(i);
290    }
291    fn write_u32(&mut self, i: u32) {
292        (**self).write_u32(i);
293    }
294    fn write_u64(&mut self, i: u64) {
295        (**self).write_u64(i);
296    }
297    fn write_u128(&mut self, i: u128) {
298        (**self).write_u128(i);
299    }
300    fn write_usize(&mut self, i: usize) {
301        (**self).write_usize(i);
302    }
303    fn write_i8(&mut self, i: i8) {
304        (**self).write_i8(i);
305    }
306    fn write_i16(&mut self, i: i16) {
307        (**self).write_i16(i);
308    }
309    fn write_i32(&mut self, i: i32) {
310        (**self).write_i32(i);
311    }
312    fn write_i64(&mut self, i: i64) {
313        (**self).write_i64(i);
314    }
315    fn write_i128(&mut self, i: i128) {
316        (**self).write_i128(i);
317    }
318    fn write_isize(&mut self, i: isize) {
319        (**self).write_isize(i);
320    }
321    // fn write_length_prefix(&mut self, len: usize) {
322    //     (**self).write_length_prefix(len)
323    // }
324    // fn write_str(&mut self, s: &str) {
325    //     (**self).write_str(s)
326    // }
327}
328
329impl<T: fmt::Display, TAG> fmt::Display for TSc<T, TAG>
330where
331    T: AssocStatic<TScPool<T>, TAG> + 'static,
332    TAG: 'static,
333{
334    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335        fmt::Display::fmt(&**self, f)
336    }
337}
338
339impl<T: fmt::Debug, TAG> fmt::Debug for TSc<T, TAG>
340where
341    T: AssocStatic<TScPool<T>, TAG> + 'static,
342    TAG: 'static,
343{
344    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
345        fmt::Debug::fmt(&**self, f)
346    }
347}
348
349impl<T, TAG> fmt::Pointer for TSc<T, TAG>
350where
351    T: AssocStatic<TScPool<T>, TAG> + 'static,
352    TAG: 'static,
353{
354    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
355        let ptr: *const T = &**self;
356        fmt::Pointer::fmt(&ptr, f)
357    }
358}
359
360#[cfg(test)]
361mod tests {
362    use crate::*;
363    use serial_test::serial;
364
365    define_tsc_pool!((): &'static str);
366    define_tsc_pool!((): u64);
367
368    #[test]
369    #[ignore]
370    #[serial]
371    fn smoke() {
372        TBox::<&'static str, ()>::pool()
373            .acquire()
374            .expect("some other thread owns the pool");
375
376        let _mybox = TSc::new("TBoxed", ());
377
378        TBox::<&'static str, ()>::pool()
379            .release()
380            .expect("thread does not own the pool");
381    }
382}