Skip to main content

embed_collections/
irc.rs

1//! Intrusive Reference Counter (Irc)
2//!
3//! `Irc` is an intrusive reference counting smart pointer, similar to `Arc` but without weak reference support.
4//! It requires the inner type to implement [IrcItem] trait to provide a counter field.
5//!
6//! The underlayer of `Irc` is customizable (default to be Box),
7//! unlike `Arc` which wrap a hidden ArcInner on your inner types,
8//! Irc use the pointer of your inner types by [Pointer::into_raw]
9//!
10//! The atomic ordering is mostly the same with std `Arc` (miri test cases verified)
11//!
12//! # Benefits
13//!
14//! - No need to manual implementing the inc / dec on counter.
15//!
16//! - No enforced weak counter if you don't need it (every atomic op has cost).
17//!
18//! - Customized counter type (not limited to AtomicUsize)
19//!
20//! - [IrcItem::on_drop] in the trait allow you to have the ownship of underlying inner memory after
21//!   the reference count of Irc is dropped. And you only need to define the drop behavior once,
22//!   instead of write the same logic `Arc::into_inner` in every possible places
23//!   (If forgetting so make your code block and hard to debug).
24//!
25//! - Using `Irc` to wrap a `Box`, no additional memory allocation and memory fragmentation, no
26//!   additional dereference cost (than using `Arc<Box<T>>`)
27//!
28//! - You can allocate a box from the time of its birth and wrap it will `Irc` for temporary usage,
29//!   don't need to move bytes from / to stack. (especially when the inner object is large)
30//!
31//! - Advanced usage, multiple layer customized counter, on the same heap object, while preserving
32//!   the safe boundary
33//!
34//! # Example
35//!
36//! The follow example shows `Irc` wrapping a `Box` (You can also the same to Change the param P with `Arc`, or other [Pointer] type)
37//!
38//! ```rust
39//! use embed_collections::irc::{Irc, IrcItem};
40//! use core::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
41//! use crossfire::oneshot;
42//! use std::thread;
43//! use std::time::Duration;
44//!
45//! // Usually we use Irc for some large structure, but we show a simple demo here.
46//! struct MyItem {
47//!     is_done: AtomicBool,
48//!     counter: AtomicUsize,
49//!     done_tx: Option<oneshot::TxOneshot<Box<MyItem>>>,
50//! }
51//!
52//! // The default parameter Tag=(), P=Box<Self>
53//! unsafe impl IrcItem for MyItem {
54//!     type Counter = AtomicUsize;
55//!     fn counter(&self) -> &Self::Counter {
56//!         &self.counter
57//!     }
58//!
59//!     // overwrite default behavior to send the item through channel
60//!     fn on_drop(mut this: Box<Self>) {
61//!         let done_tx = this.done_tx.take().unwrap();
62//!         done_tx.send(this);
63//!     }
64//! }
65//!
66//! let (done_tx, done_rx) = oneshot::oneshot();
67//! let boxed_item = Box::new(MyItem {
68//!     is_done: AtomicBool::new(false),
69//!     counter: AtomicUsize::new(0),
70//!     done_tx: Some(done_tx),
71//! });
72//!
73//! // Convert from Box to Irc, which does not have additional allocation.
74//! let item = Irc::from(boxed_item);
75//! thread::spawn(move || {
76//!     thread::sleep(Duration::from_secs(1));
77//!     item.is_done.store(true, Ordering::SeqCst);
78//!     drop(item);
79//! });
80//! let item: Box<MyItem> = done_rx.recv().unwrap();
81//! assert!(item.is_done.load(Ordering::SeqCst));
82//! ```
83
84use crate::{Pointer, SmartPointer};
85use alloc::boxed::Box;
86use atomic_traits::{
87    Atomic, NumOps,
88    fetch::{Add, Sub},
89};
90use core::fmt;
91use core::marker::PhantomData;
92use core::ops::Deref;
93use core::ptr::NonNull;
94use core::sync::atomic::{
95    Ordering::{Acquire, Relaxed, Release},
96    fence,
97};
98
99/// trait for types that can be wrapped by [Irc]
100///
101/// # Safety
102///
103/// Tag is for distinguish multiple Irc from the same Inner type.
104/// When implement multiple types of Irc from the same object,
105/// you must make sure they don't have overlapped Counter fields.
106pub unsafe trait IrcItem<Tag = (), P = Box<Self>>: Sized + Send + Sync
107where
108    <Self::Counter as Atomic>::Type: From<u8> + Into<usize> + PartialEq,
109    P: Pointer<Target = Self>,
110{
111    /// The type of counter
112    type Counter: NumOps;
113
114    /// return reference to the field of counter
115    fn counter(&self) -> &Self::Counter;
116
117    /// The default behavior for Irc is dropping the inner smart pointer type.
118    ///
119    /// You can overwrite this if you want to send the inner somewhere.
120    #[inline(always)]
121    fn on_drop(_this: P) {}
122
123    #[inline]
124    fn strong_count(&self) -> usize {
125        self.counter().load(Relaxed).into()
126    }
127}
128
129/// Intrusive reference counter, which support conversion between `P`.
130///
131/// It does not support weak reference.
132pub struct Irc<T, Tag = (), P = Box<T>>
133where
134    T: IrcItem<Tag, P>,
135    P: Pointer<Target = T>,
136{
137    inner: NonNull<T>,
138    _phan: PhantomData<fn(&Tag, &P)>,
139}
140
141impl<T, Tag, P> Irc<T, Tag, P>
142where
143    T: IrcItem<Tag, P>,
144    P: SmartPointer<Target = T>,
145{
146    /// Wrap a stack value T inside P with Irc.
147    ///
148    /// The counter will be reset to 1 on initialization.
149    #[inline]
150    pub fn new(inner: T) -> Self {
151        Self::from(P::new(inner))
152    }
153}
154
155impl<T: IrcItem<Tag, P>, Tag, P> SmartPointer for Irc<T, Tag, P>
156where
157    T: IrcItem<Tag, P>,
158    P: SmartPointer<Target = T>,
159{
160    #[inline]
161    fn new(inner: T) -> Self {
162        Irc::new(inner)
163    }
164}
165
166impl<T, Tag, P> From<P> for Irc<T, Tag, P>
167where
168    T: IrcItem<Tag, P>,
169    P: Pointer<Target = T>,
170{
171    /// Convert a [Pointer] containing `T` into Irc.
172    ///
173    /// The counter will be reset to 1 on initialization.
174    #[inline]
175    fn from(inner: P) -> Self {
176        inner.as_ref().counter().store(1u8.into(), Relaxed);
177        Self {
178            inner: unsafe { NonNull::new_unchecked(inner.into_raw() as *mut T) },
179            _phan: Default::default(),
180        }
181    }
182}
183
184impl<T, Tag, P> Irc<T, Tag, P>
185where
186    T: IrcItem<Tag, P>,
187    P: Pointer<Target = T>,
188{
189    #[inline(always)]
190    fn get_inner(&self) -> &T {
191        unsafe { self.inner.as_ref() }
192    }
193
194    #[inline]
195    pub fn ptr_eq(this: &Self, other: &Self) -> bool {
196        this.inner == other.inner
197    }
198
199    /// Wrap a [Pointer] containing `T` with Irc.
200    ///
201    /// # Safety
202    ///
203    /// The counter will be increase by 1, but the previous value is not checked
204    #[inline]
205    pub unsafe fn with_unchecked(inner: P) -> Self {
206        inner.as_ref().counter().fetch_add(1u8.into(), Relaxed);
207        Self {
208            inner: unsafe { NonNull::new_unchecked(inner.into_raw() as *mut T) },
209            _phan: Default::default(),
210        }
211    }
212
213    /// If is_unique returns true, then this thread is the only owner
214    ///
215    /// # False negative
216    ///
217    /// it's possible to return false when counter drop to 1,
218    /// Because of using Acquire load and Release on drop.
219    ///
220    /// # Example
221    ///
222    ///
223    /// ```rust
224    /// use embed_collections::irc::{Irc, IrcItem};
225    /// use core::sync::atomic::AtomicUsize;
226    ///
227    /// struct Tag;
228    ///
229    /// struct MyItem {
230    ///     value: i32,
231    ///     counter: AtomicUsize,
232    /// }
233    ///
234    /// unsafe impl IrcItem<Tag> for MyItem {
235    ///     type Counter = AtomicUsize;
236    ///     fn counter(&self) -> &Self::Counter {
237    ///         &self.counter
238    ///     }
239    /// }
240    ///
241    /// // Create a new Irc
242    /// let irc1 = Irc::<_, Tag>::new(MyItem { value: 10, counter: AtomicUsize::new(0) });
243    /// assert_eq!(irc1.value, 10);
244    /// assert!(irc1.is_unique());
245    ///
246    /// // Clone the Irc
247    /// let irc2 = irc1.clone();
248    /// assert_eq!(irc1.strong_count(), 2);
249    /// assert!(!irc1.is_unique());
250    /// ```
251    #[inline]
252    pub fn is_unique(&self) -> bool {
253        // Safety:
254        // we have make sure counter reset to 1 on init.
255        // although clone use Relaxed, it can never pass this fence
256        self.counter().load(Acquire) == 1u8.into()
257    }
258
259    /// return mutable reference if we are the only owner
260    ///
261    /// # False negative
262    ///
263    /// It can return None even when only one reference left
264    #[inline]
265    pub fn get_mut(this: &mut Self) -> Option<&mut T> {
266        if this.is_unique() { Some(unsafe { this.inner.as_mut() }) } else { None }
267    }
268}
269
270impl<T, Tag, P> Irc<T, Tag, P>
271where
272    T: IrcItem<Tag, P> + Clone,
273    P: SmartPointer<Target = T>,
274{
275    /// The Cow function, the same as `Arc::make_mut()`
276    ///
277    /// # Example
278    ///
279    /// ```rust
280    /// use embed_collections::irc::{Irc, IrcItem};
281    /// use core::sync::atomic::AtomicUsize;
282    ///
283    /// struct Tag;
284    /// struct MyItem {
285    ///     value: i32,
286    ///     counter: AtomicUsize,
287    /// }
288    ///
289    /// impl Clone for MyItem {
290    ///     fn clone(&self) -> Self {
291    ///         Self { value: self.value, counter: AtomicUsize::new(0) }
292    ///     }
293    /// }
294    ///
295    /// unsafe impl IrcItem<Tag> for MyItem {
296    ///     type Counter = AtomicUsize;
297    ///     fn counter(&self) -> &Self::Counter {
298    ///         &self.counter
299    ///     }
300    /// }
301    ///
302    /// let mut irc1 = Irc::<_, Tag>::new(MyItem { value: 10, counter: AtomicUsize::new(0) });
303    /// let irc2 = irc1.clone();
304    ///
305    /// // This will clone the inner item because it's shared
306    /// let m = Irc::make_mut(&mut irc1);
307    /// m.value = 20;
308    ///
309    /// assert_eq!(irc1.value, 20);
310    /// assert_eq!(irc2.value, 10);
311    /// ```
312    #[inline]
313    pub fn make_mut(this: &mut Self) -> &mut T {
314        if !this.is_unique() {
315            let cloned_item = this.get_inner().clone();
316            let mut new_irc = Self::new(cloned_item);
317            core::mem::swap(this, &mut new_irc);
318        }
319        unsafe { this.inner.as_mut() }
320    }
321}
322
323impl<T, Tag, P> Deref for Irc<T, Tag, P>
324where
325    T: IrcItem<Tag, P>,
326    P: Pointer<Target = T>,
327{
328    type Target = T;
329    #[inline(always)]
330    fn deref(&self) -> &Self::Target {
331        self.get_inner()
332    }
333}
334
335impl<T, Tag, P> AsRef<T> for Irc<T, Tag, P>
336where
337    T: IrcItem<Tag, P>,
338    P: Pointer<Target = T>,
339{
340    #[inline(always)]
341    fn as_ref(&self) -> &T {
342        self.get_inner()
343    }
344}
345
346unsafe impl<T, Tag, P> Send for Irc<T, Tag, P>
347where
348    T: IrcItem<Tag, P>,
349    P: Pointer<Target = T>,
350{
351}
352unsafe impl<T, Tag, P> Sync for Irc<T, Tag, P>
353where
354    T: IrcItem<Tag, P>,
355    P: Pointer<Target = T>,
356{
357}
358
359impl<T, Tag, P> Clone for Irc<T, Tag, P>
360where
361    T: IrcItem<Tag, P>,
362    P: Pointer<Target = T>,
363{
364    #[inline]
365    fn clone(&self) -> Self {
366        self.get_inner().counter().fetch_add(1u8.into(), Relaxed);
367        Self { inner: self.inner, _phan: Default::default() }
368    }
369}
370
371impl<T, Tag, P> Drop for Irc<T, Tag, P>
372where
373    T: IrcItem<Tag, P>,
374    P: Pointer<Target = T>,
375{
376    #[inline]
377    fn drop(&mut self) {
378        let p = self.inner.as_ptr();
379        unsafe {
380            if (*p).counter().fetch_sub(1u8.into(), Release) == 1u8.into() {
381                fence(Acquire);
382                let inner = P::from_raw(p);
383                IrcItem::<Tag, P>::on_drop(inner);
384            }
385        }
386    }
387}
388
389impl<T, Tag, P> fmt::Debug for Irc<T, Tag, P>
390where
391    T: IrcItem<Tag, P> + fmt::Debug,
392    P: Pointer<Target = T>,
393{
394    #[inline]
395    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
396        self.get_inner().fmt(f)
397    }
398}
399
400impl<T, Tag, P> fmt::Display for Irc<T, Tag, P>
401where
402    T: IrcItem<Tag, P> + fmt::Display,
403    P: Pointer<Target = T>,
404{
405    #[inline]
406    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
407        self.get_inner().fmt(f)
408    }
409}
410
411impl<T: IrcItem<Tag, P>, Tag, P> Pointer for Irc<T, Tag, P>
412where
413    T: IrcItem<Tag, P>,
414    P: Pointer<Target = T>,
415{
416    type Target = T;
417
418    #[inline]
419    fn as_ref(&self) -> &Self::Target {
420        unsafe { self.inner.as_ref() }
421    }
422
423    /// # Safety
424    ///
425    /// must be pointer acquire from [Irc::into_raw()]
426    #[inline]
427    unsafe fn from_raw(p: *const Self::Target) -> Self {
428        Self {
429            inner: unsafe { NonNull::new_unchecked(p as *mut Self::Target) },
430            _phan: Default::default(),
431        }
432    }
433
434    #[inline]
435    fn into_raw(self) -> *const Self::Target {
436        let p = self.inner.as_ptr();
437        core::mem::forget(self);
438        p
439    }
440}
441
442#[cfg(test)]
443mod tests {
444    use super::*;
445    use crate::test::{CounterI32, alive_count, reset_alive_count};
446    use alloc::sync::Arc;
447    use core::sync::atomic::AtomicUsize;
448    use std::thread;
449
450    struct TestItem {
451        value: CounterI32,
452        counter: AtomicUsize,
453    }
454
455    impl TestItem {
456        fn new(val: i32) -> Self {
457            Self { value: CounterI32::new(val), counter: AtomicUsize::new(0) }
458        }
459    }
460
461    impl Clone for TestItem {
462        fn clone(&self) -> Self {
463            Self { value: self.value.clone(), counter: AtomicUsize::new(0) }
464        }
465    }
466
467    unsafe impl IrcItem for TestItem {
468        type Counter = AtomicUsize;
469        fn counter(&self) -> &Self::Counter {
470            &self.counter
471        }
472    }
473
474    struct ArcTestItem {
475        value: CounterI32,
476        counter: AtomicUsize,
477    }
478
479    impl ArcTestItem {
480        fn new(val: i32) -> Self {
481            Self { value: CounterI32::new(val), counter: AtomicUsize::new(0) }
482        }
483    }
484
485    unsafe impl IrcItem<(), Arc<ArcTestItem>> for ArcTestItem {
486        type Counter = AtomicUsize;
487        fn counter(&self) -> &Self::Counter {
488            &self.counter
489        }
490    }
491
492    #[test]
493    fn test_basic() {
494        reset_alive_count();
495        {
496            let item = TestItem::new(10);
497            let irc1 = Irc::<_, _, _>::new(item);
498            assert_eq!(irc1.value.value, 10);
499            assert_eq!(irc1.strong_count(), 1);
500            assert!(irc1.is_unique());
501            assert_eq!(alive_count(), 1);
502
503            let irc2 = irc1.clone();
504            assert_eq!(irc1.strong_count(), 2);
505            assert_eq!(irc2.strong_count(), 2);
506            assert!(!irc1.is_unique());
507            assert_eq!(alive_count(), 1);
508
509            drop(irc1);
510            assert_eq!(irc2.strong_count(), 1);
511            assert!(irc2.is_unique());
512            assert_eq!(alive_count(), 1);
513        }
514        assert_eq!(alive_count(), 0);
515    }
516
517    #[test]
518    fn test_arc_underlayer() {
519        reset_alive_count();
520        {
521            let item = ArcTestItem::new(10);
522            let irc1 = Irc::<ArcTestItem, (), Arc<ArcTestItem>>::new(item);
523            assert_eq!(irc1.value.value, 10);
524            assert_eq!(irc1.strong_count(), 1);
525            assert!(irc1.is_unique());
526            assert_eq!(alive_count(), 1);
527
528            let irc2 = irc1.clone();
529            assert_eq!(irc1.strong_count(), 2);
530            assert_eq!(alive_count(), 1);
531
532            drop(irc1);
533            assert_eq!(irc2.strong_count(), 1);
534            assert_eq!(alive_count(), 1);
535        }
536        assert_eq!(alive_count(), 0);
537    }
538
539    #[test]
540    fn test_get_mut() {
541        reset_alive_count();
542        let mut irc = Irc::<_, _, _>::new(TestItem::new(10));
543        assert!(Irc::get_mut(&mut irc).is_some());
544
545        let _irc2 = irc.clone();
546        assert!(Irc::get_mut(&mut irc).is_none());
547    }
548
549    #[test]
550    fn test_make_mut() {
551        reset_alive_count();
552        let mut irc = Irc::new(TestItem::new(10));
553
554        // Unique, no clone
555        {
556            let m = Irc::make_mut(&mut irc);
557            m.value.value = 20;
558        }
559        assert_eq!(irc.value.value, 20);
560        assert_eq!(alive_count(), 1);
561
562        // Not unique, should clone
563        let irc2 = irc.clone();
564        assert_eq!(alive_count(), 1);
565        {
566            let m = Irc::make_mut(&mut irc);
567            m.value.value = 30;
568        }
569        assert_eq!(irc.value.value, 30);
570        assert_eq!(irc2.value.value, 20);
571        assert_eq!(alive_count(), 2);
572
573        assert!(irc.is_unique());
574        assert!(irc2.is_unique());
575    }
576
577    #[test]
578    fn test_multithread_count() {
579        reset_alive_count();
580        {
581            let irc = Irc::new(TestItem::new(0));
582            let mut handles = vec![];
583
584            for _ in 0..10 {
585                let irc_clone = irc.clone();
586                handles.push(thread::spawn(move || {
587                    for _ in 0..1000 {
588                        let temp = irc_clone.clone();
589                        assert_eq!(temp.value.value, 0);
590                    }
591                }));
592            }
593
594            for handle in handles {
595                handle.join().unwrap();
596            }
597
598            assert_eq!(irc.strong_count(), 1);
599            assert!(irc.is_unique());
600            assert_eq!(alive_count(), 1);
601        }
602        assert_eq!(alive_count(), 0);
603    }
604
605    #[test]
606    fn test_multithread_drop() {
607        reset_alive_count();
608        {
609            let irc = Irc::new(TestItem::new(0));
610            let mut handles = vec![];
611            for _ in 0..10 {
612                let irc_clone = irc.clone();
613                handles.push(thread::spawn(move || {
614                    for _ in 0..1000 {
615                        let temp = irc_clone.clone();
616                        assert_eq!(temp.value.value, 0);
617                    }
618                }));
619            }
620            drop(irc);
621            for handle in handles {
622                handle.join().unwrap();
623            }
624        }
625        assert_eq!(alive_count(), 0);
626    }
627
628    #[test]
629    fn test_drop_all() {
630        reset_alive_count();
631        let irc = Irc::new(TestItem::new(0));
632        let mut clones = vec![];
633        for _ in 0..100 {
634            clones.push(irc.clone());
635        }
636        assert_eq!(alive_count(), 1);
637        drop(clones);
638        assert_eq!(alive_count(), 1);
639        drop(irc);
640        assert_eq!(alive_count(), 0);
641    }
642
643    #[test]
644    fn test_from_into_raw() {
645        {
646            let irc = Irc::new(TestItem::new(0));
647            let irc_1 = irc.clone();
648            let irc_2 = irc.clone();
649            let irc1_p = irc_1.into_raw();
650            let irc2_p = irc_2.into_raw();
651            assert_eq!(irc.strong_count(), 3);
652            assert_eq!(alive_count(), 1);
653            let _irc1 = unsafe { Irc::from_raw(irc1_p) };
654            let _irc2 = unsafe { Irc::from_raw(irc2_p) };
655            assert_eq!(irc.strong_count(), 3);
656            assert_eq!(alive_count(), 1);
657        }
658        assert_eq!(alive_count(), 0);
659    }
660}